View Issue Details

IDProjectCategoryView StatusLast Update
0002328XdebugUncategorizedpublic2025-08-29 08:55
Reportertenzap Assigned Toderick  
PrioritynormalSeveritymajorReproducibilityalways
Status closedResolutionfixed 
Product Version3.4.1 
Target Version3.4devFixed in Version3.4dev 
Summary0002328: Stream resource references in stored stack traces don't hold, and can cause crashes
Description

Running the tests of php-league-csv leads to crash.

phpunit --exclude-group network --no-coverage

Running it with
export USE_ZEND_ALLOC=0
export ZEND_DONT_UNLOAD_MODULES=1
doesn't lead to crash

Steps To Reproduce

Run the test suite of https://github.com/thephpleague/csv/ version 9.22.0

Command:

vendor/bin/phpunit --exclude-group network --no-coverage

You could also try this command which results into the same crash:

composer run-script phpunit-min

Be sure to not have XDEBUG_MODE=coverage, because when it is set, the tests don't fail.

If Xdebug is not installed, it doesn't fail either.

Output is

PHPUnit 11.5.11 by Sebastian Bergmann and contributors.

Runtime: PHP 8.4.4
Configuration: /mnt/packages/git_repos/dpkg/php-league-csv/phpunit.xml

............................................................... 63 / 678 ( 9%)
............................................................... 126 / 678 ( 18%)
..........DDDDD................................................ 189 / 678 ( 27%)
....................................DDDDDDDDDDD.............zend_mm_heap corrupted
Aborted (core dumped)

I also attach the output of valgrind, invoked with various parameters.

TagsNo tags attached.
Attached Files
valgrind.log.gz (1,096 bytes)
Operating SystemDebian trixie
PHP Version8.4-dev

Activities

tenzap

2025-03-07 07:36

reporter   ~0007196

There is a typo. It's not

composer run-script phpunit-min

but

composer run-script phpunit:min

derick

2025-03-07 12:07

administrator   ~0007198

Hi,

I can't seem to be able to reproduce this.

  1. Could you share the output of php -r 'xdebug_info();'
  2. You say that you're using Debian trixie, which is "testing". I wonder whether that is the problem. Can you try with "bookwork" perhaps?
  3. Your reproduce case runs through a lot of tests. Would you be able to narrow it down into running just the test that makes things fail? You can use phpunit's --debug flag for that

cheers,
Derick

tenzap

2025-03-07 12:33

reporter   ~0007202

  1. See attachement
  2. It works on bookworm but this is with php 8.2 & xdebug 3.2. We can only say that the problem is probably not in league/csv
  3. Running only the crashing test succeeds when run alone. Even running the tests ot the class that contain it succeeds.
xdebug_info.txt (5,279 bytes)   
__   __   _      _                 
\ \ / /  | |    | |                
 \ V / __| | ___| |__  _   _  __ _ 
  > < / _` |/ _ \ '_ \| | | |/ _` |
 / . \ (_| |  __/ |_) | |_| | (_| |
/_/ \_\__,_|\___|_.__/ \__,_|\__, |
                              __/ |
                             |___/ 

Version => 3.4.1
Support Xdebug on Patreon, GitHub, or as a business: https://xdebug.org/support

             Enabled Features (through 'xdebug.mode' setting)             
Feature => Enabled/Disabled
Development Helpers => ✔ enabled
Coverage => ✘ disabled
GC Stats => ✘ disabled
Profiler => ✘ disabled
Step Debugger => ✘ disabled
Tracing => ✘ disabled

                            Optional Features                            
Compressed File Support => yes (gzip)
Clock Source => clock_gettime
TSC Clock Source => unavailable
'xdebug://gateway' pseudo-host support => yes
'xdebug://nameserver' pseudo-host support => yes
Systemd Private Temp Directory => not enabled

                              Diagnostic Log                              
[Config] WARN: Not setting up control socket with default value due to unavailable 'tsc' clock

                                   PHP                                   
                           Build Configuration                           
Version (Run Time) => 8.4.4
Version (Compile Time) => 8.4.3
Debug Build => no
Thread Safety => disabled
                                 Settings                                 
Configuration File (php.ini) Path => /etc/php/8.4/cli
Loaded Configuration File => /etc/php/8.4/cli/php.ini
Scan this dir for additional .ini files => /etc/php/8.4/cli/conf.d
Additional .ini files parsed => /etc/php/8.4/cli/conf.d/10-mysqlnd.ini,
/etc/php/8.4/cli/conf.d/10-opcache.ini,
/etc/php/8.4/cli/conf.d/10-pdo.ini,
/etc/php/8.4/cli/conf.d/15-xml.ini,
/etc/php/8.4/cli/conf.d/20-calendar.ini,
/etc/php/8.4/cli/conf.d/20-ctype.ini,
/etc/php/8.4/cli/conf.d/20-curl.ini,
/etc/php/8.4/cli/conf.d/20-dom.ini,
/etc/php/8.4/cli/conf.d/20-exif.ini,
/etc/php/8.4/cli/conf.d/20-ffi.ini,
/etc/php/8.4/cli/conf.d/20-fileinfo.ini,
/etc/php/8.4/cli/conf.d/20-ftp.ini,
/etc/php/8.4/cli/conf.d/20-gettext.ini,
/etc/php/8.4/cli/conf.d/20-iconv.ini,
/etc/php/8.4/cli/conf.d/20-intl.ini,
/etc/php/8.4/cli/conf.d/20-mbstring.ini,
/etc/php/8.4/cli/conf.d/20-mysqli.ini,
/etc/php/8.4/cli/conf.d/20-pdo_mysql.ini,
/etc/php/8.4/cli/conf.d/20-pdo_pgsql.ini,
/etc/php/8.4/cli/conf.d/20-pdo_sqlite.ini,
/etc/php/8.4/cli/conf.d/20-pgsql.ini,
/etc/php/8.4/cli/conf.d/20-phar.ini,
/etc/php/8.4/cli/conf.d/20-posix.ini,
/etc/php/8.4/cli/conf.d/20-readline.ini,
/etc/php/8.4/cli/conf.d/20-shmop.ini,
/etc/php/8.4/cli/conf.d/20-simplexml.ini,
/etc/php/8.4/cli/conf.d/20-sockets.ini,
/etc/php/8.4/cli/conf.d/20-sqlite3.ini,
/etc/php/8.4/cli/conf.d/20-sysvmsg.ini,
/etc/php/8.4/cli/conf.d/20-sysvsem.ini,
/etc/php/8.4/cli/conf.d/20-sysvshm.ini,
/etc/php/8.4/cli/conf.d/20-tokenizer.ini,
/etc/php/8.4/cli/conf.d/20-xdebug.ini,
/etc/php/8.4/cli/conf.d/20-xmlreader.ini,
/etc/php/8.4/cli/conf.d/20-xmlwriter.ini,
/etc/php/8.4/cli/conf.d/20-xsl.ini,
/etc/php/8.4/cli/conf.d/20-zip.ini


Directive => Local Value => Master Value
xdebug.mode => develop => develop
xdebug.start_with_request => default => default
xdebug.start_upon_error => default => default
xdebug.output_dir => /tmp => /tmp
xdebug.use_compression => 1 => 1
xdebug.trigger_value => no value => no value
xdebug.file_link_format => no value => no value
xdebug.filename_format => no value => no value
xdebug.control_socket => off => off
xdebug.log => no value => no value
xdebug.log_level => 7 => 7
xdebug.var_display_max_children => 128 => 128
xdebug.var_display_max_data => 512 => 512
xdebug.var_display_max_depth => 3 => 3
xdebug.max_nesting_level => 512 => 512
xdebug.cli_color => 0 => 0
xdebug.force_display_errors => Off => Off
xdebug.force_error_reporting => 0 => 0
xdebug.halt_level => 0 => 0
xdebug.max_stack_frames => -1 => -1
xdebug.show_error_trace => Off => Off
xdebug.show_exception_trace => Off => Off
xdebug.show_local_vars => Off => Off
xdebug.dump.COOKIE => no value => no value
xdebug.dump.ENV => no value => no value
xdebug.dump.FILES => no value => no value
xdebug.dump.GET => no value => no value
xdebug.dump.POST => no value => no value
xdebug.dump.REQUEST => no value => no value
xdebug.dump.SERVER => no value => no value
xdebug.dump.SESSION => no value => no value
xdebug.dump_globals => On => On
xdebug.dump_once => On => On
xdebug.dump_undefined => Off => Off
xdebug.profiler_output_name => cachegrind.out.%p => cachegrind.out.%p
xdebug.profiler_append => Off => Off
xdebug.cloud_id => no value => no value
xdebug.client_host => localhost => localhost
xdebug.client_port => 9003 => 9003
xdebug.discover_client_host => Off => Off
xdebug.client_discovery_header => HTTP_X_FORWARDED_FOR,REMOTE_ADDR => HTTP_X_FORWARDED_FOR,REMOTE_ADDR
xdebug.idekey => no value => no value
xdebug.connect_timeout_ms => 200 => 200
xdebug.scream => Off => Off
xdebug.gc_stats_output_name => gcstats.%p => gcstats.%p
xdebug.trace_output_name => trace.%c => trace.%c
xdebug.trace_format => 0 => 0
xdebug.trace_options => 0 => 0
xdebug.collect_assignments => Off => Off
xdebug.collect_params => On => On
xdebug.collect_return => Off => Off
xdebug_info.txt (5,279 bytes)   

tenzap

2025-03-07 12:34

reporter   ~0007203

By the way it also fais on debian's CI, so my system is not particularly in cause.

tenzap

2025-03-07 12:53

reporter   ~0007204

I found that:

test suite succeeds with
xdebug.mode = debug,coverage

test suite crashes when xdebug.mode is not set, which corresponds to
xdebug.mode = develop

tenzap

2025-03-13 07:55

reporter   ~0007213

This bug is still present in 3.4.2

tenzap

2025-08-16 15:24

reporter   ~0007347

I tested again with xdebug 3.4.5 & php 8.4.11 on Debian trixie and it still fails.

derick

2025-08-27 14:05

administrator   ~0007348

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

derick

2025-08-29 08:55

administrator   ~0007350

@tenzap — it would be nice if you could test the xdebug_3_4 branch of Xdebug's GIT repo (https://github.com/xdebug/xdebug) to verify it is also fixed for you. I can then make a release.

Issue History

Date Modified Username Field Change
2025-03-07 07:34 tenzap New Issue
2025-03-07 07:34 tenzap File Added: valgrind--leak-check=full--show-leak-kinds=all.log.xz
2025-03-07 07:34 tenzap File Added: valgrind--leak-check=full.log.xz
2025-03-07 07:34 tenzap File Added: valgrind.log.gz
2025-03-07 07:36 tenzap Note Added: 0007196
2025-03-07 12:07 derick Assigned To => derick
2025-03-07 12:07 derick Status new => feedback
2025-03-07 12:07 derick Note Added: 0007198
2025-03-07 12:33 tenzap Note Added: 0007202
2025-03-07 12:33 tenzap File Added: xdebug_info.txt
2025-03-07 12:33 tenzap Status feedback => assigned
2025-03-07 12:34 tenzap Note Added: 0007203
2025-03-07 12:53 tenzap Note Added: 0007204
2025-03-13 07:55 tenzap Note Added: 0007213
2025-08-16 15:24 tenzap Note Added: 0007347
2025-08-27 14:05 derick Note Added: 0007348
2025-08-27 14:07 derick Target Version => 3.4dev
2025-08-27 14:07 derick Summary tests failing with zend_mm_heap corrupted => Stream resource references in stored stack traces don't hold, and can cause crashes
2025-08-27 15:02 derick Status assigned => closed
2025-08-27 15:02 derick Resolution open => fixed
2025-08-27 15:02 derick Fixed in Version => 3.4dev
2025-08-29 08:55 derick Note Added: 0007350