|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2008-02-20 09:26 UTC] robin_fernandes at uk dot ibm dot com
Description:
------------
extract($a, EXTR_REFS) does not always respect copy-on-write reference logic.
In the testcase below, $nonRef is initially a copy-on-write reference to an element of $a. After the call to extract, it has become a real reference to an element of $a.
This is reproducible on 5.2, 5.3 and 6.0 snaps.
Reproduce code:
---------------
<?php
$a = array('foo' => 'original.foo');
$nonref = $a['foo'];
$ref = &$a;
extract($a, EXTR_REFS);
$a['foo'] = 'changed.foo';
var_dump($nonref); //expecting original.foo
?>
Expected result:
----------------
string(12) "original.foo"
Actual result:
--------------
string(11) "changed.foo"
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Fri Oct 24 13:00:02 2025 UTC |
I think the problem is that extract() can set the is_ref flag on zvals without splitting them (i.e. zvals which have more than 1 copy-on-write references can get their is_ref flag set). From array.c: ... } else { if (Z_REFCOUNT_P(var_array) > 1 || *entry == EG(uninitialized_zval_ptr)) { SEPARATE_ZVAL_TO_MAKE_IS_REF(entry); } else { Z_SET_ISREF_PP(entry); // <-- causes damage if entry has COW references! } ... I believe that the only reliable way to fix this would be to make extract() take its array argument as PREFER_REF. This way, we can safely split array elements away from their copy-on-write references, and still end up with a zval that belongs to the original array. I'm attaching a patch which implements this and fixes this bug, as well as bug http://bugs.php.net/44181. Disclaimer: - I am not an internals expert. I might have disregarded some scenarios. Feedback welcome! - Patch tested on Windows XP 32bit only. Patch against php6.0-200802191530 snap (includes test cases): http://pastebin.ca/910172