[standalone] Fix memory leak in the tag handler.

TEST=asan
Bug: https://github.com/dart-lang/sdk/issues/37030
Bug: https://github.com/dart-lang/sdk/issues/51210
Change-Id: Ia62a4d7d1805c6ac4a311ef9952fff248e7b4693
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/280284
Reviewed-by: Siva Annamalai <asiva@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 6a24139..ada246f6 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -372,12 +372,19 @@
   }
 }
 
+static void MallocFinalizer(void* isolate_callback_data, void* peer) {
+  free(peer);
+}
+
 static void MaybeLoadExtraInputs(const CommandLineOptions& inputs) {
   for (intptr_t i = 1; i < inputs.count(); i++) {
     uint8_t* buffer = NULL;
     intptr_t size = 0;
     ReadFile(inputs.GetArgument(i), &buffer, &size);
-    Dart_Handle result = Dart_LoadLibraryFromKernel(buffer, size);
+    Dart_Handle td = Dart_NewExternalTypedDataWithFinalizer(
+        Dart_TypedData_kUint8, buffer, size, buffer, size, MallocFinalizer);
+    CHECK_RESULT(td);
+    Dart_Handle result = Dart_LoadLibrary(td);
     CHECK_RESULT(result);
   }
 }
diff --git a/runtime/bin/loader.cc b/runtime/bin/loader.cc
index 709fc54..4043580 100644
--- a/runtime/bin/loader.cc
+++ b/runtime/bin/loader.cc
@@ -52,6 +52,16 @@
 static void MallocFinalizer(void* isolate_callback_data, void* peer) {
   free(peer);
 }
+static Dart_Handle WrapMallocedKernelBuffer(uint8_t* kernel_buffer,
+                                            intptr_t kernel_buffer_size) {
+  Dart_Handle result = Dart_NewExternalTypedDataWithFinalizer(
+      Dart_TypedData_kUint8, kernel_buffer, kernel_buffer_size, kernel_buffer,
+      kernel_buffer_size, MallocFinalizer);
+  if (Dart_IsError(result)) {
+    free(kernel_buffer);
+  }
+  return result;
+}
 #endif
 
 Dart_Handle Loader::LibraryTagHandler(Dart_LibraryTag tag,
@@ -87,11 +97,7 @@
                                &kernel_buffer_size)) {
       return DartUtils::NewError("'%s' is not a kernel file", url_string);
     }
-    result = Dart_NewExternalTypedData(Dart_TypedData_kUint8, kernel_buffer,
-                                       kernel_buffer_size);
-    Dart_NewFinalizableHandle(result, kernel_buffer, kernel_buffer_size,
-                              MallocFinalizer);
-    return result;
+    return WrapMallocedKernelBuffer(kernel_buffer, kernel_buffer_size);
   }
   if (dfe.CanUseDartFrontend() && dfe.UseDartFrontend() &&
       (tag == Dart_kImportTag)) {
@@ -103,7 +109,8 @@
     dfe.CompileAndReadScript(url_string, &kernel_buffer, &kernel_buffer_size,
                              &error, &exit_code, NULL, false);
     if (exit_code == 0) {
-      return Dart_LoadLibraryFromKernel(kernel_buffer, kernel_buffer_size);
+      return Dart_LoadLibrary(
+          WrapMallocedKernelBuffer(kernel_buffer, kernel_buffer_size));
     } else if (exit_code == kCompilationErrorExitCode) {
       Dart_Handle result = Dart_NewCompilationError(error);
       free(error);
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 4f4baea..aac0427 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -3646,6 +3646,8 @@
 DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
 Dart_LoadLibraryFromKernel(const uint8_t* kernel_buffer,
                            intptr_t kernel_buffer_size);
+DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
+Dart_LoadLibrary(Dart_Handle kernel_buffer);
 
 /**
  * Indicates that all outstanding load requests have been satisfied.
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 5a5a47b..3a83464 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -5841,24 +5841,8 @@
   return error_in;
 }
 
-DART_EXPORT Dart_Handle Dart_LoadLibraryFromKernel(const uint8_t* buffer,
-                                                   intptr_t buffer_size) {
-#if defined(DART_PRECOMPILED_RUNTIME)
-  return Api::NewError("%s: Cannot compile on an AOT runtime.", CURRENT_FUNC);
-#else
-  DARTSCOPE(Thread::Current());
-  API_TIMELINE_DURATION(T);
-  StackZone zone(T);
-
-  CHECK_CALLBACK_STATE(T);
-
-  // NOTE: We do not attach a finalizer for this object, because the embedder
-  // will/should free it once the isolate group has shutdown.
-  // See also http://dartbug.com/37030.
-  const auto& td = ExternalTypedData::Handle(ExternalTypedData::New(
-      kExternalTypedDataUint8ArrayCid, const_cast<uint8_t*>(buffer),
-      buffer_size, Heap::kOld));
-
+#if !defined(DART_PRECOMPILED_RUNTIME)
+static Dart_Handle LoadLibrary(Thread* T, const ExternalTypedData& td) {
   const char* error = nullptr;
   std::unique_ptr<kernel::Program> program =
       kernel::Program::ReadFromTypedData(td, &error);
@@ -5873,6 +5857,40 @@
   source->add_loaded_blob(Z, td);
 
   return Api::NewHandle(T, result.ptr());
+}
+#endif  // !defined(DART_PRECOMPILED_RUNTIME)
+
+DART_EXPORT Dart_Handle Dart_LoadLibraryFromKernel(const uint8_t* buffer,
+                                                   intptr_t buffer_size) {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  return Api::NewError("%s: Cannot compile on an AOT runtime.", CURRENT_FUNC);
+#else
+  DARTSCOPE(Thread::Current());
+  API_TIMELINE_DURATION(T);
+  StackZone zone(T);
+
+  CHECK_CALLBACK_STATE(T);
+
+  // NOTE: We do not attach a finalizer for this object, because the embedder
+  // will/should free it once the isolate group has shutdown.
+  const auto& td = ExternalTypedData::Handle(ExternalTypedData::New(
+      kExternalTypedDataUint8ArrayCid, const_cast<uint8_t*>(buffer),
+      buffer_size, Heap::kOld));
+  return LoadLibrary(T, td);
+#endif  // defined(DART_PRECOMPILED_RUNTIME)
+}
+
+DART_EXPORT Dart_Handle Dart_LoadLibrary(Dart_Handle kernel_buffer) {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  return Api::NewError("%s: Cannot compile on an AOT runtime.", CURRENT_FUNC);
+#else
+  DARTSCOPE(Thread::Current());
+  const ExternalTypedData& td =
+      Api::UnwrapExternalTypedDataHandle(Z, kernel_buffer);
+  if (td.IsNull()) {
+    RETURN_TYPE_ERROR(Z, kernel_buffer, ExternalTypedData);
+  }
+  return LoadLibrary(T, td);
 #endif  // defined(DART_PRECOMPILED_RUNTIME)
 }
 
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index 82323cd..57286f7 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -433,6 +433,10 @@
   return result;
 }
 
+static void MallocFinalizer(void* isolate_callback_data, void* peer) {
+  free(peer);
+}
+
 Dart_Handle TestCase::LoadTestLibrary(const char* lib_uri,
                                       const char* script,
                                       Dart_NativeEntryResolver resolver) {
@@ -448,12 +452,14 @@
   if ((kernel_buffer == NULL) && (error != NULL)) {
     return Dart_NewApiError(error);
   }
-  Dart_Handle lib =
-      Dart_LoadLibraryFromKernel(kernel_buffer, kernel_buffer_size);
-  EXPECT_VALID(lib);
 
-  // Ensure kernel buffer isn't leaked after test is run.
-  AddToKernelBuffers(kernel_buffer);
+  Dart_Handle td = Dart_NewExternalTypedDataWithFinalizer(
+      Dart_TypedData_kUint8, const_cast<uint8_t*>(kernel_buffer),
+      kernel_buffer_size, const_cast<uint8_t*>(kernel_buffer),
+      kernel_buffer_size, MallocFinalizer);
+  EXPECT_VALID(td);
+  Dart_Handle lib = Dart_LoadLibrary(td);
+  EXPECT_VALID(lib);
 
   // TODO(32618): Kernel doesn't correctly represent the root library.
   lib = Dart_LookupLibrary(Dart_NewStringFromCString(sourcefiles[0].uri));
@@ -488,13 +494,14 @@
     return Dart_NewApiError(error);
   }
 
-  Dart_Handle lib =
-      Dart_LoadLibraryFromKernel(kernel_buffer, kernel_buffer_size);
+  Dart_Handle td = Dart_NewExternalTypedDataWithFinalizer(
+      Dart_TypedData_kUint8, const_cast<uint8_t*>(kernel_buffer),
+      kernel_buffer_size, const_cast<uint8_t*>(kernel_buffer),
+      kernel_buffer_size, MallocFinalizer);
+  EXPECT_VALID(td);
+  Dart_Handle lib = Dart_LoadLibrary(td);
   EXPECT_VALID(lib);
 
-  // Ensure kernel buffer isn't leaked after test is run.
-  AddToKernelBuffers(kernel_buffer);
-
   // BOGUS: Kernel doesn't correctly represent the root library.
   lib = Dart_LookupLibrary(Dart_NewStringFromCString(
       entry_script_uri != NULL ? entry_script_uri : sourcefiles[0].uri));