php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #72854 PHP Crashes on duplicate destructor call
Submitted: 2016-08-16 14:47 UTC Modified: 2016-08-16 19:14 UTC
From: php at abiusx dot com Assigned: nikic (profile)
Status: Closed Package: Class/Object related
PHP Version: 7.0.9 OS: Mac OS X, Linux
Private report: No CVE-ID: None
 [2016-08-16 14:47 UTC] php at abiusx dot com
Description:
------------
I have a very complicated code that runs for 4 minutes. The important thing the code does, is it makes deep copies of data structures in PHP, does something, and discards the deep copy.

Many times when this happens, PHP segfaults (typically with memory violation) when the destructor of a deep copied object is called, and a resource is involved in that object.

Examples are wp-db and phpmailer classes in Wordpress, both of which segfault PHP on their destructor.

I still haven't had the chance to run PHP's debug version on it to figure out the details, but now I'm sure the bug is there (and has been since PHP 7.0.0, also tested on PHP 5.4 and it persists).


Test script:
---------------
github.com/abiusx/php-emul concolic mode on Wordpress and Joomla causes the crash.
The crash is not stack related, it is also deterministic.


Expected result:
----------------
No crash

Actual result:
--------------
Segfault (memory violation)

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-08-16 15:09 UTC] requinix@php.net
-Status: Open +Status: Feedback
 [2016-08-16 15:09 UTC] requinix@php.net
Running that php-emul stuff is a bit much for us to do. Some short repro code would be great - may be hard for you to come up with though. I know you said you haven't been able to run it though a debug version yet, but without the code then we'll need a backtrace (see http://bugs.php.net/bugs-generating-backtrace.php).
 [2016-08-16 15:12 UTC] php at abiusx dot com
-Status: Feedback +Status: Open
 [2016-08-16 15:12 UTC] php at abiusx dot com
I am aware of what you said, and I plan on doing a thorough investigation on this issue. I have faced it over and over in my line of work, both on OS X and on Ubuntu.

The backtrace is 600mb, which is not very useful. Plus, it ends up in system malloc, which is another useless clue.

I have made several attempts at making a short example that reproduces the crash, but have been unable to do so.

At this point, this bug just serves as an entry point for myself to do further research and find the problem.
 [2016-08-16 15:12 UTC] nikic@php.net
-Status: Open +Status: Feedback
 [2016-08-16 15:12 UTC] nikic@php.net
I tried running the command from the README

    php main.php -f wordpress/index.php -v 10 --strict && cat output.txt

on wordpress-4.1 and I do not observe a crash.
 [2016-08-16 15:16 UTC] php at abiusx dot com
-Status: Feedback +Status: Open
 [2016-08-16 15:16 UTC] php at abiusx dot com
It needs to run on concolic mode, I gave you access to the private Github repo, please give the analyzer a try.
Use the following:

php main.php -f wordpress/index.php --concolic --strict -v 10
 [2016-08-16 15:40 UTC] nikic@php.net
Thanks, I'm seeing a segfault now. GDB backtrace:

#0  0x0000000000b58b5a in zend_mm_alloc_small (heap=0x7fffeda00040, size=56, bin_num=6, 
    __zend_filename=0x1254a20 "/home/nikic/php-src/Zend/zend_vm_execute.h", __zend_lineno=16726, 
    __zend_orig_filename=0x0, __zend_orig_lineno=0) at /home/nikic/php-src/Zend/zend_alloc.c:1250
#1  0x0000000000b58dfd in zend_mm_alloc_heap (heap=0x7fffeda00040, size=56, 
    __zend_filename=0x1254a20 "/home/nikic/php-src/Zend/zend_vm_execute.h", __zend_lineno=16726, 
    __zend_orig_filename=0x0, __zend_orig_lineno=0) at /home/nikic/php-src/Zend/zend_alloc.c:1321
#2  0x0000000000b5b92c in _emalloc (size=24, 
    __zend_filename=0x1254a20 "/home/nikic/php-src/Zend/zend_vm_execute.h", __zend_lineno=16726, 
    __zend_orig_filename=0x0, __zend_orig_lineno=0) at /home/nikic/php-src/Zend/zend_alloc.c:2406
#3  0x0000000000c35e13 in ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER ()
    at /home/nikic/php-src/Zend/zend_vm_execute.h:16726
#4  0x0000000000c0bcd1 in execute_ex (ex=0x7fffeda36ac0)
    at /home/nikic/php-src/Zend/zend_vm_execute.h:429
#5  0x0000000000b83567 in zend_call_function (fci=0x7fffffff9d00, fci_cache=0x7fffffff9cd0)
    at /home/nikic/php-src/Zend/zend_execute_API.c:837
#6  0x0000000000bcb264 in zend_call_method (object=0x7fffffff9de0, obj_ce=0x7fffeda04820, 
    fn_proxy=0x7fffffff9db0, function_name=0x1251fbe "__destruct", function_name_len=10, 
    retval_ptr=0x0, param_count=0, arg1=0x0, arg2=0x0)
    at /home/nikic/php-src/Zend/zend_interfaces.c:102
#7  0x0000000000bf21df in zend_objects_destroy_object (object=0x7fffea6ff000)
    at /home/nikic/php-src/Zend/zend_objects.c:156
#8  0x0000000000bf98d8 in zend_objects_store_del (object=0x7fffea6ff000)
    at /home/nikic/php-src/Zend/zend_objects_API.c:160
#9  0x0000000000b990f7 in _zval_dtor_func (p=0x7fffea6ff000, 
    __zend_filename=0x12538e0 "/home/nikic/php-src/Zend/zend_execute.c", __zend_lineno=579)
    at /home/nikic/php-src/Zend/zend_variables.c:56
#10 0x0000000000b98fd6 in i_zval_ptr_dtor (zval_ptr=0x7fffec388698, 
    __zend_filename=0x12538e0 "/home/nikic/php-src/Zend/zend_execute.c", __zend_lineno=579)
    at /home/nikic/php-src/Zend/zend_variables.h:48
#11 0x0000000000b99131 in _zval_dtor_func (p=0x7fffec388690, 
    __zend_filename=0x12538e0 "/home/nikic/php-src/Zend/zend_execute.c", __zend_lineno=579)
    at /home/nikic/php-src/Zend/zend_variables.c:69
#12 0x0000000000c01735 in i_zval_ptr_dtor (zval_ptr=0x7fffeda6bc18, 
    __zend_filename=0x12538e0 "/home/nikic/php-src/Zend/zend_execute.c", __zend_lineno=579)
    at /home/nikic/php-src/Zend/zend_variables.h:48
#13 0x0000000000c03e89 in zend_assign_to_variable_reference (variable_ptr=0x7fffeda6bc18, 
    value_ptr=0x7fffeda36a90) at /home/nikic/php-src/Zend/zend_execute.c:579
#14 0x0000000000c40168 in ZEND_ASSIGN_REF_SPEC_VAR_VAR_HANDLER ()
    at /home/nikic/php-src/Zend/zend_vm_execute.h:20438
#15 0x0000000000c0bcd1 in execute_ex (ex=0x7fffeda14030)
    at /home/nikic/php-src/Zend/zend_vm_execute.h:429
#16 0x0000000000c0bed2 in zend_execute (op_array=0x7fffeda9a200, return_value=0x0)
    at /home/nikic/php-src/Zend/zend_vm_execute.h:474
#17 0x0000000000b9e93c in zend_execute_scripts (type=8, retval=0x0, file_count=3)
#18 0x0000000000ad63ee in php_execute_script (primary_file=0x7fffffffc8b0)
    at /home/nikic/php-src/main/main.c:2537
#19 0x0000000000c99e71 in do_cli (argc=8, argv=0x1642cf0)
    at /home/nikic/php-src/sapi/cli/php_cli.c:990
#20 0x0000000000c9b319 in main (argc=8, argv=0x1642cf0)
    at /home/nikic/php-src/sapi/cli/php_cli.c:1378

Warnings under USE_ZEND_ALLOC=0 valgrind:

==30704== Invalid read of size 4
==30704==    at 0xC01075: zval_delref_p (zend_types.h:834)
==30704==    by 0xC01717: i_zval_ptr_dtor (zend_variables.h:47)
==30704==    by 0xC03E88: zend_assign_to_variable_reference (zend_execute.c:579)
==30704==    by 0xC48C8B: ZEND_ASSIGN_REF_SPEC_VAR_CV_HANDLER (zend_vm_execute.h:24278)
==30704==    by 0xC0BCD0: execute_ex (zend_vm_execute.h:429)
==30704==    by 0xB83566: zend_call_function (zend_execute_API.c:837)
==30704==    by 0xBCB263: zend_call_method (zend_interfaces.c:102)
==30704==    by 0xBF21DE: zend_objects_destroy_object (zend_objects.c:156)
==30704==    by 0xBF98D7: zend_objects_store_del (zend_objects_API.c:160)
==30704==    by 0xB990F6: _zval_dtor_func (zend_variables.c:56)
==30704==    by 0xB98FD5: i_zval_ptr_dtor (zend_variables.h:48)
==30704==    by 0xB99130: _zval_dtor_func (zend_variables.c:69)
==30704==  Address 0x112b18b0 is 0 bytes inside a block of size 24 free'd
==30704==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30704==    by 0xB5BA53: _efree (zend_alloc.c:2417)
==30704==    by 0xB99153: _zval_dtor_func (zend_variables.c:70)
==30704==    by 0xC016E3: _zval_ptr_dtor_nogc (zend_variables.h:40)
==30704==    by 0xC7698E: ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_VAR_HANDLER (zend_vm_execute.h:45393)
==30704==    by 0xC0BCD0: execute_ex (zend_vm_execute.h:429)
==30704==    by 0xB83566: zend_call_function (zend_execute_API.c:837)
==30704==    by 0xBCB263: zend_call_method (zend_interfaces.c:102)
==30704==    by 0xBF21DE: zend_objects_destroy_object (zend_objects.c:156)
==30704==    by 0xBF98D7: zend_objects_store_del (zend_objects_API.c:160)
==30704==    by 0xB990F6: _zval_dtor_func (zend_variables.c:56)
==30704==    by 0xB98FD5: i_zval_ptr_dtor (zend_variables.h:48)
==30704==  Block was alloc'd at
==30704==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30704==    by 0xB5B8D8: _emalloc (zend_alloc.c:2402)
==30704==    by 0xC35E12: ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER (zend_vm_execute.h:16726)
==30704==    by 0xC0BCD0: execute_ex (zend_vm_execute.h:429)
==30704==    by 0xC0BED1: zend_execute (zend_vm_execute.h:474)
==30704==    by 0xB9E93B: zend_execute_scripts (zend.c:1447)
==30704==    by 0xAD63ED: php_execute_script (main.c:2537)
==30704==    by 0xC99E70: do_cli (php_cli.c:990)
==30704==    by 0xC9B318: main (php_cli.c:1378)
==30704== 
==30704== Invalid write of size 4
==30704==    at 0xC0107A: zval_delref_p (zend_types.h:834)
==30704==    by 0xC01717: i_zval_ptr_dtor (zend_variables.h:47)
==30704==    by 0xC03E88: zend_assign_to_variable_reference (zend_execute.c:579)
==30704==    by 0xC48C8B: ZEND_ASSIGN_REF_SPEC_VAR_CV_HANDLER (zend_vm_execute.h:24278)
==30704==    by 0xC0BCD0: execute_ex (zend_vm_execute.h:429)
==30704==    by 0xB83566: zend_call_function (zend_execute_API.c:837)
==30704==    by 0xBCB263: zend_call_method (zend_interfaces.c:102)
==30704==    by 0xBF21DE: zend_objects_destroy_object (zend_objects.c:156)
==30704==    by 0xBF98D7: zend_objects_store_del (zend_objects_API.c:160)
==30704==    by 0xB990F6: _zval_dtor_func (zend_variables.c:56)
==30704==    by 0xB98FD5: i_zval_ptr_dtor (zend_variables.h:48)
==30704==    by 0xB99130: _zval_dtor_func (zend_variables.c:69)
==30704==  Address 0x112b18b0 is 0 bytes inside a block of size 24 free'd
==30704==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30704==    by 0xB5BA53: _efree (zend_alloc.c:2417)
==30704==    by 0xB99153: _zval_dtor_func (zend_variables.c:70)
==30704==    by 0xC016E3: _zval_ptr_dtor_nogc (zend_variables.h:40)
==30704==    by 0xC7698E: ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_VAR_HANDLER (zend_vm_execute.h:45393)
==30704==    by 0xC0BCD0: execute_ex (zend_vm_execute.h:429)
==30704==    by 0xB83566: zend_call_function (zend_execute_API.c:837)
==30704==    by 0xBCB263: zend_call_method (zend_interfaces.c:102)
==30704==    by 0xBF21DE: zend_objects_destroy_object (zend_objects.c:156)
==30704==    by 0xBF98D7: zend_objects_store_del (zend_objects_API.c:160)
==30704==    by 0xB990F6: _zval_dtor_func (zend_variables.c:56)
==30704==    by 0xB98FD5: i_zval_ptr_dtor (zend_variables.h:48)
==30704==  Block was alloc'd at
==30704==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30704==    by 0xB5B8D8: _emalloc (zend_alloc.c:2402)
==30704==    by 0xC35E12: ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER (zend_vm_execute.h:16726)
==30704==    by 0xC0BCD0: execute_ex (zend_vm_execute.h:429)
==30704==    by 0xC0BED1: zend_execute (zend_vm_execute.h:474)
==30704==    by 0xB9E93B: zend_execute_scripts (zend.c:1447)
==30704==    by 0xAD63ED: php_execute_script (main.c:2537)
==30704==    by 0xC99E70: do_cli (php_cli.c:990)
==30704==    by 0xC9B318: main (php_cli.c:1378)
==30704== 
==30704== Invalid read of size 4
==30704==    at 0xC0107C: zval_delref_p (zend_types.h:834)
==30704==    by 0xC01717: i_zval_ptr_dtor (zend_variables.h:47)
==30704==    by 0xC03E88: zend_assign_to_variable_reference (zend_execute.c:579)
==30704==    by 0xC48C8B: ZEND_ASSIGN_REF_SPEC_VAR_CV_HANDLER (zend_vm_execute.h:24278)
==30704==    by 0xC0BCD0: execute_ex (zend_vm_execute.h:429)
==30704==    by 0xB83566: zend_call_function (zend_execute_API.c:837)
==30704==    by 0xBCB263: zend_call_method (zend_interfaces.c:102)
==30704==    by 0xBF21DE: zend_objects_destroy_object (zend_objects.c:156)
==30704==    by 0xBF98D7: zend_objects_store_del (zend_objects_API.c:160)
==30704==    by 0xB990F6: _zval_dtor_func (zend_variables.c:56)
==30704==    by 0xB98FD5: i_zval_ptr_dtor (zend_variables.h:48)
==30704==    by 0xB99130: _zval_dtor_func (zend_variables.c:69)
==30704==  Address 0x112b18b0 is 0 bytes inside a block of size 24 free'd
==30704==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30704==    by 0xB5BA53: _efree (zend_alloc.c:2417)
==30704==    by 0xB99153: _zval_dtor_func (zend_variables.c:70)
==30704==    by 0xC016E3: _zval_ptr_dtor_nogc (zend_variables.h:40)
==30704==    by 0xC7698E: ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_VAR_HANDLER (zend_vm_execute.h:45393)
==30704==    by 0xC0BCD0: execute_ex (zend_vm_execute.h:429)
==30704==    by 0xB83566: zend_call_function (zend_execute_API.c:837)
==30704==    by 0xBCB263: zend_call_method (zend_interfaces.c:102)
==30704==    by 0xBF21DE: zend_objects_destroy_object (zend_objects.c:156)
==30704==    by 0xBF98D7: zend_objects_store_del (zend_objects_API.c:160)
==30704==    by 0xB990F6: _zval_dtor_func (zend_variables.c:56)
==30704==    by 0xB98FD5: i_zval_ptr_dtor (zend_variables.h:48)
==30704==  Block was alloc'd at
==30704==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30704==    by 0xB5B8D8: _emalloc (zend_alloc.c:2402)
==30704==    by 0xC35E12: ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER (zend_vm_execute.h:16726)
==30704==    by 0xC0BCD0: execute_ex (zend_vm_execute.h:429)
==30704==    by 0xC0BED1: zend_execute (zend_vm_execute.h:474)
==30704==    by 0xB9E93B: zend_execute_scripts (zend.c:1447)
==30704==    by 0xAD63ED: php_execute_script (main.c:2537)
==30704==    by 0xC99E70: do_cli (php_cli.c:990)
==30704==    by 0xC9B318: main (php_cli.c:1378)
==30704== 
==30704== Invalid read of size 1
==30704==    at 0xC0165D: gc_check_possible_root (zend_gc.h:135)
==30704==    by 0xC01742: i_zval_ptr_dtor (zend_variables.h:50)
==30704==    by 0xC03E88: zend_assign_to_variable_reference (zend_execute.c:579)
==30704==    by 0xC48C8B: ZEND_ASSIGN_REF_SPEC_VAR_CV_HANDLER (zend_vm_execute.h:24278)
==30704==    by 0xC0BCD0: execute_ex (zend_vm_execute.h:429)
==30704==    by 0xB83566: zend_call_function (zend_execute_API.c:837)
==30704==    by 0xBCB263: zend_call_method (zend_interfaces.c:102)
==30704==    by 0xBF21DE: zend_objects_destroy_object (zend_objects.c:156)
==30704==    by 0xBF98D7: zend_objects_store_del (zend_objects_API.c:160)
==30704==    by 0xB990F6: _zval_dtor_func (zend_variables.c:56)
==30704==    by 0xB98FD5: i_zval_ptr_dtor (zend_variables.h:48)
==30704==    by 0xB99130: _zval_dtor_func (zend_variables.c:69)
==30704==  Address 0x112b18c1 is 17 bytes inside a block of size 24 free'd
==30704==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30704==    by 0xB5BA53: _efree (zend_alloc.c:2417)
==30704==    by 0xB99153: _zval_dtor_func (zend_variables.c:70)
==30704==    by 0xC016E3: _zval_ptr_dtor_nogc (zend_variables.h:40)
==30704==    by 0xC7698E: ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_VAR_HANDLER (zend_vm_execute.h:45393)
==30704==    by 0xC0BCD0: execute_ex (zend_vm_execute.h:429)
==30704==    by 0xB83566: zend_call_function (zend_execute_API.c:837)
==30704==    by 0xBCB263: zend_call_method (zend_interfaces.c:102)
==30704==    by 0xBF21DE: zend_objects_destroy_object (zend_objects.c:156)
==30704==    by 0xBF98D7: zend_objects_store_del (zend_objects_API.c:160)
==30704==    by 0xB990F6: _zval_dtor_func (zend_variables.c:56)
==30704==    by 0xB98FD5: i_zval_ptr_dtor (zend_variables.h:48)
==30704==  Block was alloc'd at
==30704==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30704==    by 0xB5B8D8: _emalloc (zend_alloc.c:2402)
==30704==    by 0xC35E12: ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER (zend_vm_execute.h:16726)
==30704==    by 0xC0BCD0: execute_ex (zend_vm_execute.h:429)
==30704==    by 0xC0BED1: zend_execute (zend_vm_execute.h:474)
==30704==    by 0xB9E93B: zend_execute_scripts (zend.c:1447)
==30704==    by 0xAD63ED: php_execute_script (main.c:2537)
==30704==    by 0xC99E70: do_cli (php_cli.c:990)
==30704==    by 0xC9B318: main (php_cli.c:1378)
==30704== 
==30704== Invalid read of size 8
==30704==    at 0xC0166F: gc_check_possible_root (zend_gc.h:135)
==30704==    by 0xC01742: i_zval_ptr_dtor (zend_variables.h:50)
==30704==    by 0xC03E88: zend_assign_to_variable_reference (zend_execute.c:579)
==30704==    by 0xC48C8B: ZEND_ASSIGN_REF_SPEC_VAR_CV_HANDLER (zend_vm_execute.h:24278)
==30704==    by 0xC0BCD0: execute_ex (zend_vm_execute.h:429)
==30704==    by 0xB83566: zend_call_function (zend_execute_API.c:837)
==30704==    by 0xBCB263: zend_call_method (zend_interfaces.c:102)
==30704==    by 0xBF21DE: zend_objects_destroy_object (zend_objects.c:156)
==30704==    by 0xBF98D7: zend_objects_store_del (zend_objects_API.c:160)
==30704==    by 0xB990F6: _zval_dtor_func (zend_variables.c:56)
==30704==    by 0xB98FD5: i_zval_ptr_dtor (zend_variables.h:48)
==30704==    by 0xB99130: _zval_dtor_func (zend_variables.c:69)
==30704==  Address 0x112b18b8 is 8 bytes inside a block of size 24 free'd
==30704==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30704==    by 0xB5BA53: _efree (zend_alloc.c:2417)
==30704==    by 0xB99153: _zval_dtor_func (zend_variables.c:70)
==30704==    by 0xC016E3: _zval_ptr_dtor_nogc (zend_variables.h:40)
==30704==    by 0xC7698E: ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_VAR_HANDLER (zend_vm_execute.h:45393)
==30704==    by 0xC0BCD0: execute_ex (zend_vm_execute.h:429)
==30704==    by 0xB83566: zend_call_function (zend_execute_API.c:837)
==30704==    by 0xBCB263: zend_call_method (zend_interfaces.c:102)
==30704==    by 0xBF21DE: zend_objects_destroy_object (zend_objects.c:156)
==30704==    by 0xBF98D7: zend_objects_store_del (zend_objects_API.c:160)
==30704==    by 0xB990F6: _zval_dtor_func (zend_variables.c:56)
==30704==    by 0xB98FD5: i_zval_ptr_dtor (zend_variables.h:48)
==30704==  Block was alloc'd at
==30704==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30704==    by 0xB5B8D8: _emalloc (zend_alloc.c:2402)
==30704==    by 0xC35E12: ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER (zend_vm_execute.h:16726)
==30704==    by 0xC0BCD0: execute_ex (zend_vm_execute.h:429)
==30704==    by 0xC0BED1: zend_execute (zend_vm_execute.h:474)
==30704==    by 0xB9E93B: zend_execute_scripts (zend.c:1447)
==30704==    by 0xAD63ED: php_execute_script (main.c:2537)
==30704==    by 0xC99E70: do_cli (php_cli.c:990)
==30704==    by 0xC9B318: main (php_cli.c:1378)
==30704== 
--------- (19.6.2) > ✔ /wp-includes/wp-db.php:623
==30704== Invalid free() / delete / delete[] / realloc()
==30704==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30704==    by 0xB5BA53: _efree (zend_alloc.c:2417)
==30704==    by 0xB99153: _zval_dtor_func (zend_variables.c:70)
==30704==    by 0xC01734: i_zval_ptr_dtor (zend_variables.h:48)
==30704==    by 0xC03E88: zend_assign_to_variable_reference (zend_execute.c:579)
==30704==    by 0xC40167: ZEND_ASSIGN_REF_SPEC_VAR_VAR_HANDLER (zend_vm_execute.h:20438)
==30704==    by 0xC0BCD0: execute_ex (zend_vm_execute.h:429)
==30704==    by 0xC0BED1: zend_execute (zend_vm_execute.h:474)
==30704==    by 0xB9E93B: zend_execute_scripts (zend.c:1447)
==30704==    by 0xAD63ED: php_execute_script (main.c:2537)
==30704==    by 0xC99E70: do_cli (php_cli.c:990)
==30704==    by 0xC9B318: main (php_cli.c:1378)
==30704==  Address 0x112b18b0 is 0 bytes inside a block of size 24 free'd
==30704==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30704==    by 0xB5BA53: _efree (zend_alloc.c:2417)
==30704==    by 0xB99153: _zval_dtor_func (zend_variables.c:70)
==30704==    by 0xC016E3: _zval_ptr_dtor_nogc (zend_variables.h:40)
==30704==    by 0xC7698E: ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_VAR_HANDLER (zend_vm_execute.h:45393)
==30704==    by 0xC0BCD0: execute_ex (zend_vm_execute.h:429)
==30704==    by 0xB83566: zend_call_function (zend_execute_API.c:837)
==30704==    by 0xBCB263: zend_call_method (zend_interfaces.c:102)
==30704==    by 0xBF21DE: zend_objects_destroy_object (zend_objects.c:156)
==30704==    by 0xBF98D7: zend_objects_store_del (zend_objects_API.c:160)
==30704==    by 0xB990F6: _zval_dtor_func (zend_variables.c:56)
==30704==    by 0xB98FD5: i_zval_ptr_dtor (zend_variables.h:48)
==30704==  Block was alloc'd at
==30704==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==30704==    by 0xB5B8D8: _emalloc (zend_alloc.c:2402)
==30704==    by 0xC35E12: ZEND_FE_FETCH_RW_SPEC_VAR_HANDLER (zend_vm_execute.h:16726)
==30704==    by 0xC0BCD0: execute_ex (zend_vm_execute.h:429)
==30704==    by 0xC0BED1: zend_execute (zend_vm_execute.h:474)
==30704==    by 0xB9E93B: zend_execute_scripts (zend.c:1447)
==30704==    by 0xAD63ED: php_execute_script (main.c:2537)
==30704==    by 0xC99E70: do_cli (php_cli.c:990)
==30704==    by 0xC9B318: main (php_cli.c:1378)
==30704==
 [2016-08-16 15:45 UTC] php at abiusx dot com
Thanks for taking the time to run it.
If you add the diehard mode (--diehard) more segfaults appear (assuming you resolve the last one).
Can you use the emulation trace to confirm that the crash is happening in wpdb destructor?
 [2016-08-16 16:14 UTC] nikic@php.net
Yes. The valgrind warnings happen right after

----- (19.6) > ✔ Running wpdb::__destruct()...
--------- (19.6.1) > ✔ Found direct method wpdb::__destruct()...
--------------- (19.6.1.1.1) > ✔ Setting class to 'wpdb' and self to 'wpdb'...

And the top of zbacktrace at the time of the warning is:

[0x1019cc30] Emulator->context_apply(reference) /home/nikic/php-analyzer/php-emul/emulator-functions.php:116 
[0x1019cb30] Emulator->context_switch(object[0x1019cb80]) /home/nikic/php-analyzer/php-emul/emulator-functions.php:122 
[0x1019c7c0] Emulator->run_function(object[0x1019c810], array(0)[0x1019c820], object[0x1019c830], array(4)[0x1019c840]) /home/nikic/php-analyzer/php-emul/emulator-functions.php:158 
[0x1019c0b0] OOEmulator->run_user_static_method("wpdb", "__destruct", array(0)[0x1019c120], reference) /home/nikic/php-analyzer/php-emul/oo-methods.php:283 
[0x1019bf90] OOEmulator->run_user_method(reference, "__destruct", array(0)[0x1019c000], "wpdb") /home/nikic/php-analyzer/php-emul/oo-methods.php:392 
[0x1019be70] OOEmulator->run_method(reference, "__destruct") /home/nikic/php-analyzer/php-emul/oo-methods.php:368 
[0x1019bd20] EmulatorObject->__destruct() /home/nikic/php-analyzer/php-emul/oo.php:73 

The context_apply() method is

    private function context_apply(EmulatorExecutionContext $context)
    {
        $bu_context=new EmulatorExecutionContext;
        foreach ($context as $k=>&$v)
            if (property_exists($context, $k))
            {
                $bu_context->{$k}=$this->{"current_{$k}"};
                $this->{"current_{$k}"}=&$v;
            }
        return $bu_context;
    }

Given that we have a free in ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_VAR_HANDLER followed by a warning in ZEND_ASSIGN_REF_SPEC_VAR_CV_HANDLER, it is likely that $bu_context->{$k}=$this->{"current_{$k}"} causes the free of $this->{"current_{$k}"}, which $this->{"current_{$k}"}=&$v still tries to use (or at least destroy again).

$this->{"current_{$k}"} at the time of the valgrind warning is

    [0x10877838] (refcount=0) reference: [0x11fa1f98] (refcount=7) object(EmulatorObject) #23128
 [2016-08-16 16:18 UTC] php at abiusx dot com
Interesting, though the last time I had the error the apply_context (and context-related functionality) did not exist.

The happens when a descructor of a deep copied object is called from another destructor.

The emulator uses __destructor on EmulatorObject, which is called by PHP when the object is no longer used, to relay the destructor call to emulator and respective object. A lot of code happens under the EmulatorObject::__destructor and AFAIK PHP has a sensitive context inside destructors (many previous bugs?).

Refcount is 0 there, but I doubt that the cause is there...
 [2016-08-16 18:09 UTC] nikic@php.net
Reproduce script for at least one issue:

<?php

function get() {
    $t = new stdClass;
    $t->prop = $t;
    return $t;
}

$i = 42;
get($t)->prop =& $i;

The problem here is that get($t)->prop =& $i destroys the stdClass object, but that is also the object to which the assignment happens, so we end up writing a destroyed object.

This can be avoided by using an intermediate garbage zval in assign_to_reference. Doing so also fixes the segfault (I only see the one, with and without --diehard) on your test case.
 [2016-08-16 18:35 UTC] php at abiusx dot com
It sounds reasonable. All segfaults might be due to the same bug. To cause the other segfaults, please comment out wpdb destruct method entirely and rerun, but I highly suspect they are all of the same type. I faced a few and they behaved very similarly.
 [2016-08-16 18:37 UTC] php at abiusx dot com
Your sample code is not segfaulting for me. Plus, it has a NOTICE.
 [2016-08-16 19:07 UTC] nikic@php.net
Automatic comment on behalf of nikic
Revision: http://git.php.net/?p=php-src.git;a=commit;h=e2230c17d3e17981c739cb858bc78d47d2365836
Log: Fix bug #72854
 [2016-08-16 19:07 UTC] nikic@php.net
-Status: Open +Status: Closed
 [2016-08-16 19:08 UTC] nikic@php.net
Automatic comment on behalf of nikic
Revision: http://git.php.net/?p=php-src.git;a=commit;h=e2230c17d3e17981c739cb858bc78d47d2365836
Log: Fix bug #72854
 [2016-08-16 19:14 UTC] nikic@php.net
-Assigned To: +Assigned To: nikic
 [2016-08-16 19:14 UTC] nikic@php.net
Yes, the example does not segfault, but the use-after-free is visible in valgrind (and a leak message in debug builds).

This resolves the segfault for me, but it may well be that you are seeing additional/different issues. For example, I do not get a segfault on 5.6, while you mention that the problem exists on PHP 5 as well.
 [2016-10-17 10:09 UTC] bwoebi@php.net
Automatic comment on behalf of nikic
Revision: http://git.php.net/?p=php-src.git;a=commit;h=e2230c17d3e17981c739cb858bc78d47d2365836
Log: Fix bug #72854
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Oct 12 23:01:27 2024 UTC