Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:69511 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 83936 invoked from network); 7 Oct 2013 22:01:22 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 7 Oct 2013 22:01:22 -0000 Authentication-Results: pb1.pair.com smtp.mail=rowan.collins@gmail.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=rowan.collins@gmail.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain gmail.com designates 209.85.212.172 as permitted sender) X-PHP-List-Original-Sender: rowan.collins@gmail.com X-Host-Fingerprint: 209.85.212.172 mail-wi0-f172.google.com Received: from [209.85.212.172] ([209.85.212.172:43615] helo=mail-wi0-f172.google.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 57/41-09409-03F23525 for ; Mon, 07 Oct 2013 18:01:21 -0400 Received: by mail-wi0-f172.google.com with SMTP id hn9so5574472wib.17 for ; Mon, 07 Oct 2013 15:01:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:subject :content-type:content-transfer-encoding; bh=AfrCX1i2J5iC5FSqljgctF7y6/jazALx+Y/2uYj5MNQ=; b=KmXcBOJnaT7Wkrm4I/LpamQFFjmDBO3AINMhIbYCPDTG2qdbhFq47PQMj8WsfK5SJw x4YxWyCB/Yp7Q6Yew75RfMrqjwYylfMXFZ7r/BWp5OXOjzcHIqV0GKDBH/3Bvc3CQC9c IfFHaH7eZtInc4vtXPNAT7QDV0vcr+1IJ7sKrDtRQTJ5P3YSNVuvSJToTLb8qHZUahN5 gsU2OSUQEtyZTJHU8SOfKFCUfYK363xIz2CUXkvwNYjBisqIN4AgOTmcStKTP4huJard eL1nie+p/AOyvEnQgC5ZPsyXNAR1wG8EuIIWKOd92kO63U2G4tFDNJuzSQnIOh6MQVUP k/Yg== X-Received: by 10.180.205.236 with SMTP id lj12mr21380058wic.22.1381183277177; Mon, 07 Oct 2013 15:01:17 -0700 (PDT) Received: from [192.168.0.2] (cpc19-brig17-2-0-cust25.3-3.cable.virginmedia.com. [81.101.201.26]) by mx.google.com with ESMTPSA id ft19sm1015758wic.5.1969.12.31.16.00.00 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 07 Oct 2013 15:01:16 -0700 (PDT) Message-ID: <52532F2C.2010704@gmail.com> Date: Mon, 07 Oct 2013 23:01:16 +0100 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:17.0) Gecko/20130801 Thunderbird/17.0.8 MIME-Version: 1.0 To: "internals@lists.php.net" Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Subject: Exceptions, stack traces, and serialization From: rowan.collins@gmail.com (Rowan Collins) Hi All, A while ago, I discovered the awkward fact that PHP exceptions can only sometimes be serialized, because they contain a stack trace which might involve non-serializable objects. In my case, one of the function calls in the trace happened to have been passed a SimpleXMLElement as an argument; similarly, anything passed a closure will render the trace unserializable. A quick example is here: http://codepad.viper-7.com/A6U91A When I mentioned this in SO chat, the general response was "yeah, don't do that". Which leads me to my first suggestion: (1) the base Exception class should *always* prevent serialization, in the same way that it always prevents cloning. This would prevent people like me writing code to do it, and only finding out later that it is a Bad Idea. (As background, my use case was some code that used serialized objects to pass call-backs and their responses between processes in a kind of "fake threading"; I wanted exceptions to bubble up to the parent "thread" just as though the callback had been executed locally.) On the other hand, most of the Exception, including its trace *can* actually be serialized - an actual call to a closure is simply given the function name '{closure}', and the object on which a method was called is stored only as its class name, like debug_backtrace without DEBUG_BACKTRACE_PROVIDE_OBJECT. The only part that is at risk of causing serialization errors is the 'args' element in each stack trace entry. This leads to two further possibilities: (2) Don't capture arguments in the trace of an exception, similar to debug_backtrace with DEBUG_BACKTRACE_IGNORE_ARGS set. This would technically be a BC break, but I'm not sure how much real code would care. It's impossible to reconstruct details of the calls fully without the PROVIDE_OBJECT behaviour anyway. This would also have the advantage of making destructors fire more predictably - at the moment, an exception can bubble past a block of code with a deliberately scoped object (e.g. an RAII-style lock token), and if that object happens to be an argument within the Exception's trace, it survives until the Exception itself is destructed, because it has a reference inside the Exception's trace. Again, arguably you shouldn't be relying on this or keeping Exception objects around for long anyway, but it's kind of unexpected behaviour. Alternatively (3), serializing an Exception could discard the 'args' keys in the trace, but retain the rest of the information; or (4) a method could be made to explicitly discard these and mark the object safe for serialization. This lets code that relies on that informaion continue unchanged, while allowing the information needed for most use cases to be serialized as safely as any other object. It seems to me that any one of these options would be better than the current unpredictable behaviour, but I'm more than willing for someone to point out the flaw in my reasoning. Regards, -- Rowan Collins [IMSoP]