Fixed bug #52614 (Memory leak when writing on uninitialized variable returned from method call)

This commit is contained in:
Dmitry Stogov 2010-08-25 09:14:36 +00:00
parent 45960c9030
commit 2188f26c45
7 changed files with 199 additions and 13 deletions

2
NEWS
View File

@ -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)

83
Zend/tests/bug52614.phpt Normal file
View File

@ -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)

View File

@ -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);

View File

@ -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); }
;

View File

@ -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)

View File

@ -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;

View File

@ -156,3 +156,4 @@
#define ZEND_DECLARE_LAMBDA_FUNCTION 153
#define ZEND_ADD_TRAIT 154
#define ZEND_BIND_TRAITS 155
#define ZEND_SEPARATE 156