Reworking status printing to use the system allocator.
diff --git a/bindings/python/iree/runtime/status_utils.cc b/bindings/python/iree/runtime/status_utils.cc
index 30239fb..b12ccd2 100644
--- a/bindings/python/iree/runtime/status_utils.cc
+++ b/bindings/python/iree/runtime/status_utils.cc
@@ -24,6 +24,21 @@
   }
 }
 
+static std::string ApiStatusToString(iree_status_t status) {
+  iree_host_size_t buffer_length = 0;
+  if (IREE_UNLIKELY(!iree_status_format(status, /*buffer_capacity=*/0,
+                                        /*buffer=*/NULL, &buffer_length))) {
+    return "";
+  }
+  std::string result;
+  result.resize(buffer_length);
+  // NOTE: buffer capacity needs to be +1 for the NUL terminator in snprintf.
+  return iree_status_format(status, result.size() + 1,
+                            const_cast<char*>(result.data()), &buffer_length)
+             ? result
+             : "";
+}
+
 }  // namespace
 
 pybind11::error_already_set ApiStatusToPyExc(iree_status_t status,
@@ -31,15 +46,12 @@
   assert(!iree_status_is_ok(status));
   std::string full_message;
 
-  char* iree_message;
-  size_t iree_message_length;
-  if (iree_status_to_string(status, &iree_message, &iree_message_length)) {
-    full_message = std::string(message) + ": " +
-                   std::string(iree_message, iree_message_length);
-    iree_allocator_free(iree_allocator_system(), iree_message);
-  } else {
+  auto status_str = ApiStatusToString(status);
+  if (status_str.empty()) {
     full_message = std::string(message) + ": " +
                    iree_status_code_string(iree_status_code(status));
+  } else {
+    full_message = std::string(message) + ": " + status_str;
   }
 
   PyErr_SetString(ApiStatusToPyExcClass(status), full_message.c_str());
diff --git a/iree/base/internal/flags.c b/iree/base/internal/flags.c
index 05a7b5f..5b47112 100644
--- a/iree/base/internal/flags.c
+++ b/iree/base/internal/flags.c
@@ -392,12 +392,8 @@
   if (iree_status_is_ok(status)) return;
 
   fprintf(stderr, "\x1b[31mFLAGS ERROR: (╯°□°)╯︵👻\x1b[0m\n");
-  char* buffer = NULL;
-  iree_host_size_t buffer_length = 0;
-  iree_status_to_string(status, &buffer, &buffer_length);
-  fprintf(stderr, "%.*s\n\n", (int)buffer_length, buffer);
+  iree_status_fprint(stderr, status);
   fflush(stderr);
-  iree_allocator_free(iree_allocator_system(), buffer);
 
   exit(EXIT_FAILURE);
 }
diff --git a/iree/base/status.c b/iree/base/status.c
index b3ba831..8f95ec6 100644
--- a/iree/base/status.c
+++ b/iree/base/status.c
@@ -729,27 +729,33 @@
   return true;
 }
 
-IREE_API_EXPORT bool iree_status_to_string(
-    iree_status_t status, char** out_buffer,
-    iree_host_size_t* out_buffer_length) {
+// Converts the status to an allocated string value using the given allocator.
+// The caller must free the buffer with |allocator|.
+static bool iree_status_to_string(iree_status_t status,
+                                  iree_allocator_t allocator, char** out_buffer,
+                                  iree_host_size_t* out_buffer_length) {
   *out_buffer_length = 0;
   iree_host_size_t buffer_length = 0;
   if (IREE_UNLIKELY(!iree_status_format(status, /*buffer_capacity=*/0,
                                         /*buffer=*/NULL, &buffer_length))) {
     return false;
   }
-  // Buffer capacity needs to be +1 to account for the terminating null of
-  // snprintf.
-  buffer_length++;
-  char* buffer = (char*)malloc(buffer_length);
-  if (IREE_UNLIKELY(!buffer)) return false;
+
+  // Buffer capacity needs to be +1 for the NUL terminator (see snprintf).
+  char* buffer = NULL;
+  iree_status_t malloc_status =
+      iree_allocator_malloc(allocator, buffer_length + 1, (void**)&buffer);
+  if (!iree_status_is_ok(malloc_status)) {
+    iree_status_ignore(malloc_status);
+    return false;
+  }
   bool ret =
-      iree_status_format(status, buffer_length, buffer, out_buffer_length);
+      iree_status_format(status, buffer_length + 1, buffer, out_buffer_length);
   if (ret) {
     *out_buffer = buffer;
     return true;
   } else {
-    free(buffer);
+    iree_allocator_free(allocator, buffer);
     return false;
   }
 }
@@ -757,10 +763,15 @@
 IREE_API_EXPORT void iree_status_fprint(FILE* file, iree_status_t status) {
   // TODO(benvanik): better support for colors/etc - possibly move to logging.
   // TODO(benvanik): do this without allocation by streaming the status.
+  iree_allocator_t allocator = iree_allocator_system();
   char* status_buffer = NULL;
   iree_host_size_t status_buffer_length = 0;
-  iree_status_to_string(status, &status_buffer, &status_buffer_length);
-  fprintf(file, "%.*s\n", (int)status_buffer_length, status_buffer);
-  free(status_buffer);
+  if (iree_status_to_string(status, allocator, &status_buffer,
+                            &status_buffer_length)) {
+    fprintf(file, "%.*s\n", (int)status_buffer_length, status_buffer);
+    iree_allocator_free(allocator, status_buffer);
+  } else {
+    fprintf(file, "(failed to format status)\n");
+  }
   fflush(file);
 }
diff --git a/iree/base/status.h b/iree/base/status.h
index 0ba8fa0..790c297 100644
--- a/iree/base/status.h
+++ b/iree/base/status.h
@@ -407,12 +407,6 @@
                                         char* buffer,
                                         iree_host_size_t* out_buffer_length);
 
-// Converts the status to an allocated string value.
-// The caller must free the buffer with the system allocator.
-IREE_API_EXPORT bool iree_status_to_string(iree_status_t status,
-                                           char** out_buffer,
-                                           iree_host_size_t* out_buffer_length);
-
 // Prints |status| to the given |file| as a string with all available
 // annotations. This will produce multiple lines of output and should be used
 // only when dumping a status on failure.