php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #64896 Segfault with gc_collect_cycles using unserialize on certain objects
Submitted: 2013-05-22 08:05 UTC Modified: 2017-01-01 12:50 UTC
Votes:3
Avg. Score:3.3 ± 0.9
Reproduced:3 of 3 (100.0%)
Same Version:0 (0.0%)
Same OS:2 (66.7%)
From: mark dot chong at acquireap dot com Assigned: laruence (profile)
Status: Closed Package: Reproducible crash
PHP Version: 5.4.15 OS: ubuntu
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: mark dot chong at acquireap dot com
New email:
PHP Version: OS:

 

 [2013-05-22 08:05 UTC] mark dot chong at acquireap dot com
Description:
------------
There are a few open bugs this may duplicate, but I have a reproducible case 
under very specific circumstances:

Having an object that has
 a. circular reference
 b. changes global variable on destructor

If this object is unserialize()'d then gc_collect_cycles will cause a segfault

Test script:
---------------
<?php
class bad
{
	private $_private = array();

	public function __construct()
	{
		$this->_private[] = 'oh noes';
	}

	public function __destruct()
	{
		//echo "bad::destructor\n";

		global $bar;
		$bar = $this->_private;
	}
}

$foo = new stdclass;
$foo->foo = $foo;
$foo->bad = new bad;
print_r($foo);

gc_disable();

for ($i=0; true; $i++)
{
	$deep_clone = unserialize(serialize($foo));
	gc_collect_cycles();
	var_dump($i);
}

Expected result:
----------------
Script should run indefinitely.

Actual result:
--------------
int(0)
int(1)
Segmentation fault (core dumped)

Patches

bug64896.phpt (last revision 2013-08-30 10:09 UTC by arjen at react dot com)

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2013-05-22 08:34 UTC] laruence@php.net
-Status: Open +Status: Feedback
 [2013-05-22 08:34 UTC] laruence@php.net
Thank you for this bug report. To properly diagnose the problem, we
need a backtrace to see what is happening behind the scenes. To
find out how to generate a backtrace, please read
http://bugs.php.net/bugs-generating-backtrace.php for *NIX and
http://bugs.php.net/bugs-generating-backtrace-win32.php for Win32

Once you have generated a backtrace, please submit it to this bug
report and change the status back to "Open". Thank you for helping
us make PHP better.

I have got it run till ouputs "1315828", no segfault occurred,

please show us the backtrace you get, will be helpful

thanks
 [2013-05-22 08:42 UTC] mark dot chong at acquireap dot com
I have run the test case on 3 different machines which call caused a segfault, 
bellow is the bt from one of them

#0  _zend_mm_free_int (heap=0xe09290, p=0x7ffff7e793a8) at /tmp/buildd/php5-
5.4.15/Zend/zend_alloc.c:2100
#1  0x000000000068d97a in _zval_dtor (zvalue=<optimised out>) at 
/tmp/buildd/php5-5.4.15/Zend/zend_variables.h:35
#2  _zval_ptr_dtor (zval_ptr=0x7ffff7e779a0) at /tmp/buildd/php5-
5.4.15/Zend/zend_execute_API.c:438
#3  _zval_ptr_dtor (zval_ptr=0x7ffff7e779a0) at /tmp/buildd/php5-
5.4.15/Zend/zend_execute_API.c:427
#4  0x00000000006aab38 in zend_hash_destroy (ht=0x7ffff7e778e0) at 
/tmp/buildd/php5-5.4.15/Zend/zend_hash.c:560
#5  0x000000000069b8fb in _zval_dtor_func (zvalue=0x7fffffffa5a0) at 
/tmp/buildd/php5-5.4.15/Zend/zend_variables.c:45
#6  0x0000000000718e7d in zend_assign_to_variable (value=0x7ffff7e776d8, 
variable_ptr_ptr=0x7ffff7e40410) at /tmp/buildd/php5-
5.4.15/Zend/zend_execute.c:937
#7  ZEND_ASSIGN_SPEC_CV_VAR_HANDLER (execute_data=0x7ffff7e40378) at 
/tmp/buildd/php5-5.4.15/Zend/zend_vm_execute.h:33084
#8  0x00000000006feaa7 in execute (op_array=0x7ffff7e76af0) at /tmp/buildd/php5-
5.4.15/Zend/zend_vm_execute.h:410
#9  0x00007ffff400fa81 in xdebug_execute (op_array=0x7ffff7e76af0) at 
/srv/debian_developer/xdebug/xdebug-2.2.1/build-php5/xdebug.c:1391
#10 0x000000000068f7e0 in zend_call_function (fci=fci@entry=0x7fffffffa970, 
fci_cache=0x7ffff7e73bb0, fci_cache@entry=0x7fffffffa940)
    at /tmp/buildd/php5-5.4.15/Zend/zend_execute_API.c:958
#11 0x00000000006b4115 in zend_call_method 
(object_pp=object_pp@entry=0x7fffffffaa28, obj_ce=<optimised out>, 
fn_proxy=fn_proxy@entry=0x7fffffffaa20, 
    function_name=function_name@entry=0xaa42a0 "__destruct", 
function_name_len=function_name_len@entry=10, 
retval_ptr_ptr=retval_ptr_ptr@entry=0x0, 
    param_count=param_count@entry=0, arg1=arg1@entry=0x0, arg2=arg2@entry=0x0) 
at /tmp/buildd/php5-5.4.15/Zend/zend_interfaces.c:97
#12 0x00000000006bdfa2 in zend_objects_destroy_object (object=0x7ffff7e775b0, 
handle=<optimised out>) at /tmp/buildd/php5-5.4.15/Zend/zend_objects.c:123
#13 0x00000000006bbdf9 in gc_collect_cycles () at /tmp/buildd/php5-
5.4.15/Zend/zend_gc.c:816
#14 0x00000000006ad719 in zif_gc_collect_cycles (ht=<optimised out>, 
return_value=0x7ffff7e75f48, return_value_ptr=<optimised out>, this_ptr=
<optimised out>, 
    return_value_used=<optimised out>) at /tmp/buildd/php5-
5.4.15/Zend/zend_builtin_functions.c:361
#15 0x00007ffff400fedc in xdebug_execute_internal 
(current_execute_data=0x7ffff7e40060, return_value_used=0)
    at /srv/debian_developer/xdebug/xdebug-2.2.1/build-php5/xdebug.c:1483
#16 0x0000000000744d49 in zend_do_fcall_common_helper_SPEC 
(execute_data=0x7ffff7e40060) at /tmp/buildd/php5-
5.4.15/Zend/zend_vm_execute.h:645
#17 0x00000000006feaa7 in execute (op_array=0x7ffff7e73bb0) at /tmp/buildd/php5-
5.4.15/Zend/zend_vm_execute.h:410
#18 0x00007ffff400fa81 in xdebug_execute (op_array=0x7ffff7e73bb0) at 
/srv/debian_developer/xdebug/xdebug-2.2.1/build-php5/xdebug.c:1391
#19 0x000000000069e0dc in zend_execute_scripts (type=type@entry=8, 
retval=retval@entry=0x0, file_count=file_count@entry=3) at /tmp/buildd/php5-
5.4.15/Zend/zend.c:1315
#20 0x000000000063e433 in php_execute_script 
(primary_file=primary_file@entry=0x7fffffffd170) at /tmp/buildd/php5-
5.4.15/main/main.c:2492
#21 0x0000000000747913 in do_cli (argc=2, argv=0x7fffffffe608) at 
/tmp/buildd/php5-5.4.15/sapi/cli/php_cli.c:988
#22 0x000000000042ceaa in main (argc=2, argv=0x7fffffffe608) at 
/tmp/buildd/php5-5.4.15/sapi/cli/php_cli.c:1364
 [2013-05-22 08:42 UTC] mark dot chong at acquireap dot com
-Status: Feedback +Status: Open
 [2013-05-24 01:21 UTC] edward dot savage at dodo dot com
With the given test case I get the segfault as described (Ubuntu 13.04/PHP 5.4.9-4ubuntu2).  I found that I could work around it by adding a function like 'usleep(1);' or '$var = 2;' between global and the $bar operation in the destructor.  A simple operation like '6^123;', even repeated at length, wasn't enough to avoid the fault.  

Once the test case was running without crashing I started looking at the array assignment to $bar.  I found that printing the result of $bar after the destructor ran showed that the values of $this->_private were lost from the global $bar.  Even more information is lost when gc_collect_cycles is executed.  It can be shown to only be the values as an assigned multidimensional array will retain its keys.  

This loss of data and the segfault can be avoided by moving the $bar assignment into a pseudo destructor or by removing the circular reference.  However, for the reported case there is definitely a data integrity issue when assigning an array to a global in a __destruct with a circular reference present.  I could not repeat this issue with other types of assignment like string and object.
 [2013-05-24 13:23 UTC] laruence@php.net
please disable xdebug then try again
 [2013-05-30 21:17 UTC] sjon at hortensius dot net
@laruence I can reproduce this easily, see http://3v4l.org/Z9Bg7#v545 every 
version of PHP since 5.4.5 segfaults on the script (without xdebug)

here is your backtrace without xdebug:

#0  0x0000000000608737 in ?? ()
#1  0x000000000061f349 in _zval_ptr_dtor ()
#2  0x000000000063b8d8 in zend_hash_destroy ()
#3  0x000000000062d37b in _zval_dtor_func ()
#4  0x000000000069e31d in ?? ()
#5  0x000000000065508f in execute ()
#6  0x0000000000621190 in zend_call_function ()
#7  0x0000000000644e55 in zend_call_method ()
#8  0x000000000064eab2 in zend_objects_destroy_object ()
#9  0x000000000064c9a8 in gc_collect_cycles ()
#10 0x000000000063e699 in ?? ()
#11 0x00000000006d6d6c in ?? ()
#12 0x000000000065508f in execute ()
#13 0x000000000062fb94 in zend_execute_scripts ()
#14 0x00000000005d1afc in php_execute_script ()
#15 0x00000000006d8d1f in ?? ()
#16 0x000000000042615d in ?? ()
#17 0x00007ffff690fa15 in __libc_start_main () from /usr/lib/libc.so.6
#18 0x00000000004261f9 in _start ()

With a debug-build; this problem seems unreproducable
 [2013-06-05 11:18 UTC] arjen at react dot com
I can confirm the segfault using PHP-5.4.15 build from php.net sources.

Backtrace is same as above @ https://gist.github.com/anonymous/5713123
Valgrind trace @ https://gist.github.com/anonymous/5713183
 [2013-06-05 13:32 UTC] laruence@php.net
Ha, I can reproduce this with non-debug build now. thanks
 [2013-06-11 21:56 UTC] webm4st0r at gmail dot com
I believe I am hitting a similar issue to this through running some test suites. 
I've not yet been able to get a smaller script to reproduce the problem, though 
the one in this issue does fail to run.

I have tested this on 5.4.16 on 64bit CentOS 6. I would be interested in testing 
a patch for this to determine if it truly is the same problem, as the crash I'm 
seeing in the test run is during php_request_shutdown, sometimes within a 
gc_collect_cycles, sometimes within a destroy_zend_class.

I am unable to reproduce these failures with zend.enable_gc = 0, or in a debug 
build.

I can provide some stack traces for both failures I've seen if that would be 
useful in looking into this.
 [2013-08-30 10:10 UTC] arjen at react dot com
Still crashes 5.4-git, testscript attached.
 [2013-08-30 11:15 UTC] laruence@php.net
-Assigned To: +Assigned To: laruence
 [2013-11-21 10:28 UTC] arjen at react dot com
A test was added with reason "We can not fix this bug without a significant (performace slow down) change to gc" in https://github.com/php/php-src/blob/PHP-5.5/Zend/tests/bug64896.phpt

Just wanted to document this in this relevant issue..
 [2013-12-18 09:59 UTC] teppo-dev at sulate dot net
Just wanted to mention (if it's still not obvious) that this bug has nothing to do with serialize/unserialize, but only with gc_collect_cycles. (Maybe the bug title should be refined?)

(Creating identical clones "manually" without unserialize triggers the bug the same.)
 [2017-01-01 12:50 UTC] nikic@php.net
-Status: Assigned +Status: Closed
 [2017-01-01 12:50 UTC] nikic@php.net
I'm closing this bug since it has been fixed in PHP 7.0 and PHP 5.6 is going out of active support.
 
PHP Copyright © 2001-2022 The PHP Group
All rights reserved.
Last updated: Sun May 29 00:05:44 2022 UTC