Bug #76502 [Ver->Csd]: Chain of mixed exceptions and errors does not serialize properly
| From: | nikic@php.net | Date: | Sun, 24 Jun 2018 20:29:45 +0000 |
| Subject: | Bug #76502 [Ver->Csd]: Chain of mixed exceptions and errors does not serialize properly | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-215957@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=76502&edit=1
ID: 76502
Updated by: nikic@php.net
Reported by: benjamin dot zikarsky at jaumo dot com
Summary: Chain of mixed exceptions and errors does not
serialize properly
-Status: Verified
+Status: Closed
Type: Bug
Package: *General Issues
Operating System: Linux 4.16
PHP Version: 7.2.6
Block user comment: N
Private report: N
New Comment:
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
Previous Comments:
------------------------------------------------------------------------
[2018-06-20 08:57:55] nikic@php.net
You are right, the code you cited should be checking for Throwable.
------------------------------------------------------------------------
[2018-06-20 07:52:09] 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
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=76502&edit=1