[vm] Prevent reinterpreting object null as a send port capability.

Also ensure that allocated port ids and well-formed object pointers are disjoint.

Bug: https://github.com/dart-lang/sdk/issues/37234
Change-Id: I15328c1ba34f2995089f084e8889b110507c4dbf
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107223
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
Reviewed-by: RĂ©gis Crelier <regis@google.com>
diff --git a/runtime/lib/isolate_patch.dart b/runtime/lib/isolate_patch.dart
index 7c28e91..f43d181 100644
--- a/runtime/lib/isolate_patch.dart
+++ b/runtime/lib/isolate_patch.dart
@@ -197,6 +197,10 @@
 
 @pragma("vm:entry-point")
 class _SendPortImpl implements SendPort {
+  factory _SendPortImpl._uninstantiable() {
+    throw "Unreachable";
+  }
+
   /*--- public interface ---*/
   @pragma("vm:entry-point", "call")
   void send(var message) {
diff --git a/runtime/vm/port.cc b/runtime/vm/port.cc
index 4ad4340..0b580dd 100644
--- a/runtime/vm/port.cc
+++ b/runtime/vm/port.cc
@@ -4,6 +4,8 @@
 
 #include "vm/port.h"
 
+#include <utility>
+
 #include "platform/utils.h"
 #include "vm/dart_api_impl.h"
 #include "vm/dart_entry.h"
@@ -82,14 +84,20 @@
 }
 
 Dart_Port PortMap::AllocatePort() {
-  const Dart_Port kMASK = 0x3fffffff;
-  Dart_Port result = prng_->NextUInt32() & kMASK;
+  Dart_Port result;
 
   // Keep getting new values while we have an illegal port number or the port
   // number is already in use.
-  while ((result == 0) || (FindPort(result) >= 0)) {
-    result = prng_->NextUInt32() & kMASK;
-  }
+  do {
+    // Ensure port ids are representable in JavaScript for the benefit of
+    // vm-service clients such as Observatory.
+    const Dart_Port kMask1 = 0xFFFFFFFFFFFFF;
+    // Ensure port ids are never valid object pointers so that reinterpreting
+    // an object pointer as a port id never produces a used port id.
+    const Dart_Port kMask2 = 0x3;
+    result = (prng_->NextUInt64() & kMask1) | kMask2;
+    ASSERT(!reinterpret_cast<RawObject*>(result)->IsWellFormed());
+  } while (FindPort(result) >= 0);
 
   ASSERT(result != 0);
   ASSERT(FindPort(result) < 0);