Bug #66040 [Com]: Cloning an object while having reference to members results incorrect clone
| From: | david at frankieandshadow dot com | Date: | Mon, 04 Jun 2018 17:49:55 +0000 |
| Subject: | Bug #66040 [Com]: Cloning an object while having reference to members results incorrect clone | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-215487@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=66040&edit=1
ID: 66040
Comment by: david at frankieandshadow dot com
Reported by: bawolff+wn at gmail dot com
Summary: Cloning an object while having reference to members
results incorrect clone
Status: Open
Type: Bug
Package: Scripting Engine problem
Operating System: linux
PHP Version: 5.5Git-2013-11-07 (snap)
Block user comment: N
Private report: N
New Comment:
I think I am encountering this bug, in a slightly different arrangement, and in PHP7.0.27 (the most
up-to-date Debian release of PHP), so if it is the same, as seems likely, it's a rather nasty
core bug that's been around for a long time.
I also verified that @bawolff's example still fails in 7.0.27.
I have
while ($q->f($obj) > 0) {
$list[$obj->field] = clone $obj;
}
where f sets fields in $obj. The list ends up with all 'field' members being the same as
the final one. I don't think there is any PHP I could write in f that would do this
accidentally as it doesn't have access to $list and clone should make the objects be distinct
from each other.
If I change it to:
while ($q->f($obj) > 0) {
$k = obj->field;
$list[$k] = clone $obj;
}
it works. Whether this is because the code generated has been perturbed slightly, or it really is
changing the example enough to not be hitting the bug I can't tell. But my guess is the while
code block is equivalent to @bawolff's function and the $list[$k] is the reference that is
still live when it calls f again causing it to overwrite - which is why I think my bug is
essentially the same.
This isn't the case for all f. In my case f is the result of a database query defined by $q,
and f results in a MySQL select, returning the number of results remaining. I simplified it down to
mimicking that returning objects in turn from a short array instead, but that doesn't fail.
Previous Comments:
------------------------------------------------------------------------
[2013-11-07 02:54:13] bawolff+wn at gmail dot com
Description:
------------
The problem is easiest understood by looking at the test script.
Basically, if you clone an object in a function that as one of its arguments (or one of its calling
functions) has a reference to a member variable of this object, the clone of the object is not
correct for the field that the reference is to. The fields of the two objects behave as if they are
references to each other (To clarify I do not mean fields point to the same object as is expected, I
mean the field itself is a reference to the other field.). If you assign something to that member
variable, the change is reflected in both the cloned object and the original, where it should only
be reflected in the object that the assignment was for.
Tested on snapshot php5.5-201311070030
Also tested on earlier versions like 5.3.3-7
Originally discovered while investigating a bug in MediaWiki: https://bugzilla.wikimedia.org/show_bug.cgi?id=56226
Test script:
---------------
<?php
$originalObj = new A;
class A {
var $foo = 'default value';
}
// Important note: If you remove the &, the bug disappears.
function changeFooWithUnusedReference( &$unusedReferenceToFoo, $newValue ) {
global $originalObj;
$newObj = clone $originalObj;
echo $originalObj->foo . "\n";
echo $newObj->foo . "\n";
$newObj->foo = $newValue;
echo $originalObj->foo . "\n";
echo $newObj->foo . "\n";
}
changeFooWithUnusedReference( $originalObj->foo, 'Some other value' );
Expected result:
----------------
I expect the following output:
default value
default value
default value
Some other value
Actual result:
--------------
Following output:
default value
default value
Some other value
Some other value
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=66040&edit=1