[VM runtime] Use memfd_create instead of shm_open for dual mapping of code.

Detect both at compile time and runtime for memfd_create support and disable
dual code mapping if not available.

Change-Id: I6908e6c116a60218bb5002378470011dfe76a257
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/96845
Commit-Queue: Régis Crelier <regis@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index 21fc4b3..07d2d03 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -352,19 +352,6 @@
 #error Unknown architecture.
 #endif
 
-// Determine whether dual mapping of code pages is supported.
-#if !defined(USING_SIMULATOR) &&                                               \
-    (defined(HOST_OS_LINUX) || defined(HOST_OS_FUCHSIA)) &&                    \
-    !defined(TARGET_OS_ANDROID) && !defined(TARGET_ARCH_IA32)
-#define DUAL_MAPPING_SUPPORTED 1
-#endif
-
-// Disable background threads by default on armv5te. The relevant
-// implementations are uniprocessors.
-#if !defined(TARGET_ARCH_ARM_5TE)
-#define ARCH_IS_MULTI_CORE 1
-#endif
-
 #if !defined(TARGET_OS_ANDROID) && !defined(TARGET_OS_FUCHSIA) &&              \
     !defined(TARGET_OS_MACOS_IOS) && !defined(TARGET_OS_LINUX) &&              \
     !defined(TARGET_OS_MACOS) && !defined(TARGET_OS_WINDOWS)
@@ -387,6 +374,19 @@
 #endif
 #endif
 
+// Determine whether dual mapping of code pages is supported.
+// We test dual mapping on linux x64 and deploy it on fuchsia.
+#if defined(TARGET_OS_LINUX) && defined(TARGET_ARCH_X64) ||                    \
+    defined(TARGET_OS_FUCHSIA)
+#define DUAL_MAPPING_SUPPORTED 1
+#endif
+
+// Disable background threads by default on armv5te. The relevant
+// implementations are uniprocessors.
+#if !defined(TARGET_ARCH_ARM_5TE)
+#define ARCH_IS_MULTI_CORE 1
+#endif
+
 // Short form printf format specifiers
 #define Pd PRIdPTR
 #define Pu PRIuPTR
diff --git a/runtime/vm/virtual_memory_posix.cc b/runtime/vm/virtual_memory_posix.cc
index bf22734..985d5b6 100644
--- a/runtime/vm/virtual_memory_posix.cc
+++ b/runtime/vm/virtual_memory_posix.cc
@@ -11,6 +11,7 @@
 #include <fcntl.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
+#include <sys/syscall.h>
 #include <unistd.h>
 
 #include "platform/assert.h"
@@ -31,8 +32,6 @@
 #undef MAP_FAILED
 #define MAP_FAILED reinterpret_cast<void*>(-1)
 
-#define DART_SHM_NAME "/dart_shm"
-
 DECLARE_FLAG(bool, dual_map_code);
 DECLARE_FLAG(bool, write_protect_code);
 
@@ -42,25 +41,29 @@
   page_size_ = getpagesize();
 
 #if defined(DUAL_MAPPING_SUPPORTED)
-  shm_unlink(DART_SHM_NAME);  // Could be left over from a previous crash.
-
   // Detect dual mapping exec permission limitation on some platforms,
   // such as on docker containers, and disable dual mapping in this case.
+  // Also detect for missing support of memfd_create syscall.
   if (FLAG_dual_map_code) {
     intptr_t size = page_size_;
     intptr_t alignment = 256 * 1024;  // e.g. heap page size.
     VirtualMemory* vm = AllocateAligned(size, alignment, true, NULL);
+    if (vm == NULL) {
+      LOG_INFO("memfd_create not supported; disabling dual mapping of code.\n");
+      FLAG_dual_map_code = false;
+      return;
+    }
     void* region = reinterpret_cast<void*>(vm->region_.start());
     void* alias = reinterpret_cast<void*>(vm->alias_.start());
     if (region == alias ||
         mprotect(region, size, PROT_READ) != 0 ||  // Remove PROT_WRITE.
         mprotect(alias, size, PROT_READ | PROT_EXEC) != 0) {  // Add PROT_EXEC.
-      LOG_INFO("disabling dual mapping of code\n");
+      LOG_INFO("mprotect fails; disabling dual mapping of code.\n");
       FLAG_dual_map_code = false;
     }
     delete vm;
   }
-#endif                        // defined(DUAL_MAPPING_SUPPORTED)
+#endif  // defined(DUAL_MAPPING_SUPPORTED)
 }
 
 static void unmap(uword start, uword end) {
@@ -80,6 +83,16 @@
 }
 
 #if defined(DUAL_MAPPING_SUPPORTED)
+// Wrapper to call memfd_create syscall.
+static inline int memfd_create(const char* name, unsigned int flags) {
+#if !defined(__NR_memfd_create)
+  errno = ENOSYS;
+  return -1;
+#else
+  return syscall(__NR_memfd_create, name, flags);
+#endif
+}
+
 static void* MapAligned(int fd,
                         int prot,
                         intptr_t size,
@@ -130,14 +143,11 @@
   const bool dual_mapping =
       is_executable && FLAG_write_protect_code && FLAG_dual_map_code;
   if (dual_mapping) {
-    // Create a shared memory object for dual mapping.
-    // There is a small conflict window, i.e. another Dart process
-    // simultaneously opening an object with the same name.
-    do {
-      fd = shm_open(DART_SHM_NAME, O_RDWR | O_CREAT | O_EXCL, S_IRWXU);
-    } while ((fd == -1) && (errno == EEXIST));
-    shm_unlink(DART_SHM_NAME);
-    if ((fd == -1) || (ftruncate(fd, size) == -1)) {
+    fd = memfd_create("dart_vm", 0);
+    if (fd == -1) {
+      return NULL;
+    }
+    if (ftruncate(fd, size) == -1) {
       close(fd);
       return NULL;
     }