]> granicus.if.org Git - php/commitdiff
Backport MAP_JIT fixes from PCRE2 10.33
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 18 Sep 2019 07:28:54 +0000 (09:28 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 18 Sep 2019 07:28:54 +0000 (09:28 +0200)
This is intended to fix the primary issue from bug #77260.

Prior to macOS 10.14 multiple MAP_JIT segments were not permitted,
leading to mmap failures and corresponding "no more memory" errors
on macOS 10.13.

ext/pcre/pcre2lib/sljit/sljitExecAllocator.c

index 7c18578618cfa7c16e01bb5a44baae54af02e000..3b37a9751f81baa4509e40f4f0d2c20b54a7a9d5 100644 (file)
@@ -94,6 +94,46 @@ static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
 
 #else
 
+#ifdef __APPLE__
+/* Configures TARGET_OS_OSX when appropriate */
+#include <TargetConditionals.h>
+
+#if TARGET_OS_OSX && defined(MAP_JIT)
+#include <sys/utsname.h>
+#endif /* TARGET_OS_OSX && MAP_JIT */
+
+#ifdef MAP_JIT
+
+static SLJIT_INLINE int get_map_jit_flag()
+{
+#if TARGET_OS_OSX
+       /* On macOS systems, returns MAP_JIT if it is defined _and_ we're running on a version
+          of macOS where it's OK to have more than one JIT block. On non-macOS systems, returns
+          MAP_JIT if it is defined. */
+       static int map_jit_flag = -1;
+
+       /* The following code is thread safe because multiple initialization
+          sets map_jit_flag to the same value and the code has no side-effects.
+          Changing the kernel version witout system restart is (very) unlikely. */
+       if (map_jit_flag == -1) {
+               struct utsname name;
+
+               uname(&name);
+
+               /* Kernel version for 10.14.0 (Mojave) */
+               map_jit_flag = (atoi(name.release) >= 18) ? MAP_JIT : 0;
+       }
+
+       return map_jit_flag;
+#else /* !TARGET_OS_OSX */
+       return MAP_JIT;
+#endif /* TARGET_OS_OSX */
+}
+
+#endif /* MAP_JIT */
+
+#endif /* __APPLE__ */
+
 static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
 {
        void *retval;
@@ -103,17 +143,17 @@ static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
        int flags = MAP_PRIVATE | MAP_ANON;
 
 #ifdef MAP_JIT
-       flags |= MAP_JIT;
+       flags |= get_map_jit_flag();
 #endif
 
        retval = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, flags, -1, 0);
-#else
+#else /* !MAP_ANON */
        if (dev_zero < 0) {
                if (open_dev_zero())
                        return NULL;
        }
        retval = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, dev_zero, 0);
-#endif
+#endif /* MAP_ANON */
 
        return (retval != MAP_FAILED) ? retval : NULL;
 }