php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #52001 Memory allocation problems after using variable variables
Submitted: 2010-06-05 17:14 UTC Modified: 2010-06-10 11:16 UTC
Votes:128
Avg. Score:4.1 ± 1.2
Reproduced:72 of 80 (90.0%)
Same Version:63 (87.5%)
Same OS:38 (52.8%)
From: lisio at bk dot ru Assigned: dmitry
Status: Closed Package: Scripting Engine problem
PHP Version: 5.3.2 OS: Linux
Private report: No CVE-ID:
 [2010-06-05 17:14 UTC] lisio at bk dot ru
Description:
------------
After calling the function using a non-defined variable variable as a second parameter the interpreter goes crazy. Just reproduce the script on any of 5.3.* versions of PHP.

Test script:
---------------
<?php
a(0,$$var);

$temp1=1;
$temp2=2;
echo $temp1;

function a($b,$c) {}
?>

Expected result:
----------------
1

Actual result:
--------------
2

Patches

patch-dont-ruine-uninitialized-ptr (last revision 2010-06-08 02:40 UTC) by boldin dot pavel at gmail dot com)
patch-bug-52001-tests (last revision 2010-06-07 23:27 UTC) by boldin dot pavel at gmail dot com)
patch-zend-fetch-make-ref-uninitialized-ptr (last revision 2010-06-06 17:03 UTC) by boldin dot pavel at gmail dot com)

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2010-06-06 09:10 UTC] akorolyov at gmail dot com
<?php
$test = 0;
$var = 'test';
f(0, $$var);
$x = 1;
$y = 2;
echo $x;
function f($a, $b) {}
?>

In this case I receive correct result.
 [2010-06-06 10:30 UTC] boldin dot pavel at gmail dot com
Even more:
f($$var, 0) will also work.
If you declare function before calling it will work too.

Seems like bug in zend_do_pass_params or so on, causing to corruption of buffer.

These CVs are just missing from the scope (active_symbol_table) after calling function. Seems like they are removed in middle of code execution.
 [2010-06-06 10:36 UTC] boldin dot pavel at gmail dot com
More detailed: when you pass off the function, _get_zval_cv_lookup no longer able to find your CVs, and they are missed. _get_zval_cv_lookup then returns pointer EG(uninitialized_zval_ptr), which is shared among a set of values.

So two values are stored in same place. It is essential that this happens only if you call it with ZEND_FCALL_BY_NAME (i.e. declare after using) and only if dereferenced value is not first.
 [2010-06-06 11:23 UTC] boldin dot pavel at gmail dot com
Here is the problem: Zend/zend_execution.c line 703 (version 5.3.2): incorrect reference count (== 1) in case of bug. Should be == 3 and copy data in 'else' branch.
 [2010-06-06 18:08 UTC] boldin dot pavel at gmail dot com
Version without bug:
(gdb)
zend_send_by_var_helper_SPEC_VAR (execute_data=0x88a28d0)
    at /home/davinchi/php-5.3.2/Zend/zend_vm_execute.h:8257
8257            varptr = _get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC);
(gdb)
8259            if (varptr == &EG(uninitialized_zval)) {
(gdb) p varptr
$24 = (zval *) 0x877fd04
(gdb) p &executor_globals.uninitialized_zval
$25 = (zval *) 0x877fd04
(gdb) p executor_globals.uninitialized_zval_ptr
$26 = (zval *) 0x877fd04

And version with bug:
zend_send_by_var_helper_SPEC_VAR (execute_data=0x88a28d0)
    at /home/davinchi/php-5.3.2/Zend/zend_vm_execute.h:8254
8254            zend_op *opline = EX(opline);
(gdb)
8257            varptr = _get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC);
(gdb) n
8259            if (varptr == &EG(uninitialized_zval)) {
(gdb) p varptr
$27 = (zval *) 0x8876d8c
(gdb) p &executor_globals.uninitialized_zval
$28 = (zval *) 0x877fd04
(gdb) p executor_globals.uninitialized_zval_ptr
$29 = (zval *) 0x8876d8c


See that uninitialized_zval_ptr dont pointers to the uninitialized_zval at all!
 [2010-06-06 18:38 UTC] boldin dot pavel at gmail dot com
Finally: bug is at 
                if (opline->extended_value & ZEND_FETCH_MAKE_REF) {
                        SEPARATE_ZVAL_TO_MAKE_IS_REF(retval);
                }

SEPARATE_ZVAL_TO_MAKE_IS_REF seems to ruine *retval (which is executor_globals.uninitialized_ptr). Then this leads to incorrectly working zend_send_by_var_helper and incorrect referencing count in zend_assign_to_variable.

Trying to patch now.
 [2010-06-06 19:06 UTC] boldin dot pavel at gmail dot com
I have attached patch. It must be reviewed by professional PHP developer.

For me it is clearly that call of SEPARATE_ZVAL_TO_MAKE_IS_REF must be predicated with such a check (and it is done in all other cases).
 [2010-06-06 19:15 UTC] boldin dot pavel at gmail dot com
Zend/zend_compile.c 1066:
                if (opline && type == BP_VAR_W && arg_offset) {
                        opline->extended_value = ZEND_FETCH_MAKE_REF;
                }

Is not this bug too? ZEND_FETCH_MAKE_REF is not set for first (arg_offset == 0) arg?
 [2010-06-08 11:18 UTC] tony2001@php.net
-Status: Open +Status: Assigned -Assigned To: +Assigned To: dmitry
 [2010-06-08 11:22 UTC] boldin dot pavel at gmail dot com
old patch brokes tests (Zend/tests/objects_020.phpt), new one don't. Still don't sure if it is absolutely correct.
 [2010-06-10 11:13 UTC] dmitry@php.net
Automatic comment from SVN on behalf of dmitry
Revision: http://svn.php.net/viewvc/?view=revision&amp;revision=300345
Log: Fixed bug #52001 (Memory allocation problems after using variable variables)
 [2010-06-10 11:16 UTC] dmitry@php.net
-Status: Assigned +Status: Closed
 [2010-06-10 11:16 UTC] dmitry@php.net
This bug has been fixed in SVN.

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.


 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Sun Apr 20 03:02:42 2014 UTC