Bug #72854 [Opn->Csd]: PHP Crashes on duplicate destructor call
| From: | nikic@php.net | Date: | Tue, 16 Aug 2016 19:07:00 +0000 |
| Subject: | Bug #72854 [Opn->Csd]: PHP Crashes on duplicate destructor call | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-203327@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=72854&edit=1
ID: 72854
Updated by: nikic@php.net
Reported by: php at abiusx dot com
Summary: PHP Crashes on duplicate destructor call
-Status: Open
+Status: Closed
Type: Bug
Package: Class/Object related
Operating System: Mac OS X, Linux
PHP Version: 7.0.9
Block user comment: N
Private report: N
New Comment:
Automatic comment on behalf of nikic
Revision: http://git.php.net/?p=php-src.git;a=commit;h=e2230c17d3e17981c739cb858bc78d47d2365836
Log: Fix bug #72854
Previous Comments:
------------------------------------------------------------------------
[2016-08-16 18:37:16] php at abiusx dot com
Your sample code is not segfaulting for me. Plus, it has a NOTICE.
------------------------------------------------------------------------
[2016-08-16 18:35:53] 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:09:22] 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 16:18:02] 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 16:14:52] 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
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=72854
--
Edit this bug report at https://bugs.php.net/bug.php?id=72854&edit=1