php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #44182 extract($a, EXTR_REFS) can fail to split copy-on-write references
Submitted: 2008-02-20 09:26 UTC Modified: 2008-11-26 01:03 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:0 of 0 (0.0%)
From: robin_fernandes at uk dot ibm dot com Assigned:
Status: Closed Package: Arrays related
PHP Version: 5CVS, 6CVS (2008-10-27) OS: *
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: robin_fernandes at uk dot ibm dot com
New email:
PHP Version: OS:

 

 [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"

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2008-02-20 09:29 UTC] robin_fernandes at uk dot ibm dot com
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
 [2008-10-25 13:25 UTC] jani@php.net
That url does not work..
 [2008-10-25 13:52 UTC] robin_fernandes at uk dot ibm dot com
The patch URL? Seems OK to me, perhaps it was temporarily broken.

In any case, here's another one: 
http://soal.org/php/extract.patch.txt
 [2008-10-27 13:01 UTC] jani@php.net
Does this bug exist in HEAD, PHP_5_3 and PHP_5_2 branches? And in today's versions of them?
 [2008-10-27 13:20 UTC] robin_fernandes at uk dot ibm dot com
Confirmed this bug (and bug 44181) still present on:
PHP 5.2.7RC3-dev (cli) (built: Oct 27 2008 11:40:07) 
PHP 5.3.0alpha3-dev (cli) (built: Oct 27 2008 14:06:30) 
PHP 6.0.0-dev (cli) (built: Oct 27 2008 12:39:36)
 [2008-11-26 01:03 UTC] lbarnaud@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.

Thanks for the patch
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 12:01:29 2024 UTC