Bug #76502 [Ver->Csd]: Chain of mixed exceptions and errors does not serialize properly

From: 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

« previous php.bugs (#215957) next »