[io/domain_sockets] Ensure OSError is released in case Dart_ThrowException reports an error.

Fixes https://github.com/dart-lang/sdk/issues/47428.

Also truncate buffer only if allocated buffer is larger than number of bytes received.

TEST=unix_socket_test on asan

Change-Id: I4d707d3bec48a33f900bca002f09f70e017597e4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/216261
Reviewed-by: Siva Annamalai <asiva@google.com>
Commit-Queue: Alexander Aprelev <aam@google.com>
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc
index ac9d95d..2333b43 100644
--- a/runtime/bin/socket.cc
+++ b/runtime/bin/socket.cc
@@ -658,6 +658,7 @@
   int64_t buffer_num_bytes = 0;
   DartUtils::GetInt64Value(ThrowIfError(Dart_GetNativeArgument(args, 1)),
                            &buffer_num_bytes);
+  int64_t buffer_num_bytes_allocated = buffer_num_bytes;
   uint8_t* buffer = nullptr;
   Dart_Handle data = IOBuffer::Allocate(buffer_num_bytes, &buffer);
   if (Dart_IsNull(data)) {
@@ -665,16 +666,21 @@
   }
   ASSERT(buffer != nullptr);
 
-  OSError os_error;
+  // Can't rely on RAII since Dart_ThrowException won't call destructors.
+  OSError* os_error = new OSError();
   SocketControlMessage* control_messages;
   const intptr_t messages_read = SocketBase::ReceiveMessage(
       socket->fd(), buffer, &buffer_num_bytes, &control_messages,
-      SocketBase::kAsync, &os_error);
+      SocketBase::kAsync, os_error);
   if (messages_read < 0) {
     ASSERT(messages_read == -1);
-    Dart_ThrowException(DartUtils::NewDartOSError(&os_error));
+    Dart_Handle error = DartUtils::NewDartOSError(os_error);
+    delete os_error;
+    Dart_ThrowException(error);
   }
-  if (buffer_num_bytes > 0) {
+  delete os_error;
+  if (buffer_num_bytes > 0 && buffer_num_bytes != buffer_num_bytes_allocated) {
+    // If received fewer than allocated buffer size, truncate buffer.
     uint8_t* new_buffer = nullptr;
     Dart_Handle new_data = IOBuffer::Allocate(buffer_num_bytes, &new_buffer);
     if (Dart_IsNull(new_data)) {
@@ -789,7 +795,8 @@
         SocketControlMessage(level, type, copied_data, data.size_in_bytes());
   }
 
-  OSError os_error;
+  // Can't rely on RAII since Dart_ThrowException won't call destructors.
+  OSError* os_error = new OSError();
   intptr_t bytes_written;
   {
     Dart_Handle buffer_dart = Dart_GetNativeArgument(args, 1);
@@ -800,12 +807,15 @@
         reinterpret_cast<uint8_t*>(data.data()) + offset;
     bytes_written = SocketBase::SendMessage(
         socket->fd(), buffer_at_offset, length, control_messages,
-        num_control_messages, SocketBase::kAsync, &os_error);
+        num_control_messages, SocketBase::kAsync, os_error);
   }
 
   if (bytes_written < 0) {
-    Dart_ThrowException(DartUtils::NewDartOSError(&os_error));
+    Dart_Handle error = DartUtils::NewDartOSError(os_error);
+    delete os_error;
+    Dart_ThrowException(error);
   }
+  delete os_error;
 
   Dart_SetIntegerReturnValue(args, bytes_written);
 }