|
Hi,
So I have tried again now — first on Trixie, and then later locally again, and I can now indeed reproduce it. Using 9.2.2 was critical for doing so.
I also need to run it with valgrind, like:
export USE_ZEND_ALLOC=0
export ZEND_DONT_UNLOAD_MODULES=1
valgrind php -dpcre.jit=0 vendor/bin/phpunit --exclude-group=network --no-coverage 2>&1 | less
This produces the following warning (as first):
Invalid read of size 4
==3029939== at 0xC3C61B: zend_gc_delref (zend_types.h:1358)
==3029939== by 0xC3CF71: i_zval_ptr_dtor (zend_variables.h:44)
==3029939== by 0xC42DD1: zend_array_destroy (zend_hash.c:1843)
==3029939== by 0xCBA840: rc_dtor_func (zend_variables.c:57)
==3029939== by 0xC3CF81: i_zval_ptr_dtor (zend_variables.h:45)
==3029939== by 0xC42DD1: zend_array_destroy (zend_hash.c:1843)
==3029939== by 0xCBA840: rc_dtor_func (zend_variables.c:57)
==3029939== by 0xC3CF81: i_zval_ptr_dtor (zend_variables.h:45)
==3029939== by 0xC42D4A: zend_array_destroy (zend_hash.c:1831)
==3029939== by 0xCBA840: rc_dtor_func (zend_variables.c:57)
==3029939== by 0xCBA7BA: i_zval_ptr_dtor (zend_variables.h:45)
==3029939== by 0xCBAA00: zval_ptr_dtor (zend_variables.c:84)
==3029939== by 0x9F44133: last_exception_get_slot (stack.c:520)
==3029939== by 0x9F4681E: xdebug_develop_throw_exception_hook (stack.c:1249)
==3029939== by 0x9F05F45: xdebug_throw_exception_hook (base.c:1569)
==3029939== by 0xB8F79A: zend_throw_exception_internal (zend_exceptions.c:222)
==3029939== by 0xB92E13: zend_throw_exception_object (zend_exceptions.c:1034)
==3029939== by 0xBCE36C: ZEND_THROW_SPEC_TMPVAR_HANDLER (zend_vm_execute.h:15225)
==3029939== by 0xC2B2F9: execute_ex (zend_vm_execute.h:60765)
==3029939== by 0x9F0497C: xdebug_execute_ex (base.c:883)
==3029939== by 0xBAECAF: ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:2123)
==3029939== by 0xC298B6: execute_ex (zend_vm_execute.h:58941)
==3029939== by 0x9F0497C: xdebug_execute_ex (base.c:883)
==3029939== by 0xBAECAF: ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:2123)
==3029939== by 0xC298B6: execute_ex (zend_vm_execute.h:58941)
==3029939== by 0x9F0497C: xdebug_execute_ex (base.c:883)
==3029939== by 0xBAECAF: ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:2123)
==3029939== by 0xC298B6: execute_ex (zend_vm_execute.h:58941)
==3029939== by 0x9F0497C: xdebug_execute_ex (base.c:883)
==3029939== by 0xBAECAF: ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:2123)
==3029939== by 0xC298B6: execute_ex (zend_vm_execute.h:58941)
==3029939== by 0x9F0497C: xdebug_execute_ex (base.c:883)
==3029939== Address 0xcebfeb0 is 0 bytes inside a block of size 32 free'd
==3029939== at 0x484787F: free (vg_replace_malloc.c:989)
==3029939== by 0xB34BDC: __zend_free (zend_alloc.c:3322)
==3029939== by 0xB336B8: _efree (zend_alloc.c:2750)
==3029939== by 0xC8F3AD: list_entry_destructor (zend_list.c:182)
==3029939== by 0xC41CEC: _zend_hash_del_el_ex (zend_hash.c:1487)
==3029939== by 0xC427FB: zend_hash_index_del (zend_hash.c:1718)
==3029939== by 0xC8EF67: zend_list_free (zend_list.c:58)
==3029939== by 0xCBA840: rc_dtor_func (zend_variables.c:57)
==3029939== by 0xB99D48: i_zval_ptr_dtor (zend_variables.h:45)
==3029939== by 0xBA6731: i_free_compiled_variables (zend_execute.c:4068)
==3029939== by 0xC2967D: execute_ex (zend_vm_execute.h:58833)
==3029939== by 0x9F0497C: xdebug_execute_ex (base.c:883)
==3029939== by 0xBAECAF: ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:2123)
==3029939== by 0xC298B6: execute_ex (zend_vm_execute.h:58941)
==3029939== by 0x9F0497C: xdebug_execute_ex (base.c:883)
==3029939== by 0xBAECAF: ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:2123)
==3029939== by 0xC298B6: execute_ex (zend_vm_execute.h:58941)
==3029939== by 0x9F0497C: xdebug_execute_ex (base.c:883)
==3029939== by 0xBAECAF: ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:2123)
==3029939== by 0xC298B6: execute_ex (zend_vm_execute.h:58941)
==3029939== by 0x9F0497C: xdebug_execute_ex (base.c:883)
==3029939== by 0xBAECAF: ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:2123)
==3029939== by 0xC298B6: execute_ex (zend_vm_execute.h:58941)
==3029939== by 0x9F0497C: xdebug_execute_ex (base.c:883)
==3029939== by 0xBAECAF: ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:2123)
==3029939== by 0xC298B6: execute_ex (zend_vm_execute.h:58941)
==3029939== by 0x9F0497C: xdebug_execute_ex (base.c:883)
==3029939== by 0xBAECAF: ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:2123)
==3029939== by 0xC298B6: execute_ex (zend_vm_execute.h:58941)
==3029939== Block was alloc'd at
==3029939== at 0x4844818: malloc (vg_replace_malloc.c:446)
==3029939== by 0xB34AAA: __zend_malloc (zend_alloc.c:3294)
==3029939== by 0xB33632: _emalloc (zend_alloc.c:2740)
==3029939== by 0xC8EE4E: zend_list_insert (zend_list.c:42)
==3029939== by 0xC8F07D: zend_register_resource (zend_list.c:91)
==3029939== by 0xAAFEAA: _php_stream_alloc (streams.c:314)
==3029939== by 0xAAB73A: _php_stream_fopen_from_fd_int (plain_wrapper.c:194)
==3029939== by 0xAAB92E: _php_stream_fopen_temporary_file (plain_wrapper.c:230)
==3029939== by 0xAABA35: _php_stream_fopen_tmpfile (plain_wrapper.c:252)
==3029939== by 0x937294: zif_tmpfile (file.c:716)
==3029939== by 0xBAD1AC: ZEND_DO_ICALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:1416)
==3029939== by 0xC29826: execute_ex (zend_vm_execute.h:58896)
==3029939== by 0x9F0497C: xdebug_execute_ex (base.c:883)
==3029939== by 0xBAECAF: ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:2123)
==3029939== by 0xC298B6: execute_ex (zend_vm_execute.h:58941)
==3029939== by 0x9F0497C: xdebug_execute_ex (base.c:883)
==3029939== by 0xBAECAF: ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:2123)
==3029939== by 0xC298B6: execute_ex (zend_vm_execute.h:58941)
==3029939== by 0x9F0497C: xdebug_execute_ex (base.c:883)
==3029939== by 0xBAECAF: ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:2123)
==3029939== by 0xC298B6: execute_ex (zend_vm_execute.h:58941)
==3029939== by 0x9F0497C: xdebug_execute_ex (base.c:883)
==3029939== by 0xBAECAF: ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:2123)
==3029939== by 0xC298B6: execute_ex (zend_vm_execute.h:58941)
==3029939== by 0x9F0497C: xdebug_execute_ex (base.c:883)
==3029939== by 0xBAECAF: ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:2123)
==3029939== by 0xC298B6: execute_ex (zend_vm_execute.h:58941)
==3029939== by 0x9F0497C: xdebug_execute_ex (base.c:883)
==3029939== by 0xBAECAF: ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:2123)
==3029939== by 0xC298B6: execute_ex (zend_vm_execute.h:58941)
==3029939== by 0x9F0497C: xdebug_execute_ex (base.c:883)
==3029939== by 0xBAECAF: ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:2123)
This provides the following hints.
From Block was alloc'd at, we see:
==3029939== at 0x4844818: malloc (vg_replace_malloc.c:446)
==3029939== by 0xB34AAA: __zend_malloc (zend_alloc.c:3294)
==3029939== by 0xB33632: _emalloc (zend_alloc.c:2740)
==3029939== by 0xC8EE4E: zend_list_insert (zend_list.c:42)
==3029939== by 0xC8F07D: zend_register_resource (zend_list.c:91)
==3029939== by 0xAAFEAA: _php_stream_alloc (streams.c:314)
==3029939== by 0xAAB73A: _php_stream_fopen_from_fd_int (plain_wrapper.c:194)
==3029939== by 0xAAB92E: _php_stream_fopen_temporary_file (plain_wrapper.c:230)
==3029939== by 0xAABA35: _php_stream_fopen_tmpfile (plain_wrapper.c:252)
==3029939== by 0x937294: zif_tmpfile (file.c:716)
And this allocation gets freed in the Address 0xcebfeb0 is 0 bytes inside a block of size 32 free'd section:
==3029939== at 0x484787F: free (vg_replace_malloc.c:989)
==3029939== by 0xB34BDC: __zend_free (zend_alloc.c:3322)
==3029939== by 0xB336B8: _efree (zend_alloc.c:2750)
==3029939== by 0xC8F3AD: list_entry_destructor (zend_list.c:182)
==3029939== by 0xC41CEC: _zend_hash_del_el_ex (zend_hash.c:1487)
==3029939== by 0xC427FB: zend_hash_index_del (zend_hash.c:1718)
==3029939== by 0xC8EF67: zend_list_free (zend_list.c:58)
==3029939== by 0xCBA840: rc_dtor_func (zend_variables.c:57)
==3029939== by 0xB99D48: i_zval_ptr_dtor (zend_variables.h:45)
==3029939== by 0xBA6731: i_free_compiled_variables (zend_execute.c:4068)
These two together show that the stream resource opened with tmpfile is freed at the end of a function/method call during the i_free_compiled_variables stage.
Then Xdebug later uses this freed memory when it tries to show an exception (xdebug_develop_throw_exception_hook) where it then also tries to free this memory.
However, I can't quite see how this happens, as I do increase the ref count for the exceptions when they get caught. But for some reason the refcount for the stream resource is not affected by this, and gets freed regardless. Reducing this test case is not so easy, as the freeing of this exception that Xdebug keeps hold of only happens after 8 other exceptions.
However, the fix is easy, and I've made a PR: https://github.com/xdebug/xdebug/pull/1033 |