On 01/08/2015 01:06, Rowan Collins wrote:
On 1 August 2015 00:36:58 BST, Stanislav Malyshev <smalys...@gmail.com> wrote:

DEBUG_BACKTRACE_IGNORE_ARGS in a debug_backtrace() call. IIRC the
object of called methods is already excluded (equivalent to masking
out DEBUG_PROVIDE_OBJECT) so what's left is all strings.
I'm not sure how you arrived at the conclusion that all arguments in
backtrace are strings. Arguments can be of any type. When printed, they
are converted to strings, but they are not strings when stored.
I'll have to recheck when I have more time, and something better than a phone 
to type on, but from memory, the backtrace which can be retrieved from an 
exception includes the same  information as debug_backtrace(false), that is:
- function: string
- line: integer
- file: string
- class: string
- type: string
- args: array

Of these 6 items, it is only 'args' that can contain an object of any kind, so 
without this item, the data would be  serializable. This would be equivalent to 
debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS).

If any of these items (other than args) are stored in memory in a different 
form (which doesn't seem likely to me), that form is completely inaccessible to 
the user, so converting to string during serialization would effectively be 
lossless. (Or, pre-converting would have zero BC break.) Similarly, if 
additional details are stored, those details are inaccessible, so removing them 
has no impact on any existing (userland) code.

I just double-checked this. You can see that there is not even an internal reference to objects which were $this in the stack trace, because the object can be garbage collected separately from the exception. http://3v4l.org/hOYb9

So, as I said, no object will be implicitly attached to the exception anywhere other than the 'args' key of the backtrace. Obviously, people can attach object references wherever they like, but without this implicit gathering of objects from the entire environment, "serialize(new Exception)" would be a safe operation.

Slightly abbreviated version:

class Example {
    private $label;
    public function __construct($label) {
        $this->label = $label;
    }
    public function __sleep() {
        echo "Attempt to serialize object with label $this->label\n";
        return array('label');
    }
    public function __destruct() {
        echo "Refcount reached zero for object with label $this->label\n";
    }
    public function throwSomething($unused_parameter) {
        throw new Exception;
    }
}

$target = new Example('Target of method call');
$parameter = new Example('Parameter passed but never actually used');
try {
    $target->throwSomething($parameter);
}
catch ( Exception $e ) {
// Serialize exception, will attempt to serialize $parameter but not $target
    var_dump(serialize($e));
    // Destroy $target, as there are no other references to it
    unset($target);
// Attempt to do the same for $parameter, but Exception holds a reference
    unset($parameter);
}
echo "-- PHP process cleanup begins here --\n";
// $parameter will have its destructor fired once $e goes out of scope and relinquishes its reference

Regards,

--
Rowan Collins
[IMSoP]


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to