php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #39346 Unsetting a static variable inside a destructor causes segfault later on
Submitted: 2006-11-02 16:54 UTC Modified: 2008-01-11 08:44 UTC
Votes:1
Avg. Score:4.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:0 (0.0%)
From: daan at parse dot nl Assigned: dmitry
Status: Closed Package: Reproducible crash
PHP Version: 5.2.0RC5 OS: Slackware 10.2
Private report: No CVE-ID:
 [2006-11-02 16:54 UTC] daan at parse dot nl
Description:
------------
Tested on 5.2.0RC6

Unsetting a static variable referring to the object itself causes a segfault later on. (possible alloc problems)

I was able to reproduce segfaults in this situation with other functions besides debug_backtrace(), for instance with mysqli_fetch_assoc(). The resulting backtrace also led to  _zend_mm_alloc_int. (I am presuming it is the same bug)

PS. The print_r() is not required to trigger the crash.

Reproduce code:
---------------
<?php
class test
{
	protected $_id;
	static $instances;
	
	public function __construct($id)
	{
		$this->test();
			
		$this->_id = $id;
		
		self::$instances[$this->_id] = $this;
	}
	
	function __destruct()
	{
		unset(self::$instances[$this->_id]);
	}
	
	function test()
	{
		print_r(debug_backtrace());	
	}
	
}
	
	$test = new test(2);
	
	$test = new test(1);
	
	$test = new test(2);

	$test = new test(3);
?>

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

Actual result:
--------------
#0  _zend_mm_alloc_int (heap=0x80ebbb8, size=16) at /usr/src/php-5.2.0RC6/Zend/zend_alloc.c:1090 
#1  0x4063f953 in add_assoc_long_ex (arg=0x3, key=0x40769a60 "line", key_len=5, n=16) at /usr/src/php-5.2.0RC6/Zend/zend_API.c:977 
#2  0x4064d2d8 in zend_fetch_debug_backtrace (return_value=0x40f289cc, skip_last=1, provide_object=1) 
    at /usr/src/php-5.2.0RC6/Zend/zend_builtin_functions.c:1962 
#3  0x40658d54 in zend_do_fcall_common_helper_SPEC (execute_data=0xbfffacc0) at /usr/src/php-5.2.0RC6/Zend/zend_vm_execute.h:200 
#4  0x40658489 in execute (op_array=0x40f282c8) at /usr/src/php-5.2.0RC6/Zend/zend_vm_execute.h:92 
#5  0x40658709 in zend_do_fcall_common_helper_SPEC (execute_data=0xbfffae80) at /usr/src/php-5.2.0RC6/Zend/zend_vm_execute.h:234 
#6  0x40658489 in execute (op_array=0x40f28fd4) at /usr/src/php-5.2.0RC6/Zend/zend_vm_execute.h:92 
#7  0x40658709 in zend_do_fcall_common_helper_SPEC (execute_data=0xbfffb0e0) at /usr/src/php-5.2.0RC6/Zend/zend_vm_execute.h:234 
#8  0x40658489 in execute (op_array=0x40f24194) at /usr/src/php-5.2.0RC6/Zend/zend_vm_execute.h:92 
#9  0x4063ebfc in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /usr/src/php-5.2.0RC6/Zend/zend.c:1097 
#10 0x40604e2a in php_execute_script (primary_file=0xbfffd440) at /usr/src/php-5.2.0RC6/main/main.c:1758 
#11 0x406bf882 in apache_php_module_main (r=0x80cb5bc, display_source_mode=0) at /usr/src/php-5.2.0RC6/sapi/apache/sapi_apache.c:53 
#12 0x406c0296 in send_php (r=0x80cb5bc, display_source_mode=0, filename=0x0) at /usr/src/php-5.2.0RC6/sapi/apache/mod_php5.c:660 
#13 0x406c04a6 in send_parsed_php (r=0x80cb5bc) at /usr/src/php-5.2.0RC6/sapi/apache/mod_php5.c:675 
#14 0x08053ff7 in ap_invoke_handler () 
#15 0x08069039 in process_request_internal () 
#16 0x08069098 in ap_process_request () 
#17 0x080600ba in child_main () 
#18 0x08060262 in make_child () 
#19 0x080603c8 in startup_children () 
#20 0x08060a88 in standalone_main () 
#21 0x080612a6 in main () 

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2006-11-06 15:36 UTC] daan at parse dot nl
Also crashing on 5.2.0 final.
 [2006-11-08 17:06 UTC] dmitry@php.net
I don't know how to fix this.

BTW I don't understand what do you like to do with this code. Note that object is not destroied while someone is refering it, so if you put it into self::$instances[] it never be destroied. The test::__destruct() can only be called from test::__construct() then you update self::$instances[$this->_id]. And this makes double free() and crash.
 [2006-11-08 17:28 UTC] daan at parse dot nl
Ah I was tinkering with an instances static array, which first held only the $this->_id, but then I changed it into $this (which is indeed a bit strange, I figured that out too later) - but the crash still was a crash and not some error, so hence the bugreport.
 [2006-12-20 10:33 UTC] duncanh at icritical dot com
OS: CentOS 4.4
Apache: httpd-2.0.52-28.ent.centos4
PHP: PHP 5.2.0 (cli) (built: Dec 13 2006 10:13:00)

I'm seeing similar segfaults in the same area (0x0122081d 
in _zend_mm_alloc_int (heap=0x8494f90, size=32) 
at /root/Files/php-5.2.0/Zend/zend_alloc.c:1076), but I'm 
not using destructors at all.

function Tenant($clientid) {
 doDebug(6, __METHOD__."($clientid)");
 doDebug(6, __METHOD__);
}

Logs show Tenant::Tenant(), and Tenant::Tenant.  The 
apache child then falls over in a heap.  I can only assume 
that somewhere in my includes, a bit of code is doing 
something that the Zend code can't handle.  I've trawled 
through my code changes since this last worked, and 
nothing obvious is showing up.  I'm now working on 
reducing my code to bare-bones, and building it back up 
until the segfaults occur again.
 [2006-12-20 10:42 UTC] daan at parse dot nl
@ duncanh at icritical dot com:

That's probably an unrelated bug, which also results in a memory related segfault.

The best thing to do is to report it as a new bug, and perhaps reference to this bug in your description.
(and of course see if you can narrow it down to single piece of code)
 [2006-12-20 11:39 UTC] duncanh at icritical dot com
@ daan at parse dot nl

You were correct.  I managed to write an infinite loop.  
Sorry for the noise.
 [2006-12-21 06:37 UTC] judas dot iscariote at gmail dot com
this leaks memory on current 5_2 CVS but does not crash..

zend_vm_execute.h(405) :  Freeing 0x2B8735197300 (24 bytes), script=crash.php
=== Total 1 memory leaks detected ===
 [2007-11-08 12:20 UTC] dmitry@php.net
The bug seems to be unfixable.
In __construct() the operator self::$instances[$this->_id] = $this; executes the following sequence:

1) fetch address of self::$instances[$this->_id]
2) destroys old value
3) assigns new value into the address fetched on step (1)

but during step (2) __destruct() is called and it calls unset(self::$instances[$this->_id])
as the result, the address fetched on step (1) became invalid on step (3)

 [2008-01-11 08:44 UTC] dmitry@php.net
Fixed in CVS HEAD and PHP_5_3.

Now the assignment operator calls destructor for left value after the actual assignment.
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Fri Apr 18 13:02:15 2014 UTC