dmitry Wed, 25 Aug 2010 09:14:36 +0000 Revision: http://svn.php.net/viewvc?view=revision&revision=302764
Log: Fixed bug #52614 (Memory leak when writing on uninitialized variable returned from method call) Bug: http://bugs.php.net/52614 (Assigned) Memory leak when writing on uninitialized variable returned from method call Changed paths: U php/php-src/trunk/NEWS A php/php-src/trunk/Zend/tests/bug52614.phpt U php/php-src/trunk/Zend/zend_compile.c U php/php-src/trunk/Zend/zend_language_parser.y U php/php-src/trunk/Zend/zend_vm_def.h U php/php-src/trunk/Zend/zend_vm_execute.h U php/php-src/trunk/Zend/zend_vm_opcodes.h
Modified: php/php-src/trunk/NEWS =================================================================== --- php/php-src/trunk/NEWS 2010-08-25 08:26:12 UTC (rev 302763) +++ php/php-src/trunk/NEWS 2010-08-25 09:14:36 UTC (rev 302764) @@ -117,6 +117,8 @@ - Fixed a NULL pointer dereference when processing invalid XML-RPC requests (Fixes CVE-2010-0397, bug #51288). (Raphael Geissert) +- Fixed bug #52614 (Memory leak when writing on uninitialized variable returned + from method call). (Dmitry) - Fixed bug #51338 (URL-Rewriter is still enabled if use_only_cookies is on). (Ilia, j dot jeising at gmail dot com) - Fixed bug #51269 (zlib.output_compression Overwrites Vary Header). (Adam) Added: php/php-src/trunk/Zend/tests/bug52614.phpt =================================================================== --- php/php-src/trunk/Zend/tests/bug52614.phpt (rev 0) +++ php/php-src/trunk/Zend/tests/bug52614.phpt 2010-08-25 09:14:36 UTC (rev 302764) @@ -0,0 +1,83 @@ +--TEST-- +Bug #52614 (Memory leak when writing on uninitialized variable returned from method call) +--FILE-- +<?php +class foo { + public $a1; + public $a2 = array(); + public $a3; + public $o1; + public $o2; + + public function f1() { + return $this->a1; + } + + public function f2() { + return $this->a2; + } + + public function f3() { + $this->a3 = array(); + return $this->a3; + } + + public function f4() { + return $this->o1; + } + + public function f5() { + $this->o2 = new stdClass; + return $this->o2; + } + + public function &f6() { + return $this->a1; + } + + public function f7(&$x) { + $x = 2; + } + +} + +$foo = new foo; + +$foo->f1()[0] = 1; +var_dump($foo->a1); + +$foo->f2()[0] = 1; +var_dump($foo->a2); + +$foo->f3()[0] = 1; +var_dump($foo->a3); + +$foo->f4()->a = 1; +var_dump($foo->o1); + +$foo->f5()->a = 1; +var_dump($foo->o2); + +$foo->a1[0] = 1; +$foo->f7($foo->f6()[0]); +var_dump($foo->a1[0]); +$foo->f1()[0]++; +var_dump($foo->a1[0]); +$foo->f6()[0]++; +var_dump($foo->a1[0]); +--EXPECTF-- +NULL +array(0) { +} +array(0) { +} + +Strict Standards: Creating default object from empty value in %sbug52614.php on line 52 +NULL +object(stdClass)#%d (1) { + ["a"]=> + int(1) +} +int(2) +int(2) +int(3) Modified: php/php-src/trunk/Zend/zend_compile.c =================================================================== --- php/php-src/trunk/Zend/zend_compile.c 2010-08-25 08:26:12 UTC (rev 302763) +++ php/php-src/trunk/Zend/zend_compile.c 2010-08-25 09:14:36 UTC (rev 302764) @@ -550,6 +550,14 @@ op.constant = zend_add_literal(CG(active_op_array), &_c); \ } while (0) +static inline zend_bool zend_is_function_or_method_call(const znode *variable) /* {{{ */ +{ + zend_uint type = variable->EA; + + return ((type & ZEND_PARSED_METHOD_CALL) || (type == ZEND_PARSED_FUNCTION_CALL)); +} +/* }}} */ + void zend_do_binary_op(zend_uchar op, znode *result, const znode *op1, const znode *op2 TSRMLS_DC) /* {{{ */ { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); @@ -781,6 +789,18 @@ zend_op opline; zend_llist *fetch_list_ptr; + zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr); + + if (zend_is_function_or_method_call(parent)) { + init_op(&opline TSRMLS_CC); + opline.opcode = ZEND_SEPARATE; + SET_NODE(opline.op1, parent); + SET_UNUSED(opline.op2); + opline.result_type = IS_VAR; + opline.result.var = opline.op1.var; + zend_llist_add_element(fetch_list_ptr, &opline); + } + init_op(&opline TSRMLS_CC); opline.opcode = ZEND_FETCH_DIM_W; /* the backpatching routine assumes W */ opline.result_type = IS_VAR; @@ -802,7 +822,6 @@ GET_NODE(result, opline.result); - zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr); zend_llist_add_element(fetch_list_ptr, &opline); } /* }}} */ @@ -985,14 +1004,6 @@ } /* }}} */ -static inline zend_bool zend_is_function_or_method_call(const znode *variable) /* {{{ */ -{ - zend_uint type = variable->EA; - - return ((type & ZEND_PARSED_METHOD_CALL) || (type == ZEND_PARSED_FUNCTION_CALL)); -} -/* }}} */ - void zend_do_assign_ref(znode *result, const znode *lvar, const znode *rvar TSRMLS_DC) /* {{{ */ { zend_op *opline; @@ -1307,6 +1318,14 @@ while (le) { opline_ptr = (zend_op *)le->data; + if (opline_ptr->opcode == ZEND_SEPARATE) { + if (type != BP_VAR_R && type != BP_VAR_IS) { + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + memcpy(opline, opline_ptr, sizeof(zend_op)); + } + le = le->next; + continue; + } opline = get_next_op(CG(active_op_array) TSRMLS_CC); memcpy(opline, opline_ptr, sizeof(zend_op)); if (opline->op1_type == IS_VAR && @@ -4865,6 +4884,16 @@ } } + if (zend_is_function_or_method_call(object)) { + init_op(&opline TSRMLS_CC); + opline.opcode = ZEND_SEPARATE; + SET_NODE(opline.op1, object); + SET_UNUSED(opline.op2); + opline.result_type = IS_VAR; + opline.result.var = opline.op1.var; + zend_llist_add_element(fetch_list_ptr, &opline); + } + init_op(&opline TSRMLS_CC); opline.opcode = ZEND_FETCH_OBJ_W; /* the backpatching routine assumes W */ opline.result_type = IS_VAR; @@ -5745,7 +5774,11 @@ if (fetch->opcode == ZEND_FETCH_DIM_W && fetch->op2_type == IS_UNUSED) { zend_error(E_COMPILE_ERROR, "Cannot use [] for reading"); } - fetch->opcode -= 3; /* FETCH_W -> FETCH_R */ + if (fetch->opcode == ZEND_SEPARATE) { + MAKE_NOP(fetch); + } else { + fetch->opcode -= 3; /* FETCH_W -> FETCH_R */ + } } /* prevent double SWITCH_FREE */ zend_stack_top(&CG(foreach_copy_stack), (void **) &foreach_copy); Modified: php/php-src/trunk/Zend/zend_language_parser.y =================================================================== --- php/php-src/trunk/Zend/zend_language_parser.y 2010-08-25 08:26:12 UTC (rev 302763) +++ php/php-src/trunk/Zend/zend_language_parser.y 2010-08-25 09:14:36 UTC (rev 302764) @@ -932,7 +932,7 @@ array_method_dereference: array_method_dereference '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } - | method '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } + | method '[' dim_offset ']' { $1.EA = ZEND_PARSED_METHOD_CALL; fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } ; method: @@ -942,7 +942,7 @@ ; method_or_not: - method { $$ = $1; zend_do_push_object(&$$ TSRMLS_CC); $$.EA = ZEND_PARSED_METHOD_CALL; } + method { $$ = $1; $$.EA = ZEND_PARSED_METHOD_CALL; zend_do_push_object(&$$ TSRMLS_CC); } | array_method_dereference { $$ = $1; zend_do_push_object(&$$ TSRMLS_CC); } | /* empty */ { $$.EA = ZEND_PARSED_MEMBER; } ; @@ -964,7 +964,7 @@ array_function_dereference: array_function_dereference '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } - | function_call { zend_do_begin_variable_parse(TSRMLS_C); $$.EA = ZEND_PARSED_FUNCTION_CALL; } + | function_call { zend_do_begin_variable_parse(TSRMLS_C); $1.EA = ZEND_PARSED_FUNCTION_CALL; } '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$4 TSRMLS_CC); } ; Modified: php/php-src/trunk/Zend/zend_vm_def.h =================================================================== --- php/php-src/trunk/Zend/zend_vm_def.h 2010-08-25 08:26:12 UTC (rev 302763) +++ php/php-src/trunk/Zend/zend_vm_def.h 2010-08-25 09:14:36 UTC (rev 302764) @@ -4998,4 +4998,25 @@ ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HANDLER(156, ZEND_SEPARATE, VAR, UNUSED) +{ + USE_OPLINE + zval *var_ptr, *new_zv; + + SAVE_OPLINE(); + var_ptr = EX_T(opline->op1.var).var.ptr; + if (Z_TYPE_P(var_ptr) != IS_OBJECT && + !PZVAL_IS_REF(var_ptr) && + Z_REFCOUNT_P(var_ptr) > 1) { + + Z_DELREF_P(var_ptr); + ALLOC_ZVAL(new_zv); + INIT_PZVAL_COPY(new_zv, var_ptr); + var_ptr = new_zv; + zval_copy_ctor(var_ptr); + EX_T(opline->op1.var).var.ptr = var_ptr; + } + ZEND_VM_NEXT_OPCODE(); +} + ZEND_VM_EXPORT_HELPER(zend_do_fcall, zend_do_fcall_common_helper) Modified: php/php-src/trunk/Zend/zend_vm_execute.h =================================================================== --- php/php-src/trunk/Zend/zend_vm_execute.h 2010-08-25 08:26:12 UTC (rev 302763) +++ php/php-src/trunk/Zend/zend_vm_execute.h 2010-08-25 09:14:36 UTC (rev 302764) @@ -18807,6 +18807,27 @@ ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_SEPARATE_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *var_ptr, *new_zv; + + SAVE_OPLINE(); + var_ptr = EX_T(opline->op1.var).var.ptr; + if (Z_TYPE_P(var_ptr) != IS_OBJECT && + !PZVAL_IS_REF(var_ptr) && + Z_REFCOUNT_P(var_ptr) > 1) { + + Z_DELREF_P(var_ptr); + ALLOC_ZVAL(new_zv); + INIT_PZVAL_COPY(new_zv, var_ptr); + var_ptr = new_zv; + zval_copy_ctor(var_ptr); + EX_T(opline->op1.var).var.ptr = var_ptr; + } + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_ADD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -39488,6 +39509,31 @@ ZEND_BIND_TRAITS_SPEC_HANDLER, ZEND_BIND_TRAITS_SPEC_HANDLER, ZEND_BIND_TRAITS_SPEC_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_SEPARATE_SPEC_VAR_UNUSED_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_NULL_HANDLER }; zend_opcode_handlers = (opcode_handler_t*)labels; Modified: php/php-src/trunk/Zend/zend_vm_opcodes.h =================================================================== --- php/php-src/trunk/Zend/zend_vm_opcodes.h 2010-08-25 08:26:12 UTC (rev 302763) +++ php/php-src/trunk/Zend/zend_vm_opcodes.h 2010-08-25 09:14:36 UTC (rev 302764) @@ -156,3 +156,4 @@ #define ZEND_DECLARE_LAMBDA_FUNCTION 153 #define ZEND_ADD_TRAIT 154 #define ZEND_BIND_TRAITS 155 +#define ZEND_SEPARATE 156
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php