DEVSENSE / Phalanger

PHP 5.4 compiler for .NET/Mono frameworks. Predecessor to the opensource PeachPie project (www.peachpie.io).

Home Page:http://v4.php-compiler.net/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

bug with references and array's copy on write

proff opened this issue · comments

<?
function test()
{
       global $a;

       $b = &$a[0];
       $b = 1;
}

$a = array(0);
test();
$d = $a;
$a[0] = 2;
echo $d[0];
?>

in php result is 1, in phalanger 2

        private void PHP.Core.OrderedDictionary._deep_copy_entry_value(object oldref, object newref, ref Entry entry)
        {
            var r = entry.Value as PhpReference;
            if (r != null)
            {
                if (r.Value == oldref)
                    entry.Value = new PhpReference(newref);
                else
                    entry.Value = new PhpReference(r.Value);
            }
            else
                entry.Value = PhpVariable.DeepCopy(entry.Value);
        }

but i'm not tested for new bugs yet

This change is equal the preview version
new PhpReference(r.Value) === PhpVariable.DeepCopy(entry.Value) // in case entry.Value is PhpReference, see PhpReference.DeepCopy()

new PhpReference(r.Value) !== PhpVariable.DeepCopy(entry.Value)
in left part it will be new instance of the PhpReference, in right part it will be same instance of the PhpReference (and "$a[0] = 2;" line change value in both arrays because theirs contains same instance of the PhpReference).

I see, right

So
$b = &$a[0] // upgrades 0th element to PhpRreference
$d = $a; // increases copy count of internal PhpHashtable (CopyOnWrite mechanism)
$a[0] = 2; // starts CopyOnWrite ... DeepCopy all elements, how do we handle PhpReference?

  1. references to self should be changed to new self (there is bug too, if we are lazy-copying on original self, the new self would have copy count back to 1 and reference to self of another PhpHashtable instance won't be updated)
  2. other references are needed? Shouldn't we dereference all the values ?

If we create new PhpReference instance, following test would fails I guess:

<?php

function test()
{
    $x = 1;
    $arr = [&$x];
    $arr[0] = 2;
    var_dump($x, $arr);

    $arr2 = $arr;
    $arr2[0] = 3;
    var_dump($x, $arr, $arr2);
}
test();

AH! I think the problem is somewhere else ...

PHP COUNTS references. As $b dies, $a[0] behaves as a value type again.

We've encountered this issue earlier, and it would require to implement own garbage collector I afraid.