diff options
author | Dmitry Stogov <dmitry@php.net> | 2010-08-25 09:14:36 +0000 |
---|---|---|
committer | Dmitry Stogov <dmitry@php.net> | 2010-08-25 09:14:36 +0000 |
commit | 2188f26c45375358ac872a61b6de76fc85b83be4 (patch) | |
tree | f58577a62b779a539271f4f8641e7a957d115c39 | |
parent | 45960c90302bb60a22e11a779d866b9eed909c33 (diff) | |
download | php-git-2188f26c45375358ac872a61b6de76fc85b83be4.tar.gz |
Fixed bug #52614 (Memory leak when writing on uninitialized variable returned from method call)
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | Zend/tests/bug52614.phpt | 83 | ||||
-rw-r--r-- | Zend/zend_compile.c | 53 | ||||
-rw-r--r-- | Zend/zend_language_parser.y | 6 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 21 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 46 | ||||
-rw-r--r-- | Zend/zend_vm_opcodes.h | 1 |
7 files changed, 199 insertions, 13 deletions
@@ -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) diff --git a/Zend/tests/bug52614.phpt b/Zend/tests/bug52614.phpt new file mode 100644 index 0000000000..38a210b9a9 --- /dev/null +++ b/Zend/tests/bug52614.phpt @@ -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) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 66fdec13f1..4720dec1e4 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -550,6 +550,14 @@ int zend_add_const_name_literal(zend_op_array *op_array, const zval *zv, int unq 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 @@ void fetch_array_dim(znode *result, const znode *parent, const znode *dim TSRMLS 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 @@ void fetch_array_dim(znode *result, const znode *parent, const znode *dim TSRMLS 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 @@ void zend_do_assign(znode *result, znode *variable, znode *value TSRMLS_DC) /* { } /* }}} */ -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 @@ void zend_do_end_variable_parse(znode *variable, int type, int arg_offset TSRMLS 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 @@ void zend_do_fetch_property(znode *result, znode *object, const znode *property } } + 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 @@ void zend_do_foreach_cont(znode *foreach_token, const znode *open_brackets_token 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); diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 5e448462a0..6d2432eaea 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -932,7 +932,7 @@ variable_property: 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: ; 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 @@ variable_class_name: 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); } ; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index bae4c995ff..9b274cc615 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -4998,4 +4998,25 @@ ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED) 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) diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 3b07493c52..4da5485d37 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -18807,6 +18807,27 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_VAR_UNUSED_HANDLER(ZEND_OP 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 @@ void zend_init_opcodes_handlers(void) 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; diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index 7cd8add0f8..4cd1ac4346 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -156,3 +156,4 @@ #define ZEND_DECLARE_LAMBDA_FUNCTION 153 #define ZEND_ADD_TRAIT 154 #define ZEND_BIND_TRAITS 155 +#define ZEND_SEPARATE 156 |