diff --git a/zend_abstract_interface/jit_utils/jit_blacklist.c b/zend_abstract_interface/jit_utils/jit_blacklist.c index 059c5bba2b..98cf32695c 100644 --- a/zend_abstract_interface/jit_utils/jit_blacklist.c +++ b/zend_abstract_interface/jit_utils/jit_blacklist.c @@ -88,10 +88,6 @@ typedef union _zend_op_trace_info { #define ZEND_OP_TRACE_INFO(opline, offset) \ ((zend_op_trace_info*)(((char*)opline) + offset)) - -#ifndef _WIN32 -static int dd_probe_pipes[2]; -#endif #endif #define ZEND_FUNC_INFO(op_array) \ @@ -107,9 +103,6 @@ static void zai_jit_find_opcache_handle(void *ext) { // opcache startup NULLs its handle. MINIT is executed before extension startup. void zai_jit_minit(void) { -#if PHP_VERSION_ID < 80400 && !defined(_WIN32) - pipe(dd_probe_pipes); -#endif zend_llist_apply(&zend_extensions, zai_jit_find_opcache_handle); } @@ -185,6 +178,68 @@ int zai_get_zend_func_rid(zend_op_array *op_array) { return zend_func_info_rid; } +#if defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__)) && PHP_VERSION_ID < 80400 +static bool is_mapped(void *addr, size_t size) { + uintptr_t page_size = sysconf(_SC_PAGESIZE); + assert(size <= page_size); + uintptr_t page_addr = ((uintptr_t)addr & ~(page_size - 1)); + uintptr_t last_page_addr = ((uintptr_t)(addr + size - 1) & ~(page_size - 1)); + + unsigned char vec[2]; +#ifdef __x86_64__ +#define SYS_mincore 0x1B +#else // aarch64 +#define SYS_mincore 0xE8 +#endif + + int retries = 5; +again: + if (syscall(SYS_mincore, page_addr, (1 + (page_addr != last_page_addr)) * page_size, &vec) == 0) { + return true; + } else if (errno == EFAULT || errno == ENOMEM) { + return false; + } else if (errno == EAGAIN) { + if (retries-- > 0) { + goto again; + } + return true; + } else { + // we don't know... assume true +#ifdef ZEND_DEBUG + abort(); +#else + return true; +#endif + } +} +#elif defined(__APPLE__) && PHP_VERSION_ID < 80400 +#include +static bool is_mapped(void *addr, size_t size) { + mach_port_t task = mach_task_self(); + vm_address_t address = (vm_address_t)addr; + + while (address < (vm_address_t)addr + size) { + __auto_type a = address; + vm_size_t region_size; + vm_region_basic_info_data_64_t info; + kern_return_t kr = vm_region_64(task, &address, ®ion_size, VM_REGION_BASIC_INFO, (vm_region_info_t)&info, + &(mach_msg_type_number_t){VM_REGION_BASIC_INFO_COUNT_64}, &(memory_object_name_t){0}); + + if (kr != KERN_SUCCESS || !(info.protection & VM_PROT_READ)) { + return false; + } + + address += region_size; + } + + return true; +} +#else +static inline bool is_mapped(...) { + return true; +} +#endif + void zai_jit_blacklist_function_inlining(zend_op_array *op_array) { #if PHP_VERSION_ID >= 80400 if (opcache_handle) { @@ -210,15 +265,11 @@ void zai_jit_blacklist_function_inlining(zend_op_array *op_array) { size_t offset = jit_extension->offset; -#ifndef _WIN32 // check whether the op_trace_info is actually readable or EFAULTing // we can't trust opcache too much here... - char dummy_buf[sizeof(zend_op_trace_info)]; - if (write(dd_probe_pipes[1], ZEND_OP_TRACE_INFO(opline, offset), sizeof(zend_op_trace_info)) < 0) { + if (!is_mapped(ZEND_OP_TRACE_INFO(opline, offset), sizeof(zend_op_trace_info))) { return; } - read(dd_probe_pipes[0], dummy_buf, sizeof(zend_op_trace_info)); -#endif if (!(ZEND_OP_TRACE_INFO(opline, offset)->trace_flags & ZEND_JIT_TRACE_BLACKLISTED)) { bool is_protected_memory = false;