Skip to content

Commit

Permalink
Use MAP_JIT when doing an mmap for executable pages (needed for macOS…
Browse files Browse the repository at this point in the history
… Catalina).

Please refer to https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_cs_allow-jit for more details.

This is the Dart VM part for flutter/flutter#36714

Change-Id: Ifbc0ce82921d5f05421e01ce2d19423a5f3e32f9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/112849
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Siva Annamalai <asiva@google.com>
  • Loading branch information
a-siva authored and commit-bot@chromium.org committed Aug 14, 2019
1 parent f87237c commit ec2d06d
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 2 deletions.
73 changes: 73 additions & 0 deletions runtime/platform/utils_macos.cc
Expand Up @@ -7,6 +7,9 @@

#include "platform/utils.h"

#include <errno.h> // NOLINT
#include <sys/utsname.h> // NOLINT

namespace dart {

char* Utils::StrNDup(const char* s, intptr_t n) {
Expand Down Expand Up @@ -64,6 +67,76 @@ int Utils::VSNPrint(char* str, size_t size, const char* format, va_list args) {
return retval;
}

namespace internal {

// Returns the running system's Darwin major version. Don't call this, it's
// an implementation detail and its result is meant to be cached by
// MacOSXMinorVersion.
int32_t DarwinMajorVersionInternal() {
// uname is implemented as a simple series of sysctl system calls to
// obtain the relevant data from the kernel. The data is
// compiled right into the kernel, so no threads or blocking or other
// funny business is necessary.

struct utsname uname_info;
if (uname(&uname_info) != 0) {
FATAL("Fatal error in DarwinMajorVersionInternal : invalid return uname");
return 0;
}

if (strcmp(uname_info.sysname, "Darwin") != 0) {
FATAL1(
"Fatal error in DarwinMajorVersionInternal : unexpected uname"
" sysname '%s'",
uname_info.sysname);
return 0;
}

int32_t darwin_major_version = 0;
char* dot = strchr(uname_info.release, '.');
if (dot) {
errno = 0;
char* end_ptr = NULL;
darwin_major_version = strtol(uname_info.release, &end_ptr, 10);
if (errno != 0 || (end_ptr == uname_info.release)) {
dot = NULL;
}
}

if (!dot) {
FATAL1(
"Fatal error in DarwinMajorVersionInternal :"
" could not parse uname release '%s'",
uname_info.release);
return 0;
}

return darwin_major_version;
}

// Returns the running system's Mac OS X minor version. This is the |y| value
// in 10.y or 10.y.z. Don't call this, it's an implementation detail and the
// result is meant to be cached by MacOSXMinorVersion.
int32_t MacOSXMinorVersionInternal() {
int darwin_major_version = DarwinMajorVersionInternal();

// The Darwin major version is always 4 greater than the Mac OS X minor
// version for Darwin versions beginning with 6, corresponding to Mac OS X
// 10.2. Since this correspondence may change in the future, warn when
// encountering a version higher than anything seen before. Older Darwin
// versions, or versions that can't be determined, result in
// immediate death.
ASSERT(darwin_major_version >= 6);
return (darwin_major_version - 4);
}

int32_t MacOSXMinorVersion() {
static int mac_os_x_minor_version = MacOSXMinorVersionInternal();
return mac_os_x_minor_version;
}

} // namespace internal

} // namespace dart

#endif // defined(HOST_OS_MACOS)
61 changes: 61 additions & 0 deletions runtime/platform/utils_macos.h
Expand Up @@ -5,10 +5,71 @@
#ifndef RUNTIME_PLATFORM_UTILS_MACOS_H_
#define RUNTIME_PLATFORM_UTILS_MACOS_H_

#include <AvailabilityMacros.h>
#include <libkern/OSByteOrder.h> // NOLINT

namespace dart {

namespace internal {

// Returns the system's Mac OS X minor version. This is the |y| value
// in 10.y or 10.y.z.
int32_t MacOSXMinorVersion();

} // namespace internal

// Run-time OS version checks.
#define DEFINE_IS_OS_FUNCS(V, TEST_DEPLOYMENT_TARGET) \
inline bool IsOS10_##V() { \
TEST_DEPLOYMENT_TARGET(>, V, false) \
return internal::MacOSXMinorVersion() == V; \
} \
inline bool IsAtLeastOS10_##V() { \
TEST_DEPLOYMENT_TARGET(>=, V, true) \
return internal::MacOSXMinorVersion() >= V; \
} \
inline bool IsAtMostOS10_##V() { \
TEST_DEPLOYMENT_TARGET(>, V, false) \
return internal::MacOSXMinorVersion() <= V; \
}

#define TEST_DEPLOYMENT_TARGET(OP, V, RET) \
if (MAC_OS_X_VERSION_MIN_REQUIRED OP MAC_OS_X_VERSION_10_##V) return RET;
#define IGNORE_DEPLOYMENT_TARGET(OP, V, RET)

DEFINE_IS_OS_FUNCS(9, TEST_DEPLOYMENT_TARGET)
DEFINE_IS_OS_FUNCS(10, TEST_DEPLOYMENT_TARGET)

#ifdef MAC_OS_X_VERSION_10_11
DEFINE_IS_OS_FUNCS(11, TEST_DEPLOYMENT_TARGET)
#else
DEFINE_IS_OS_FUNCS(11, IGNORE_DEPLOYMENT_TARGET)
#endif

#ifdef MAC_OS_X_VERSION_10_12
DEFINE_IS_OS_FUNCS(12, TEST_DEPLOYMENT_TARGET)
#else
DEFINE_IS_OS_FUNCS(12, IGNORE_DEPLOYMENT_TARGET)
#endif

#ifdef MAC_OS_X_VERSION_10_13
DEFINE_IS_OS_FUNCS(13, TEST_DEPLOYMENT_TARGET)
#else
DEFINE_IS_OS_FUNCS(13, IGNORE_DEPLOYMENT_TARGET)
#endif

#ifdef MAC_OS_X_VERSION_10_14
DEFINE_IS_OS_FUNCS(14, TEST_DEPLOYMENT_TARGET)
#else
DEFINE_IS_OS_FUNCS(14, IGNORE_DEPLOYMENT_TARGET)
#endif

#ifdef MAC_OS_X_VERSION_10_15
DEFINE_IS_OS_FUNCS(15, TEST_DEPLOYMENT_TARGET)
#else
DEFINE_IS_OS_FUNCS(15, IGNORE_DEPLOYMENT_TARGET)
#endif

inline int Utils::CountLeadingZeros(uword x) {
#if defined(ARCH_IS_32_BIT)
return __builtin_clzl(x);
Expand Down
11 changes: 9 additions & 2 deletions runtime/vm/virtual_memory_posix.cc
Expand Up @@ -194,6 +194,8 @@ VirtualMemory* VirtualMemory::AllocateAligned(intptr_t size,
// The mapping will be RX and stays that way until it will eventually be
// unmapped.
MemoryRegion region(region_ptr, size);
// DUAL_MAPPING_SUPPORTED is false in TARGET_OS_MACOS and hence support
// for MAP_JIT is not required here.
const int alias_prot = PROT_READ | PROT_EXEC;
void* alias_ptr =
MapAligned(fd, alias_prot, size, alignment, allocated_size);
Expand All @@ -211,8 +213,13 @@ VirtualMemory* VirtualMemory::AllocateAligned(intptr_t size,
const int prot =
PROT_READ | PROT_WRITE |
((is_executable && !FLAG_write_protect_code) ? PROT_EXEC : 0);
void* address =
mmap(NULL, allocated_size, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
int map_flags = MAP_PRIVATE | MAP_ANONYMOUS;
#if defined(HOST_OS_MACOS)
if (IsAtLeastOS10_14()) {
map_flags |= MAP_JIT;
}
#endif // defined(HOST_OS_MACOS)
void* address = mmap(NULL, allocated_size, prot, map_flags, -1, 0);
LOG_INFO("mmap(NULL, 0x%" Px ", %u, ...): %p\n", allocated_size, prot,
address);
if (address == MAP_FAILED) {
Expand Down

0 comments on commit ec2d06d

Please sign in to comment.