php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #76502 Chain of mixed exceptions and errors does not serialize properly
Submitted: 2018-06-20 07:52 UTC Modified: 2018-06-20 08:57 UTC
Votes:1
Avg. Score:4.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: benjamin dot zikarsky at jaumo dot com Assigned:
Status: Closed Package: *General Issues
PHP Version: 7.2.6 OS: Linux 4.16
Private report: No CVE-ID: None
 [2018-06-20 07:52 UTC] benjamin dot zikarsky at jaumo dot com
Description:
------------
In some error-cases we try to send serialized exceptions from our background worker infrastructure to our webservers, where those get deserialized and rethrown.

This usually works fine but recently we came around strange, cut-off exception-chains. When we debugged the problem, we realized that if an Error gets thrown, and later is wrapped into an Exception, this Error is lost in the serialization/deserialization process. Further analysis showed that while the error/exception chain gets serialized properly, the `__wakeup` implementation replaces Error-objects in Exception-objects with NULL and vice-versa.

See:
https://github.com/php/php-src/blob/d04917c7b361fd07e098fe29ae931fb6fac1d9e0/Zend/zend_exceptions.c#L327-L331
https://github.com/php/php-src/blob/d04917c7b361fd07e098fe29ae931fb6fac1d9e0/Zend/zend_exceptions.c#L63-L66

While an Error wrapping an Exception may be uncommon, the Error wrapped in an Exception is a common pattern in our codebase. With $previous being defined as Throwable, the problem is unexpected.

Proposition: Replace `instanceof_function(Z_OBJCE_P(pvalue), i_get_exception_base(object)` with `instanceof_function(Z_OBJCE_P(pvalue), THROWABLE`. my understanding of php-src is not good enough to fix this, but THROWABLE should be replaced with a reference to the Throwable interface.

Test script:
---------------
<?php

$examples = [
    "Exception(Exception())" => new Exception("outer", 0,  new Exception("inner")),
    "Error(Error())"         => new Error("outer", 0, new Error("inner")),
    "Error(Exception())"     => new Error("outer", 0, new Exception("inner")),
    "Exception(Error())"     => new Exception("outer", 0, new Error("inner"))
];

foreach ($examples as $name => $example) {
    $processed = unserialize(serialize($example));
    $processedPrev = $processed->getPrevious();
    echo "---- $name ----\n";
    echo "before: ", get_class($example), ".previous == ", get_class($example->getPrevious()), "\n";                                                                             
    echo "after : ", get_class($processed), ".previous == ", $processedPrev ? get_class($processedPrev) : "null", "\n";                                                          
}



Expected result:
----------------
---- Exception(Exception()) ----
before: Exception.previous == Exception
after : Exception.previous == Exception
---- Error(Error()) ----
before: Error.previous == Error
after : Error.previous == Error
---- Error(Exception()) ----
before: Error.previous == Exception
after : Error.previous == Error
---- Exception(Error()) ----
before: Exception.previous == Error
after : Exception.previous == Exception


Actual result:
--------------
---- Exception(Exception()) ----
before: Exception.previous == Exception
after : Exception.previous == Exception
---- Error(Error()) ----
before: Error.previous == Error
after : Error.previous == Error
---- Error(Exception()) ----
before: Error.previous == Exception
after : Error.previous == null
---- Exception(Error()) ----
before: Exception.previous == Error
after : Exception.previous == null


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-06-20 08:57 UTC] nikic@php.net
-Status: Open +Status: Verified
 [2018-06-20 08:57 UTC] nikic@php.net
You are right, the code you cited should be checking for Throwable.
 [2018-06-24 20:29 UTC] nikic@php.net
Automatic comment on behalf of nikita.ppv@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=701460ba84865be03df81265a6c6d76f40dd6b00
Log: Fixed bug #76502
 [2018-06-24 20:29 UTC] nikic@php.net
-Status: Verified +Status: Closed
 
PHP Copyright © 2001-2018 The PHP Group
All rights reserved.
Last updated: Mon Nov 19 02:01:26 2018 UTC