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

problems with array_splice

proff opened this issue · comments

in some places in my legacy project functions used array_splice for remove elements in subarray of array passed via parameter, but after it return in parent function i got changed array in parent function. For now i can't reproduce this bug. Change PhpArray.Copy body to "return this.DeepCopy();" solves problem.

<?
function test($arr)
{
  array_splice($arr['content'],1,1);
}
function test1($arr) //works
{
  $content=$arr['content'];
  array_splice($content,1,1);
}
$arr=array('content'=>array(array(),array(),array()));
test($arr);
echo count($arr['content']);
?>

in php result will be 3, in phalanger 2

workaround: declare first parameter in array_splice as ref, it's force compiler generate code with copying array before call array_splice

"ref" does not force compiler to copy the array.
It has several side effects

  • it does not throw PHP warning when provided parameter is not an array
  • it adds overhead when updating PHP variable

But it does not cause the array to be copied.

This case is probably a bug in runtime, I'll take a look.

Yep, bug in PhpArray copy-on-write mechanism

"ref" does not force compiler to copy the array, but it force compiler to save subarray in a variable before function call and it force to copy the array.

It only causes the variable (in this case subarray) to be wrapped into PhpReference. This is just a coincidence that it was not PhpReference yet, and making array item a reference causes internally the CopyOnWrite process.

The bug is in PhpArray mechanism. Using "ref" just to fix this random test case only causes the rest of applications to perform slower.

The problem is, compiler does not care about [PhpRw] attribute. It should check it, and perform CopyOnWrite (PhpArray.EnsureWritable())

PhpRw attribute was designed before PhpArray CopyOnWrite mechanism was implemented. I'll just finish the PhpRw implementation, and (ALL!!) class library functions making use of PhpRw will work.

I said that this just workaround :)

Well, we were looking for this bug for years :-) however fixing it won't be any trivial

note for me: when calling a LibraryFunction([PhpRw]item), content of "item" must not be shared by more variables (this happens due to CopyOnWrite mechanism). Normally CoW works when array is modified (by calling Ensure*, SetItem, GetItemRef), however GetItem does not cause lazy copying.
[PhpRw] tells compiler, the parameter may be modified, and so CoW has to be performed.
Catch - CoW has to be performed on the owner if the item (where the item is contained), not the item (e.g. when passing $arr[1], $arr is shared by more variables, and in this case $arr must be lazy copied). There might be another catch when there are references in the chain of array items ...