diff --git a/Zend/tests/gh14626.phpt b/Zend/tests/gh14626.phpt new file mode 100644 index 00000000000..c0c029fcd84 --- /dev/null +++ b/Zend/tests/gh14626.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-14626: is_zend_ptr() may crash for non-zend ptrs when huge blocks exist +--EXTENSIONS-- +zend_test +--FILE-- + +==DONE== +--EXPECT-- +==DONE== diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index bf2116fc91f..50f1bbbb69c 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -2469,17 +2469,15 @@ ZEND_API bool is_zend_ptr(const void *ptr) } while (chunk != AG(mm_heap)->main_chunk); } - if (AG(mm_heap)->huge_list) { - zend_mm_huge_list *block = AG(mm_heap)->huge_list; - - do { - if (ptr >= (void*)block - && ptr < (void*)((char*)block + block->size)) { - return 1; - } - block = block->next; - } while (block != AG(mm_heap)->huge_list); + zend_mm_huge_list *block = AG(mm_heap)->huge_list; + while (block) { + if (ptr >= (void*)block + && ptr < (void*)((char*)block + block->size)) { + return 1; + } + block = block->next; } + return 0; } diff --git a/ext/ffi/tests/gh14626.phpt b/ext/ffi/tests/gh14626.phpt new file mode 100644 index 00000000000..f69122e2889 --- /dev/null +++ b/ext/ffi/tests/gh14626.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-14626: FFI::free() may crash in is_zend_ptr() when at least one huge block exists and the ptr is non-zend +--EXTENSIONS-- +ffi +--SKIPIF-- + +--INI-- +ffi.enable=1 +--FILE-- +malloc(10); +$addr = $ffi->cast("uintptr_t", $ffi->cast("char*", $ptr))->cdata; + +$ptr = FFI::cdef()->cast("char*", $addr); + +// Should not crash in is_zend_ptr() +FFI::free($ptr); + +?> +==DONE== +--EXPECT-- +==DONE== diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index e4a8870f77e..a5534284d99 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -782,6 +782,17 @@ static ZEND_FUNCTION(zend_test_cast_fread) } } +static ZEND_FUNCTION(zend_test_is_zend_ptr) +{ + zend_long addr; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(addr); + ZEND_PARSE_PARAMETERS_END(); + + RETURN_BOOL(is_zend_ptr((void*)addr)); +} + static zend_object *zend_test_class_new(zend_class_entry *class_type) { zend_object *obj = zend_objects_new(class_type); diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index abe51785612..6d9df7b85be 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -253,6 +253,8 @@ function zend_test_override_libxml_global_state(): void {} /** @param resource $stream */ function zend_test_cast_fread($stream): void {} + + function zend_test_is_zend_ptr(int $addr): bool {} } namespace ZendTestNS { diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 66dbaccc681..134322e0367 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 98329c979738792b2fc672d5b5c5a4b5dc0271f4 */ + * Stub hash: 127c7004a014495353135df6d0b6658446ae040b */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -154,6 +154,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_cast_fread, 0, 1, IS_V ZEND_ARG_INFO(0, stream) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_is_zend_ptr, 0, 1, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, addr, IS_LONG, 0) +ZEND_END_ARG_INFO() + #define arginfo_ZendTestNS2_namespaced_func arginfo_zend_test_is_pcre_bundled #define arginfo_ZendTestNS2_namespaced_deprecated_func arginfo_zend_test_void_return @@ -280,6 +284,7 @@ static ZEND_FUNCTION(zend_test_is_pcre_bundled); static ZEND_FUNCTION(zend_test_set_fmode); #endif static ZEND_FUNCTION(zend_test_cast_fread); +static ZEND_FUNCTION(zend_test_is_zend_ptr); static ZEND_FUNCTION(ZendTestNS2_namespaced_func); static ZEND_FUNCTION(ZendTestNS2_namespaced_deprecated_func); static ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_func); @@ -357,6 +362,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_test_set_fmode, arginfo_zend_test_set_fmode) #endif ZEND_FE(zend_test_cast_fread, arginfo_zend_test_cast_fread) + ZEND_FE(zend_test_is_zend_ptr, arginfo_zend_test_is_zend_ptr) ZEND_NS_FALIAS("ZendTestNS2", namespaced_func, ZendTestNS2_namespaced_func, arginfo_ZendTestNS2_namespaced_func) ZEND_NS_DEP_FALIAS("ZendTestNS2", namespaced_deprecated_func, ZendTestNS2_namespaced_deprecated_func, arginfo_ZendTestNS2_namespaced_deprecated_func) ZEND_NS_FALIAS("ZendTestNS2", namespaced_aliased_func, zend_test_void_return, arginfo_ZendTestNS2_namespaced_aliased_func)