diff --git a/Zend/tests/gh14626.phpt b/Zend/tests/gh14626.phpt new file mode 100644 index 0000000000000..c0c029fcd8474 --- /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 0952a88a41194..e86f2961cfac9 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -2455,17 +2455,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 0000000000000..f69122e288917 --- /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 8ab8a06107eb1..2df6c2027498a 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -628,6 +628,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 e4439fe38c05f..7dc348934400f 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -189,6 +189,8 @@ function zend_test_set_fmode(bool $binary): 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 c07e3dca01bed..19ea9e7a2adf5 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: 98cade449e4dcf038166adeee07b17308dd48725 */ + * Stub hash: 07ce28cd75080118509ac0d30d8ce5ef54110747 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -122,6 +122,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 @@ -230,6 +234,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); @@ -293,6 +298,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)