Use va_list argument to abort transaction

Creates AbortTransactionV taking a va_list argument and renames
AbortTransaction to AbortTransactionF which calls AbortTransactionV.

This fixes the compiler_driver_test under valgrind.

Change-Id: Ia1c57330091c055ae9e46585a944ce0b78864920
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 582843c..375d644 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -467,16 +467,20 @@
   }
 }
 
-void AbortTransaction(Thread* self, const char* fmt, ...) {
-  CHECK(Runtime::Current()->IsActiveTransaction());
-  // Constructs abort message.
+void AbortTransactionF(Thread* self, const char* fmt, ...) {
   va_list args;
   va_start(args, fmt);
+  AbortTransactionV(self, fmt, args);
+  va_end(args);
+}
+
+void AbortTransactionV(Thread* self, const char* fmt, va_list args) {
+  CHECK(Runtime::Current()->IsActiveTransaction());
+  // Constructs abort message.
   std::string abort_msg;
   StringAppendV(&abort_msg, fmt, args);
   // Throws an exception so we can abort the transaction and rollback every change.
   Runtime::Current()->AbortTransactionAndThrowAbortError(self, abort_msg);
-  va_end(args);
 }
 
 template<bool is_range, bool do_assignability_check>
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 7d413c5..2f8bf55 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -81,7 +81,11 @@
   ref->MonitorExit(self);
 }
 
-void AbortTransaction(Thread* self, const char* fmt, ...)
+void AbortTransactionF(Thread* self, const char* fmt, ...)
+    __attribute__((__format__(__printf__, 2, 3)))
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+void AbortTransactionV(Thread* self, const char* fmt, va_list args)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 void RecordArrayElementsInTransaction(mirror::Array* array, int32_t count)
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index 9c48df6..cead26c 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -536,8 +536,8 @@
       // Don't allow finalizable objects to be allocated during a transaction since these can't be
       // finalized without a started runtime.
       if (transaction_active && obj->GetClass()->IsFinalizable()) {
-        AbortTransaction(self, "Allocating finalizable object in transaction: %s",
-                         PrettyTypeOf(obj).c_str());
+        AbortTransactionF(self, "Allocating finalizable object in transaction: %s",
+                          PrettyTypeOf(obj).c_str());
         HANDLE_PENDING_EXCEPTION();
       }
       shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), obj);
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 609faf5..fe7ad77 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -438,8 +438,8 @@
           // Don't allow finalizable objects to be allocated during a transaction since these can't
           // be finalized without a started runtime.
           if (transaction_active && obj->GetClass()->IsFinalizable()) {
-            AbortTransaction(self, "Allocating finalizable object in transaction: %s",
-                             PrettyTypeOf(obj).c_str());
+            AbortTransactionF(self, "Allocating finalizable object in transaction: %s",
+                              PrettyTypeOf(obj).c_str());
             HANDLE_PENDING_EXCEPTION();
             break;
           }
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 2aa4af4..b1e4193 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -44,14 +44,21 @@
 namespace interpreter {
 
 static void AbortTransactionOrFail(Thread* self, const char* fmt, ...)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    __attribute__((__format__(__printf__, 2, 3)))
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+static void AbortTransactionOrFail(Thread* self, const char* fmt, ...) {
   va_list args;
-  va_start(args, fmt);
   if (Runtime::Current()->IsActiveTransaction()) {
-    AbortTransaction(self, fmt, args);
+    va_start(args, fmt);
+    AbortTransactionV(self, fmt, args);
     va_end(args);
   } else {
-    LOG(FATAL) << "Trying to abort, but not in transaction mode: " << StringPrintf(fmt, args);
+    va_start(args, fmt);
+    std::string msg;
+    StringAppendV(&msg, fmt, args);
+    va_end(args);
+    LOG(FATAL) << "Trying to abort, but not in transaction mode: " << msg;
     UNREACHABLE();
   }
 }
@@ -159,8 +166,8 @@
   // If we're in a transaction, class must not be finalizable (it or a superclass has a finalizer).
   if (Runtime::Current()->IsActiveTransaction()) {
     if (h_klass.Get()->IsFinalizable()) {
-      AbortTransaction(self, "Class for newInstance is finalizable: '%s'",
-                       PrettyClass(h_klass.Get()).c_str());
+      AbortTransactionF(self, "Class for newInstance is finalizable: '%s'",
+                        PrettyClass(h_klass.Get()).c_str());
       return;
     }
   }
@@ -1020,8 +1027,8 @@
   if (iter != jni_handlers_.end()) {
     (*iter->second)(self, method, receiver, args, result);
   } else if (Runtime::Current()->IsActiveTransaction()) {
-    AbortTransaction(self, "Attempt to invoke native method in non-started runtime: %s",
-                     name.c_str());
+    AbortTransactionF(self, "Attempt to invoke native method in non-started runtime: %s",
+                      name.c_str());
   } else {
     LOG(FATAL) << "Calling native method " << PrettyMethod(method) << " in an unstarted "
         "non-transactional runtime";