[php-src] Issue #24730: extract() with EXTR_REFS: use-after-free still present in modes other than EXTR_OVERWRITE (follow-up to #18209)

From: Date: Mon, 26 Oct 2026 08:49:03 +0000
Subject: [php-src] Issue #24730: extract() with EXTR_REFS: use-after-free still present in modes other than EXTR_OVERWRITE (follow-up to #18209)
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-253208@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/24730 Author: IzaiahSun ### Description The following code: ```php <?php class Old { public function __destruct() { $GLOBALS['b'] = 43; } } $b = new Old; $array = ['b' => 42]; extract($array, EXTR_REFS | EXTR_IF_EXISTS); ``` Resulted in this output: ``` ==72028==ERROR: AddressSanitizer: heap-use-after-free on address 0x604000028f90 at pc 0x000103a9b2f4 bp 0x00016d37fa90 sp 0x00016d37fa88 READ of size 4 at 0x604000028f90 thread T0 #0 zend_gc_delref zend_types.h:1370 #1 zend_objects_store_del zend_objects_API.c:182 #2 rc_dtor_func zend_variables.c:57 #3 i_zval_ptr_dtor zend_variables.h:45 #4 zval_ptr_dtor zend_variables.c:84 #5 php_extract_ref_if_exists array.c:1911 #6 zif_extract array.c:2663 #7 ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER zend_vm_execute.h:1287 #8 execute_ex zend_vm_execute.h:58729 #9 zend_execute zend_vm_execute.h:64381 #10 zend_execute_script zend.c:1943 freed by thread T0 here: #0 free(libclang_rt.asan_osx_dynamic.dylib:arm64e) #1 __zend_free zend_alloc.c:3728 #2 _efree zend_alloc.c:2889 #3 zend_objects_store_del zend_objects_API.c:200 #4 zend_object_release zend_objects_API.h:77 #5 zend_objects_destroy_object zend_objects.c:209 #6 zend_objects_store_del zend_objects_API.c:181 #7 rc_dtor_func zend_variables.c:57 #8 i_zval_ptr_dtor zend_variables.h:45 #9 zval_ptr_dtor zend_variables.c:84 #10 php_extract_ref_if_exists array.c:1911 SUMMARY: AddressSanitizer: heap-use-after-free zend_types.h:1370 in zend_gc_delref ``` But I expected this output instead: ``` (no output, clean exit) ``` --- Debug + ASan build, run with USE_ZEND_ALLOC=0. The fix for #18209 was applied to php_extract_ref_overwrite() only. The five sibling functions still destroy the old variable before overwriting the slot, so the same use-after-free is reachable through the other EXTR_REFS modes. ext/standard/array.c, e.g. php_extract_ref_if_exists(): ```c zval_ptr_dtor(orig_var); ZVAL_REF(orig_var, Z_REF_P(entry)); ``` Affected: php_extract_ref_if_exists, php_extract_ref_prefix_if_exists, php_extract_ref_prefix_all, php_extract_ref_prefix_same, php_extract_ref_prefix_invalid. EXTR_REFS|EXTR_OVERWRITE is clean, as expected after #18209. The other four modes crash the same way with the variable named to match the mode: | Mode | Reproducer differs by | | --- | --- | | EXTR_REFS\|EXTR_PREFIX_ALL, prefix p | $p_b = new Old; | | EXTR_REFS\|EXTR_PREFIX_SAME, prefix p | $b = 1; $p_b = new Old; | | EXTR_REFS\|EXTR_PREFIX_IF_EXISTS, prefix p | $b = 1; $p_b = new Old; | | EXTR_REFS\|EXTR_PREFIX_INVALID, prefix p | $p_0 = new Old; with [0 => 42] | ### PHP Version ```plain PHP 8.4.28-dev (cli) (built: Oct 25 2026 01:02:13) (NTS DEBUG) Copyright (c) The PHP Group Zend Engine v4.4.28-dev, Copyright (c) Zend Technologies Also reproduced on master (29b5e168bf): PHP 8.7.0-dev (cli) (built: Oct 24 2026 21:13:17) (NTS DEBUG) Copyright © The PHP Group and Contributors Zend Engine v4.7.0-dev, Copyright © Zend by Perforce with Zend OPcache v8.7.0-dev, Copyright ©, by Zend by Perforce ``` ### Operating System macOS 27.0.1 (arm64)

« previous php.bugs (#253208) next »