Bug #72854 [Opn]: PHP Crashes on duplicate destructor call

From: Date: Tue, 16 Aug 2016 18:37:16 +0000
Subject: Bug #72854 [Opn]: PHP Crashes on duplicate destructor call
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-203324@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 User updated by: php at abiusx dot com Reported by: php at abiusx dot com Summary: PHP Crashes on duplicate destructor call Status: Open 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: Your sample code is not segfaulting for me. Plus, it has a NOTICE. Previous Comments: ------------------------------------------------------------------------ [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 ------------------------------------------------------------------------ [2016-08-16 15:45:01] 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? ------------------------------------------------------------------------ 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

« previous php.bugs (#203324) next »