php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #72543 different references behavior comparing to 5.5
Submitted: 2016-07-04 13:31 UTC Modified: 2016-07-06 17:49 UTC
From: tony2001@php.net Assigned: dmitry (profile)
Status: Closed Package: Scripting Engine problem
PHP Version: 7.1.0alpha1 OS: *
Private report: No CVE-ID: None
 [2016-07-04 13:31 UTC] tony2001@php.net
Description:
------------
Looks like references behavior has changed in 7.x comparing to 5.5.
First of all, once variable becomes reference, it never looses that flag, even though the second reference is already destroyed (see the first function "create_references").
Second, I'm able to change the original variable by passing its copy to a function and modifying it there, which is definitely counter-intuitive.
I expected the function to copy the variable to write, since it was not passed by reference, as that's what seems to be happening in PHP 5.5

Test script:
---------------
/* after this function all array elements become references */
function create_references(&$array) {
    $refs[] = &$array;
    foreach ($array as $key => $value) {
        create_references($array[$key]);
    }
}   

/* a copy is passed and then modified, which also modifies the original variable */
function change_copy($copy) {
    for ($i = 0; $i < 2; $i++) {
        $copy['b']['b'] = $copy['b']; //this causes recursion
    }
}   

$data = [
    'a' => [
        'b' => [],
    ],  
];  
 
create_references($data);
 
$copy = $data['a'];
var_dump($data);

change_copy($copy);
var_dump($data); //RECURSION

Expected result:
----------------
array(1) {
  ["a"]=>
  array(1) {
    ["b"]=>
    array(0) {
    }
  }
}
array(1) {
  ["a"]=>
  array(1) {
    ["b"]=>
    array(0) {
    }
  }
}


Actual result:
--------------
array(1) {
  ["a"]=>
  array(1) {
    ["b"]=>
    array(0) {
    }
  }
}
array(1) {
  ["a"]=>
  array(1) {
    ["b"]=>
    array(1) {
      ["b"]=>
      *RECURSION*
    }
  }
}


Patches

bug72543_3.diff (last revision 2016-07-06 00:31 UTC by dmitry@php.net)
bug72543_2.diff (last revision 2016-07-05 19:57 UTC by dmitry@php.net)
bug72543.diff (last revision 2016-07-05 10:45 UTC by dmitry@php.net)

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-07-04 13:32 UTC] tony2001@php.net
-Status: Open +Status: Assigned -Assigned To: +Assigned To: dmitry
 [2016-07-04 15:52 UTC] laruence@php.net
@Dmitry, this reminds me of the patch I committed before(it was replaced though), http://pastebin.com/jHGEL7v8 the base idea here is, we should return non-reference in read context(FETCH_DIM_R), that patch should fix this problem as well

what do you think?
 [2016-07-04 17:02 UTC] dmitry@php.net
In general, you fix is right, but it introduces an extra check on fast path, that is useless in almost all cases. I'll try to find a cheaper solution.
 [2016-07-05 03:17 UTC] laruence@php.net
yeah, I agree with that, but if cheaper fix is mess, than I prefer a clear one, besides, one UNEXPECT check should not change anything in performance.
 [2016-07-05 09:58 UTC] dmitry@php.net
Before execution of the following statement $copy['b'] is a "dead" REFERENCE with refcount==1. 

$copy['b']['b'] = $copy['b'];

Right-side expression evaluated first, and incrementats REFERENCE refcount (it became 2). After that, it starts to behave as a real REFERENCE and is not separated during left-side expression evaluation.
 [2016-07-05 10:45 UTC] dmitry@php.net
The following patch has been added/updated:

Patch Name: bug72543.diff
Revision:   1467715534
URL:        https://bugs.php.net/patch-display.php?bug=72543&patch=bug72543.diff&revision=1467715534
 [2016-07-05 11:19 UTC] laruence@php.net
does your patch also take care of

$arr = 'b';
$$arr['b']['b'] = $b['b']; ?
 [2016-07-05 19:57 UTC] dmitry@php.net
The following patch has been added/updated:

Patch Name: bug72543_2.diff
Revision:   1467748668
URL:        https://bugs.php.net/patch-display.php?bug=72543&patch=bug72543_2.diff&revision=1467748668
 [2016-07-06 00:31 UTC] dmitry@php.net
The following patch has been added/updated:

Patch Name: bug72543_3.diff
Revision:   1467765063
URL:        https://bugs.php.net/patch-display.php?bug=72543&patch=bug72543_3.diff&revision=1467765063
 [2016-07-06 17:46 UTC] dmitry@php.net
Automatic comment on behalf of dmitry@zend.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=023b81259325c00012c0f703976c082be72dc5b9
Log: Fixed bug #72543 (Different references behavior comparing to PHP 5)
 [2016-07-06 17:46 UTC] dmitry@php.net
-Status: Assigned +Status: Closed
 [2016-07-20 11:30 UTC] davey@php.net
Automatic comment on behalf of dmitry@zend.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=023b81259325c00012c0f703976c082be72dc5b9
Log: Fixed bug #72543 (Different references behavior comparing to PHP 5)
 [2016-10-17 10:11 UTC] bwoebi@php.net
Automatic comment on behalf of dmitry@zend.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=023b81259325c00012c0f703976c082be72dc5b9
Log: Fixed bug #72543 (Different references behavior comparing to PHP 5)
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Oct 11 09:01:26 2024 UTC