From 79d6f11a4a3f6da55fa05b156fe8ff8accc3ff06 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 5 May 2005 17:37:25 +0000 Subject: [PATCH] Fixed bug #31525 (object reference being dropped. $this getting lost) --- Zend/tests/bug31525.phpt | 22 +++++++++++++ Zend/zend_compile.c | 18 +++++++---- Zend/zend_vm_def.h | 14 +++++++- Zend/zend_vm_execute.h | 70 +++++++++++++++++++++++++++++++++++++--- tests/lang/bug20175.phpt | 7 ++-- tests/lang/bug21600.phpt | 9 ++++-- 6 files changed, 123 insertions(+), 17 deletions(-) create mode 100755 Zend/tests/bug31525.phpt diff --git a/Zend/tests/bug31525.phpt b/Zend/tests/bug31525.phpt new file mode 100755 index 0000000000..b1a01b61ef --- /dev/null +++ b/Zend/tests/bug31525.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #31525 (object reference being dropped. $this getting lost) +--INI-- +error_reporting=4095 +--FILE-- +getThis(); + } +} +$bar = new Foo(); +$bar->destroyThis(); +var_dump($bar); +?> +--EXPECTF-- +Strict Standards: Only variables should be assigned by reference in %sbug31525.php on line 7 +object(Foo)#1 (0) { +} diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index de876333d0..3f79e44eb3 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -562,6 +562,12 @@ void zend_do_assign(znode *result, znode *variable, znode *value TSRMLS_DC) } } +static inline zend_bool zend_is_function_or_method_call(znode *variable) +{ + zend_uint type = variable->u.EA.type; + + return ((type & ZEND_PARSED_METHOD_CALL) || (type == ZEND_PARSED_FUNCTION_CALL)); +} void zend_do_assign_ref(znode *result, znode *lvar, znode *rvar TSRMLS_DC) { @@ -573,6 +579,11 @@ void zend_do_assign_ref(znode *result, znode *lvar, znode *rvar TSRMLS_DC) if (opline_is_fetch_this(last_op TSRMLS_CC)) { zend_error(E_COMPILE_ERROR, "Cannot re-assign $this"); } + if (zend_is_function_or_method_call(rvar)) { + opline->extended_value = ZEND_RETURNS_FUNCTION; + } else { + opline->extended_value = 0; + } if (result) { opline->result.op_type = IS_VAR; opline->result.u.EA.type = 0; @@ -796,13 +807,6 @@ void zend_check_writable_variable(znode *variable) } } -static inline zend_bool zend_is_function_or_method_call(znode *variable) -{ - zend_uint type = variable->u.EA.type; - - return ((type & ZEND_PARSED_METHOD_CALL) || (type == ZEND_PARSED_FUNCTION_CALL)); -} - void zend_do_begin_variable_parse(TSRMLS_D) { zend_llist fetch_list; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 638cec2b37..8f4681306c 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1329,9 +1329,21 @@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV) { zend_op *opline = EX(opline); zend_free_op free_op1, free_op2; - zval **variable_ptr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); + zval **variable_ptr_ptr; zval **value_ptr_ptr = GET_OP2_ZVAL_PTR_PTR(BP_VAR_W); + if (OP2_TYPE == IS_VAR && + !(*value_ptr_ptr)->is_ref && + opline->extended_value == ZEND_RETURNS_FUNCTION && + !EX_T(opline->op2.u.var).var.fcall_returned_reference) { + zend_error(E_STRICT, "Only variables should be assigned by reference"); + if (free_op2.var == NULL) { + PZVAL_LOCK(*value_ptr_ptr); /* undo the effect of get_zval_ptr_ptr() */ + } + ZEND_VM_DISPATCH_TO_HANDLER(ZEND_ASSIGN); + } + + variable_ptr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC); if (!RETURN_VALUE_UNUSED(&opline->result)) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 13ecdab0d9..773e31b19b 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -11505,9 +11505,21 @@ static int ZEND_ASSIGN_REF_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); zend_free_op free_op1, free_op2; - zval **variable_ptr_ptr = _get_zval_ptr_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); + zval **variable_ptr_ptr; zval **value_ptr_ptr = _get_zval_ptr_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); + if (IS_VAR == IS_VAR && + !(*value_ptr_ptr)->is_ref && + opline->extended_value == ZEND_RETURNS_FUNCTION && + !EX_T(opline->op2.u.var).var.fcall_returned_reference) { + zend_error(E_STRICT, "Only variables should be assigned by reference"); + if (free_op2.var == NULL) { + PZVAL_LOCK(*value_ptr_ptr); /* undo the effect of get_zval_ptr_ptr() */ + } + return ZEND_ASSIGN_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } + + variable_ptr_ptr = _get_zval_ptr_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC); if (!RETURN_VALUE_UNUSED(&opline->result)) { @@ -13267,9 +13279,21 @@ static int ZEND_ASSIGN_REF_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); zend_free_op free_op1, free_op2; - zval **variable_ptr_ptr = _get_zval_ptr_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); + zval **variable_ptr_ptr; zval **value_ptr_ptr = _get_zval_ptr_ptr_cv(&opline->op2, EX(Ts), &free_op2, BP_VAR_W TSRMLS_CC); + if (IS_CV == IS_VAR && + !(*value_ptr_ptr)->is_ref && + opline->extended_value == ZEND_RETURNS_FUNCTION && + !EX_T(opline->op2.u.var).var.fcall_returned_reference) { + zend_error(E_STRICT, "Only variables should be assigned by reference"); + if (free_op2.var == NULL) { + PZVAL_LOCK(*value_ptr_ptr); /* undo the effect of get_zval_ptr_ptr() */ + } + return ZEND_ASSIGN_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } + + variable_ptr_ptr = _get_zval_ptr_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC); zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC); if (!RETURN_VALUE_UNUSED(&opline->result)) { @@ -22945,9 +22969,21 @@ static int ZEND_ASSIGN_REF_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); zend_free_op free_op1, free_op2; - zval **variable_ptr_ptr = _get_zval_ptr_ptr_cv(&opline->op1, EX(Ts), &free_op1, BP_VAR_W TSRMLS_CC); + zval **variable_ptr_ptr; zval **value_ptr_ptr = _get_zval_ptr_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC); + if (IS_VAR == IS_VAR && + !(*value_ptr_ptr)->is_ref && + opline->extended_value == ZEND_RETURNS_FUNCTION && + !EX_T(opline->op2.u.var).var.fcall_returned_reference) { + zend_error(E_STRICT, "Only variables should be assigned by reference"); + if (free_op2.var == NULL) { + PZVAL_LOCK(*value_ptr_ptr); /* undo the effect of get_zval_ptr_ptr() */ + } + return ZEND_ASSIGN_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } + + variable_ptr_ptr = _get_zval_ptr_ptr_cv(&opline->op1, EX(Ts), &free_op1, BP_VAR_W TSRMLS_CC); zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC); if (!RETURN_VALUE_UNUSED(&opline->result)) { @@ -24707,9 +24743,21 @@ static int ZEND_ASSIGN_REF_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); zend_free_op free_op1, free_op2; - zval **variable_ptr_ptr = _get_zval_ptr_ptr_cv(&opline->op1, EX(Ts), &free_op1, BP_VAR_W TSRMLS_CC); + zval **variable_ptr_ptr; zval **value_ptr_ptr = _get_zval_ptr_ptr_cv(&opline->op2, EX(Ts), &free_op2, BP_VAR_W TSRMLS_CC); + if (IS_CV == IS_VAR && + !(*value_ptr_ptr)->is_ref && + opline->extended_value == ZEND_RETURNS_FUNCTION && + !EX_T(opline->op2.u.var).var.fcall_returned_reference) { + zend_error(E_STRICT, "Only variables should be assigned by reference"); + if (free_op2.var == NULL) { + PZVAL_LOCK(*value_ptr_ptr); /* undo the effect of get_zval_ptr_ptr() */ + } + return ZEND_ASSIGN_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } + + variable_ptr_ptr = _get_zval_ptr_ptr_cv(&opline->op1, EX(Ts), &free_op1, BP_VAR_W TSRMLS_CC); zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC); if (!RETURN_VALUE_UNUSED(&opline->result)) { @@ -30271,9 +30319,21 @@ static int ZEND_ASSIGN_REF_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { zend_op *opline = EX(opline); zend_free_op free_op1, free_op2; - zval **variable_ptr_ptr = get_zval_ptr_ptr(&opline->op1, EX(Ts), &free_op1, BP_VAR_W); + zval **variable_ptr_ptr; zval **value_ptr_ptr = get_zval_ptr_ptr(&opline->op2, EX(Ts), &free_op2, BP_VAR_W); + if (opline->op2.op_type == IS_VAR && + !(*value_ptr_ptr)->is_ref && + opline->extended_value == ZEND_RETURNS_FUNCTION && + !EX_T(opline->op2.u.var).var.fcall_returned_reference) { + zend_error(E_STRICT, "Only variables should be assigned by reference"); + if (free_op2.var == NULL) { + PZVAL_LOCK(*value_ptr_ptr); /* undo the effect of get_zval_ptr_ptr() */ + } + return ZEND_ASSIGN_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } + + variable_ptr_ptr = get_zval_ptr_ptr(&opline->op1, EX(Ts), &free_op1, BP_VAR_W); zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC); if (!RETURN_VALUE_UNUSED(&opline->result)) { diff --git a/tests/lang/bug20175.phpt b/tests/lang/bug20175.phpt index 55ff7d82b8..d2248e6f0e 100644 --- a/tests/lang/bug20175.phpt +++ b/tests/lang/bug20175.phpt @@ -2,6 +2,8 @@ Bug #20175 (Static vars can't store ref to new instance) --SKIPIF-- +--INI-- +error_reporting=4095 --FILE-- ---EXPECT-- +--EXPECTF-- +Strict Standards: Only variables should be assigned by reference in %sbug21600.php on line 4 array(1) { ["foo"]=> - &string(4) "test" + string(4) "test" } + +Strict Standards: Only variables should be assigned by reference in %sbug21600.php on line 11 array(1) { ["foo"]=> string(4) "test" -- 2.50.1