php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #43175 __destruct() throwing an exception with __call() causes segfault
Submitted: 2007-11-01 15:27 UTC Modified: 2007-11-09 09:16 UTC
Votes:1
Avg. Score:4.0 ± 0.0
Reproduced:0 of 0 (0.0%)
From: development at domain51 dot com Assigned: dmitry (profile)
Status: Closed Package: Scripting Engine problem
PHP Version: 5CVS,6CVS (2007-11-01) OS: *
Private report: No CVE-ID: None
 [2007-11-01 15:27 UTC] development at domain51 dot com
Description:
------------
If __destruct() throws an exception on an object that was not assigned to a variable, but had __call() invoked, it will segfault

Reproduce code:
---------------
Full test case available at:
http://plumb.domain51.com/sandbox/__destruct-bug/bug.phpt
http://plumb.domain51.com/sandbox/__destruct-bug/bug.phps (syntax highlighted)

Simplified sample:
foobar::factory()>unknown();
foobar()->unknown(); // where foobar is a function wrapping new foobar

Expected result:
----------------
Exception to be thrown in foobar::__destruct()

Actual result:
--------------
Segfault on Linux
Bus error on Mac OSX

I'll get a backtrace added later as time allows

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2007-11-01 17:17 UTC] jani@php.net
I noticed you try to throw in destructor and that's not supposed to work. See page: http://docs.php.net/manual/en/language.oop5.decon.php

"Note: Attempting to throw an exception from a destructor (called in the time of script termination) causes a fatal error. "

Of course it shouldn't cause any crash though. :)

 [2007-11-01 17:26 UTC] jani@php.net
Simplest script to reproduce:

<?php

class foobar {
    public function __destruct() {
        throw new Exception();
    }
    public function __call($m, $a) {
        return $this;
    }
    public static function factory() {
        return new foobar();
    }
}
function foobar() {
    return new foobar();
}
try {
    foobar::factory()->unknown();
} catch (Exception $e) {
    echo "__call via traditional factory should be caught\n";
}
?>

Program received signal SIGSEGV, Segmentation fault.
0x082fe66d in add_assoc_string_ex (arg=0x95f0484, key=0x85d8db2 "function", key_len=9, str=0x7 <Address 0x7 out of bounds>, duplicate=1)
    at /home/jani/src/php-5.3/Zend/zend_API.c:1147
1147            ZVAL_STRING(tmp, str, duplicate);
(gdb) bt
#0  0x082fe66d in add_assoc_string_ex (arg=0x95f0484, key=0x85d8db2 "function", key_len=9, str=0x7 <Address 0x7 out of bounds>, duplicate=1)
    at /home/jani/src/php-5.3/Zend/zend_API.c:1147
#1  0x08310cb1 in zend_fetch_debug_backtrace (return_value=0x95f21a4, skip_last=-1, provide_object=0)
    at /home/jani/src/php-5.3/Zend/zend_builtin_functions.c:2026
.
.

 [2007-11-01 17:53 UTC] development at domain51 dot com
Throwing it sure, but the entire try catch syntax gets wrapped up in 
it too.  In the example I blogged about, __destruct() actually wants 
to catch any exceptions so it can create meaningful output based on 
the Exceptions that were generated.  In that case, __destruct() would 
have returned peacefully.

The documentation you pointed to actually has a phrase that would lead 
someone to believe that the only time throwing an exception within a 
__destruct() will cause a fatal error is if that exception is thrown 
as part of the script shutdown.  The presence of the text in 
parentheses makes it appear that only a destructor called as part of 
garbage collection at the end of the script would cause this issue.  
The portions of the linked to PHPT test above agree with that.

At any rate, my take on that would be that would still be that if 
__destruct() is finished and an exception is still present, then 
there's an error.  Otherwise, how would you handle things such as 
PDOExceptions thrown during DB clean-up?
 [2007-11-09 09:16 UTC] dmitry@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.


 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Mar 19 13:01:29 2024 UTC