From 8ee605d8c346d4ba94a68c3402f4680851eb02e0 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 25 Feb 2013 16:40:37 +0100 Subject: [PATCH 1/4] Allow (...)->foo() type expressions not only for `new` --- Zend/zend_language_parser.y | 5 +- Zend/zend_vm_def.h | 10 +- Zend/zend_vm_execute.h | 1206 ++++++++++++++++++++++++++++++- tests/lang/clone_expr_call.phpt | 25 + 4 files changed, 1210 insertions(+), 36 deletions(-) create mode 100644 tests/lang/clone_expr_call.phpt diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index ccbc9b174c9d..7057e1f12093 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -50,7 +50,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %} %pure_parser -%expect 3 +%expect 2 %token END 0 "end of file" %left T_INCLUDE T_INCLUDE_ONCE T_EVAL T_REQUIRE T_REQUIRE_ONCE @@ -783,9 +783,8 @@ expr_without_variable: | expr '>' expr { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$3, &$1 TSRMLS_CC); } | expr T_IS_GREATER_OR_EQUAL expr { zend_do_binary_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$3, &$1 TSRMLS_CC); } | expr T_INSTANCEOF class_name_reference { zend_do_instanceof(&$$, &$1, &$3, 0 TSRMLS_CC); } - | parenthesis_expr { $$ = $1; } + | parenthesis_expr { $$ = $1; } instance_call { $$ = $3; } | new_expr { $$ = $1; } - | '(' new_expr ')' { $$ = $2; } instance_call { $$ = $5; } | expr '?' { zend_do_begin_qm_op(&$1, &$2 TSRMLS_CC); } expr ':' { zend_do_qm_true(&$4, &$2, &$5 TSRMLS_CC); } expr { zend_do_qm_false(&$$, &$7, &$2, &$5 TSRMLS_CC); } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 0aaed2e465a8..a85648f06466 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1248,7 +1248,7 @@ ZEND_VM_HANDLER(87, ZEND_FETCH_DIM_RW, VAR|CV, CONST|TMP|VAR|UNUSED|CV) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(90, ZEND_FETCH_DIM_IS, VAR|CV, CONST|TMP|VAR|CV) +ZEND_VM_HANDLER(90, ZEND_FETCH_DIM_IS, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; @@ -1334,7 +1334,7 @@ ZEND_VM_HANDLER(96, ZEND_FETCH_DIM_UNSET, VAR|CV, CONST|TMP|VAR|CV) } } -ZEND_VM_HELPER(zend_fetch_property_address_read_helper, VAR|UNUSED|CV, CONST|TMP|VAR|CV) +ZEND_VM_HELPER(zend_fetch_property_address_read_helper, CONST|TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) { USE_OPLINE zend_free_op free_op1; @@ -1377,7 +1377,7 @@ ZEND_VM_HELPER(zend_fetch_property_address_read_helper, VAR|UNUSED|CV, CONST|TMP ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(82, ZEND_FETCH_OBJ_R, VAR|UNUSED|CV, CONST|TMP|VAR|CV) +ZEND_VM_HANDLER(82, ZEND_FETCH_OBJ_R, CONST|TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) { ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_property_address_read_helper); } @@ -1462,7 +1462,7 @@ ZEND_VM_HANDLER(88, ZEND_FETCH_OBJ_RW, VAR|UNUSED|CV, CONST|TMP|VAR|CV) ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(91, ZEND_FETCH_OBJ_IS, VAR|UNUSED|CV, CONST|TMP|VAR|CV) +ZEND_VM_HANDLER(91, ZEND_FETCH_OBJ_IS, CONST|TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) { USE_OPLINE zend_free_op free_op1; @@ -2421,7 +2421,7 @@ ZEND_VM_HANDLER(109, ZEND_FETCH_CLASS, ANY, CONST|TMP|VAR|UNUSED|CV) } } -ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) +ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) { USE_OPLINE zval *function_name; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 2fe18fbceec7..81711bc4c32b 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3515,6 +3515,109 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_ ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval **container; + + SAVE_OPLINE(); + container = NULL; + zend_fetch_dimension_address_read(&EX_T(opline->result.var), container, opline->op2.zv, IS_CONST, BP_VAR_IS TSRMLS_CC); + + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_CONST_CONST(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = opline->op2.zv; + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + zend_error(E_NOTICE, "Trying to get property of non-object"); + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + + } else { + zval *retval; + + if (0) { + MAKE_REAL_ZVAL_PTR(offset); + } + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_R, ((IS_CONST == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); + + PZVAL_LOCK(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); + + if (0) { + zval_ptr_dtor(&offset); + } else { + + } + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + return zend_fetch_property_address_read_helper_SPEC_CONST_CONST(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = opline->op2.zv; + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + + } else { + zval *retval; + + if (0) { + MAKE_REAL_ZVAL_PTR(offset); + } + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_IS, ((IS_CONST == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); + + PZVAL_LOCK(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); + + if (0) { + zval_ptr_dtor(&offset); + } else { + + } + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_FETCH_DIM_TMP_VAR_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -3539,6 +3642,85 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_TMP_VAR_SPEC_CONST_CONST_HANDLER(ZEND_O ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *function_name; + char *function_name_strval; + int function_name_strlen; + + call_slot *call = EX(call_slots) + opline->result.num; + + SAVE_OPLINE(); + + function_name = opline->op2.zv; + + if (IS_CONST != IS_CONST && + UNEXPECTED(Z_TYPE_P(function_name) != IS_STRING)) { + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Method name must be a string"); + } + + function_name_strval = Z_STRVAL_P(function_name); + function_name_strlen = Z_STRLEN_P(function_name); + + call->object = opline->op1.zv; + + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); + + if (IS_CONST != IS_CONST || + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; + + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); + } + if (IS_CONST == IS_CONST && + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); + } + } + } else { + if (UNEXPECTED(EG(exception) != NULL)) { + + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + } + + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; + } else { + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ + } else { + zval *this_ptr; + ALLOC_ZVAL(this_ptr); + INIT_PZVAL_COPY(this_ptr, call->object); + zval_copy_ctor(this_ptr); + call->object = this_ptr; + } + } + call->is_ctor_call = 0; + EX(call) = call; + + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -4532,6 +4714,189 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HA ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op2; + zval **container; + + SAVE_OPLINE(); + container = NULL; + zend_fetch_dimension_address_read(&EX_T(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR, BP_VAR_IS TSRMLS_CC); + zval_dtor(free_op2.var); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_CONST_TMP(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + zend_free_op free_op2; + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + zend_error(E_NOTICE, "Trying to get property of non-object"); + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + zval_dtor(free_op2.var); + } else { + zval *retval; + + if (1) { + MAKE_REAL_ZVAL_PTR(offset); + } + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_R, ((IS_TMP_VAR == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); + + PZVAL_LOCK(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); + + if (1) { + zval_ptr_dtor(&offset); + } else { + zval_dtor(free_op2.var); + } + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + return zend_fetch_property_address_read_helper_SPEC_CONST_TMP(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + zend_free_op free_op2; + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + zval_dtor(free_op2.var); + } else { + zval *retval; + + if (1) { + MAKE_REAL_ZVAL_PTR(offset); + } + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_IS, ((IS_TMP_VAR == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); + + PZVAL_LOCK(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); + + if (1) { + zval_ptr_dtor(&offset); + } else { + zval_dtor(free_op2.var); + } + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *function_name; + char *function_name_strval; + int function_name_strlen; + zend_free_op free_op2; + call_slot *call = EX(call_slots) + opline->result.num; + + SAVE_OPLINE(); + + function_name = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (IS_TMP_VAR != IS_CONST && + UNEXPECTED(Z_TYPE_P(function_name) != IS_STRING)) { + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Method name must be a string"); + } + + function_name_strval = Z_STRVAL_P(function_name); + function_name_strlen = Z_STRLEN_P(function_name); + + call->object = opline->op1.zv; + + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); + + if (IS_TMP_VAR != IS_CONST || + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; + + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_TMP_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); + } + if (IS_TMP_VAR == IS_CONST && + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); + } + } + } else { + if (UNEXPECTED(EG(exception) != NULL)) { + zval_dtor(free_op2.var); + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + } + + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; + } else { + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ + } else { + zval *this_ptr; + ALLOC_ZVAL(this_ptr); + INIT_PZVAL_COPY(this_ptr, call->object); + zval_copy_ctor(this_ptr); + call->object = this_ptr; + } + } + call->is_ctor_call = 0; + EX(call) = call; + + zval_dtor(free_op2.var); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -5394,6 +5759,189 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HA ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op2; + zval **container; + + SAVE_OPLINE(); + container = NULL; + zend_fetch_dimension_address_read(&EX_T(opline->result.var), container, _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR, BP_VAR_IS TSRMLS_CC); + if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_CONST_VAR(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + zend_free_op free_op2; + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + zend_error(E_NOTICE, "Trying to get property of non-object"); + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; + } else { + zval *retval; + + if (0) { + MAKE_REAL_ZVAL_PTR(offset); + } + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_R, ((IS_VAR == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); + + PZVAL_LOCK(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); + + if (0) { + zval_ptr_dtor(&offset); + } else { + if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; + } + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + return zend_fetch_property_address_read_helper_SPEC_CONST_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + zend_free_op free_op2; + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; + } else { + zval *retval; + + if (0) { + MAKE_REAL_ZVAL_PTR(offset); + } + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_IS, ((IS_VAR == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); + + PZVAL_LOCK(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); + + if (0) { + zval_ptr_dtor(&offset); + } else { + if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; + } + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *function_name; + char *function_name_strval; + int function_name_strlen; + zend_free_op free_op2; + call_slot *call = EX(call_slots) + opline->result.num; + + SAVE_OPLINE(); + + function_name = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (IS_VAR != IS_CONST && + UNEXPECTED(Z_TYPE_P(function_name) != IS_STRING)) { + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Method name must be a string"); + } + + function_name_strval = Z_STRVAL_P(function_name); + function_name_strlen = Z_STRLEN_P(function_name); + + call->object = opline->op1.zv; + + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); + + if (IS_VAR != IS_CONST || + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; + + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_VAR == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); + } + if (IS_VAR == IS_CONST && + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); + } + } + } else { + if (UNEXPECTED(EG(exception) != NULL)) { + if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + } + + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; + } else { + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ + } else { + zval *this_ptr; + ALLOC_ZVAL(this_ptr); + INIT_PZVAL_COPY(this_ptr, call->object); + zval_copy_ctor(this_ptr); + call->object = this_ptr; + } + } + call->is_ctor_call = 0; + EX(call) = call; + + if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -6971,6 +7519,188 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HAN ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval **container; + + SAVE_OPLINE(); + container = NULL; + zend_fetch_dimension_address_read(&EX_T(opline->result.var), container, _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV, BP_VAR_IS TSRMLS_CC); + + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_CONST_CV(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + zend_error(E_NOTICE, "Trying to get property of non-object"); + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + + } else { + zval *retval; + + if (0) { + MAKE_REAL_ZVAL_PTR(offset); + } + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_R, ((IS_CV == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); + + PZVAL_LOCK(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); + + if (0) { + zval_ptr_dtor(&offset); + } else { + + } + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + return zend_fetch_property_address_read_helper_SPEC_CONST_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *container; + + zval *offset; + + SAVE_OPLINE(); + container = opline->op1.zv; + offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + + } else { + zval *retval; + + if (0) { + MAKE_REAL_ZVAL_PTR(offset); + } + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_IS, ((IS_CV == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); + + PZVAL_LOCK(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); + + if (0) { + zval_ptr_dtor(&offset); + } else { + + } + } + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *function_name; + char *function_name_strval; + int function_name_strlen; + + call_slot *call = EX(call_slots) + opline->result.num; + + SAVE_OPLINE(); + + function_name = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + + if (IS_CV != IS_CONST && + UNEXPECTED(Z_TYPE_P(function_name) != IS_STRING)) { + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Method name must be a string"); + } + + function_name_strval = Z_STRVAL_P(function_name); + function_name_strlen = Z_STRLEN_P(function_name); + + call->object = opline->op1.zv; + + if (EXPECTED(call->object != NULL) && + EXPECTED(Z_TYPE_P(call->object) == IS_OBJECT)) { + call->called_scope = Z_OBJCE_P(call->object); + + if (IS_CV != IS_CONST || + (call->fbc = CACHED_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope)) == NULL) { + zval *object = call->object; + + if (UNEXPECTED(Z_OBJ_HT_P(call->object)->get_method == NULL)) { + zend_error_noreturn(E_ERROR, "Object does not support method calls"); + } + + /* First, locate the function. */ + call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_CV == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(call->fbc == NULL)) { + zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(call->object), function_name_strval); + } + if (IS_CV == IS_CONST && + EXPECTED(call->fbc->type <= ZEND_USER_FUNCTION) && + EXPECTED((call->fbc->common.fn_flags & (ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_NEVER_CACHE)) == 0) && + EXPECTED(call->object == object)) { + CACHE_POLYMORPHIC_PTR(opline->op2.literal->cache_slot, call->called_scope, call->fbc); + } + } + } else { + if (UNEXPECTED(EG(exception) != NULL)) { + + HANDLE_EXCEPTION(); + } + zend_error_noreturn(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval); + } + + if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { + call->object = NULL; + } else { + if (!PZVAL_IS_REF(call->object)) { + Z_ADDREF_P(call->object); /* For $this pointer */ + } else { + zval *this_ptr; + ALLOC_ZVAL(this_ptr); + INIT_PZVAL_COPY(this_ptr, call->object); + zval_copy_ctor(this_ptr); + call->object = this_ptr; + } + } + call->is_ctor_call = 0; + EX(call) = call; + + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -8889,6 +9619,111 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HA ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval **container; + + SAVE_OPLINE(); + container = NULL; + zend_fetch_dimension_address_read(&EX_T(opline->result.var), container, opline->op2.zv, IS_CONST, BP_VAR_IS TSRMLS_CC); + + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_TMP_CONST(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = opline->op2.zv; + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + zend_error(E_NOTICE, "Trying to get property of non-object"); + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + + } else { + zval *retval; + + if (0) { + MAKE_REAL_ZVAL_PTR(offset); + } + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_R, ((IS_CONST == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); + + PZVAL_LOCK(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); + + if (0) { + zval_ptr_dtor(&offset); + } else { + + } + } + + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + return zend_fetch_property_address_read_helper_SPEC_TMP_CONST(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = opline->op2.zv; + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + + } else { + zval *retval; + + if (0) { + MAKE_REAL_ZVAL_PTR(offset); + } + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_IS, ((IS_CONST == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); + + PZVAL_LOCK(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); + + if (0) { + zval_ptr_dtor(&offset); + } else { + + } + } + + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_FETCH_DIM_TMP_VAR_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -9775,6 +10610,111 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HAND ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op2; + zval **container; + + SAVE_OPLINE(); + container = NULL; + zend_fetch_dimension_address_read(&EX_T(opline->result.var), container, _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_TMP_VAR, BP_VAR_IS TSRMLS_CC); + zval_dtor(free_op2.var); + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_TMP_TMP(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + zend_free_op free_op2; + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + zend_error(E_NOTICE, "Trying to get property of non-object"); + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + zval_dtor(free_op2.var); + } else { + zval *retval; + + if (1) { + MAKE_REAL_ZVAL_PTR(offset); + } + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_R, ((IS_TMP_VAR == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); + + PZVAL_LOCK(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); + + if (1) { + zval_ptr_dtor(&offset); + } else { + zval_dtor(free_op2.var); + } + } + + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + return zend_fetch_property_address_read_helper_SPEC_TMP_TMP(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + zend_free_op free_op2; + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + zval_dtor(free_op2.var); + } else { + zval *retval; + + if (1) { + MAKE_REAL_ZVAL_PTR(offset); + } + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_IS, ((IS_TMP_VAR == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); + + PZVAL_LOCK(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); + + if (1) { + zval_ptr_dtor(&offset); + } else { + zval_dtor(free_op2.var); + } + } + + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_ADD_VAR_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -10641,6 +11581,111 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HAND ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op2; + zval **container; + + SAVE_OPLINE(); + container = NULL; + zend_fetch_dimension_address_read(&EX_T(opline->result.var), container, _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC), IS_VAR, BP_VAR_IS TSRMLS_CC); + if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_TMP_VAR(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + zend_free_op free_op2; + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + zend_error(E_NOTICE, "Trying to get property of non-object"); + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; + } else { + zval *retval; + + if (0) { + MAKE_REAL_ZVAL_PTR(offset); + } + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_R, ((IS_VAR == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); + + PZVAL_LOCK(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); + + if (0) { + zval_ptr_dtor(&offset); + } else { + if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; + } + } + + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + return zend_fetch_property_address_read_helper_SPEC_TMP_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + zend_free_op free_op2; + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; + } else { + zval *retval; + + if (0) { + MAKE_REAL_ZVAL_PTR(offset); + } + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_IS, ((IS_VAR == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); + + PZVAL_LOCK(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); + + if (0) { + zval_ptr_dtor(&offset); + } else { + if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; + } + } + + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_ADD_VAR_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -12083,6 +13128,111 @@ static int ZEND_FASTCALL ZEND_FETCH_DIM_R_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDL ZEND_VM_NEXT_OPCODE(); } +static int ZEND_FASTCALL ZEND_FETCH_DIM_IS_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval **container; + + SAVE_OPLINE(); + container = NULL; + zend_fetch_dimension_address_read(&EX_T(opline->result.var), container, _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC), IS_CV, BP_VAR_IS TSRMLS_CC); + + + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL zend_fetch_property_address_read_helper_SPEC_TMP_CV(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + zend_error(E_NOTICE, "Trying to get property of non-object"); + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + + } else { + zval *retval; + + if (0) { + MAKE_REAL_ZVAL_PTR(offset); + } + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_R, ((IS_CV == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); + + PZVAL_LOCK(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); + + if (0) { + zval_ptr_dtor(&offset); + } else { + + } + } + + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + return zend_fetch_property_address_read_helper_SPEC_TMP_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +} + +static int ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *container; + + zval *offset; + + SAVE_OPLINE(); + container = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); + offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + + } else { + zval *retval; + + if (0) { + MAKE_REAL_ZVAL_PTR(offset); + } + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_IS, ((IS_CV == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); + + PZVAL_LOCK(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); + + if (0) { + zval_ptr_dtor(&offset); + } else { + + } + } + + zval_dtor(free_op1.var); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); +} + static int ZEND_FASTCALL ZEND_ADD_VAR_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -43016,16 +44166,16 @@ void zend_init_opcodes_handlers(void) ZEND_FETCH_DIM_R_SPEC_CV_VAR_HANDLER, ZEND_NULL_HANDLER, ZEND_FETCH_DIM_R_SPEC_CV_CV_HANDLER, + ZEND_FETCH_OBJ_R_SPEC_CONST_CONST_HANDLER, + ZEND_FETCH_OBJ_R_SPEC_CONST_TMP_HANDLER, + ZEND_FETCH_OBJ_R_SPEC_CONST_VAR_HANDLER, ZEND_NULL_HANDLER, + ZEND_FETCH_OBJ_R_SPEC_CONST_CV_HANDLER, + ZEND_FETCH_OBJ_R_SPEC_TMP_CONST_HANDLER, + ZEND_FETCH_OBJ_R_SPEC_TMP_TMP_HANDLER, + ZEND_FETCH_OBJ_R_SPEC_TMP_VAR_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_FETCH_OBJ_R_SPEC_TMP_CV_HANDLER, ZEND_FETCH_OBJ_R_SPEC_VAR_CONST_HANDLER, ZEND_FETCH_OBJ_R_SPEC_VAR_TMP_HANDLER, ZEND_FETCH_OBJ_R_SPEC_VAR_VAR_HANDLER, @@ -43216,16 +44366,16 @@ void zend_init_opcodes_handlers(void) ZEND_FETCH_IS_SPEC_CV_VAR_HANDLER, ZEND_FETCH_IS_SPEC_CV_UNUSED_HANDLER, ZEND_NULL_HANDLER, + ZEND_FETCH_DIM_IS_SPEC_CONST_CONST_HANDLER, + ZEND_FETCH_DIM_IS_SPEC_CONST_TMP_HANDLER, + ZEND_FETCH_DIM_IS_SPEC_CONST_VAR_HANDLER, ZEND_NULL_HANDLER, + ZEND_FETCH_DIM_IS_SPEC_CONST_CV_HANDLER, + ZEND_FETCH_DIM_IS_SPEC_TMP_CONST_HANDLER, + ZEND_FETCH_DIM_IS_SPEC_TMP_TMP_HANDLER, + ZEND_FETCH_DIM_IS_SPEC_TMP_VAR_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_FETCH_DIM_IS_SPEC_TMP_CV_HANDLER, ZEND_FETCH_DIM_IS_SPEC_VAR_CONST_HANDLER, ZEND_FETCH_DIM_IS_SPEC_VAR_TMP_HANDLER, ZEND_FETCH_DIM_IS_SPEC_VAR_VAR_HANDLER, @@ -43241,16 +44391,16 @@ void zend_init_opcodes_handlers(void) ZEND_FETCH_DIM_IS_SPEC_CV_VAR_HANDLER, ZEND_NULL_HANDLER, ZEND_FETCH_DIM_IS_SPEC_CV_CV_HANDLER, + ZEND_FETCH_OBJ_IS_SPEC_CONST_CONST_HANDLER, + ZEND_FETCH_OBJ_IS_SPEC_CONST_TMP_HANDLER, + ZEND_FETCH_OBJ_IS_SPEC_CONST_VAR_HANDLER, ZEND_NULL_HANDLER, + ZEND_FETCH_OBJ_IS_SPEC_CONST_CV_HANDLER, + ZEND_FETCH_OBJ_IS_SPEC_TMP_CONST_HANDLER, + ZEND_FETCH_OBJ_IS_SPEC_TMP_TMP_HANDLER, + ZEND_FETCH_OBJ_IS_SPEC_TMP_VAR_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_FETCH_OBJ_IS_SPEC_TMP_CV_HANDLER, ZEND_FETCH_OBJ_IS_SPEC_VAR_CONST_HANDLER, ZEND_FETCH_OBJ_IS_SPEC_VAR_TMP_HANDLER, ZEND_FETCH_OBJ_IS_SPEC_VAR_VAR_HANDLER, @@ -43766,11 +44916,11 @@ void zend_init_opcodes_handlers(void) ZEND_RETURN_BY_REF_SPEC_CV_HANDLER, ZEND_RETURN_BY_REF_SPEC_CV_HANDLER, ZEND_RETURN_BY_REF_SPEC_CV_HANDLER, + ZEND_INIT_METHOD_CALL_SPEC_CONST_CONST_HANDLER, + ZEND_INIT_METHOD_CALL_SPEC_CONST_TMP_HANDLER, + ZEND_INIT_METHOD_CALL_SPEC_CONST_VAR_HANDLER, ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, - ZEND_NULL_HANDLER, + ZEND_INIT_METHOD_CALL_SPEC_CONST_CV_HANDLER, ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER, ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER, ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER, diff --git a/tests/lang/clone_expr_call.phpt b/tests/lang/clone_expr_call.phpt new file mode 100644 index 000000000000..50850598ac57 --- /dev/null +++ b/tests/lang/clone_expr_call.phpt @@ -0,0 +1,25 @@ +--TEST-- +Test call on a clone expression in parentheses +--FILE-- +bar = 'bar'; + } + + public function bar() { + return $this->bar; + } +} + +$foo = new Foo; +var_dump((clone $foo)->bar); +var_dump((clone $foo)->bar()); + +?> +--EXPECT-- +string(3) "bar" +string(3) "bar" From 178c80170cc2ffc872f5b6516a1395028b10fb84 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Fri, 8 Mar 2013 17:00:48 +0800 Subject: [PATCH 2/4] Implements function chained call --- Zend/tests/closure_047.phpt | 25 +++++++++++ Zend/tests/function_chain_call_001.phpt | 31 ++++++++++++++ Zend/tests/instance_invoke_001.phpt | 31 ++++++++++++++ Zend/tests/instance_invoke_002.phpt | 13 ++++++ Zend/tests/instance_invoke_003.phpt | 27 ++++++++++++ Zend/zend_language_parser.y | 18 +++++--- Zend/zend_vm_def.h | 14 +++++-- Zend/zend_vm_execute.h | 56 +++++++++++++++++++------ 8 files changed, 194 insertions(+), 21 deletions(-) create mode 100644 Zend/tests/closure_047.phpt create mode 100644 Zend/tests/function_chain_call_001.phpt create mode 100644 Zend/tests/instance_invoke_001.phpt create mode 100644 Zend/tests/instance_invoke_002.phpt create mode 100644 Zend/tests/instance_invoke_003.phpt diff --git a/Zend/tests/closure_047.phpt b/Zend/tests/closure_047.phpt new file mode 100644 index 000000000000..9c607c71c982 --- /dev/null +++ b/Zend/tests/closure_047.phpt @@ -0,0 +1,25 @@ +--TEST-- +Closure 046: Closure instance call +--FILE-- +bindTo(new Stdclass()))(); + +((function() { + return function() { + var_dump(123); + }; +})())(); + +?> +--EXPECTF-- +string(9) "{closure}" +object(stdClass)#3 (0) { +} +int(123) diff --git a/Zend/tests/function_chain_call_001.phpt b/Zend/tests/function_chain_call_001.phpt new file mode 100644 index 000000000000..6ab62aec2820 --- /dev/null +++ b/Zend/tests/function_chain_call_001.phpt @@ -0,0 +1,31 @@ +--TEST-- +function chained call +--FILE-- +dummy(); +var_dump((new Foo())->var); +var_dump((new Foo())->noexists); + +--EXPECT-- +string(10) "Foo::dummy" +string(3) "foo" +string(8) "noexists" diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 7057e1f12093..49bb0122e92c 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -733,6 +733,15 @@ new_expr: T_NEW class_name_reference { zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$1, &$2 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$$, &$1, &$4 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} ; +lambda_function: + function is_reference { zend_do_begin_lambda_function_declaration(&$$, &$1, $2.op_type, 0 TSRMLS_CC); } + '(' parameter_list ')' lexical_vars + '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); $$ = $3; } + | T_STATIC function is_reference { zend_do_begin_lambda_function_declaration(&$$, &$2, $3.op_type, 1 TSRMLS_CC); } + '(' parameter_list ')' lexical_vars + '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); $$ = $4; } + + expr_without_variable: T_LIST '(' { zend_do_list_init(TSRMLS_C); } assignment_list ')' '=' expr { zend_do_list_end(&$$, &$7 TSRMLS_CC); } | variable '=' expr { zend_check_writable_variable(&$1); zend_do_assign(&$$, &$1, &$3 TSRMLS_CC); } @@ -806,12 +815,7 @@ expr_without_variable: | '`' backticks_expr '`' { zend_do_shell_exec(&$$, &$2 TSRMLS_CC); } | T_PRINT expr { zend_do_print(&$$, &$2 TSRMLS_CC); } | T_YIELD { zend_do_yield(&$$, NULL, NULL, 0 TSRMLS_CC); } - | function is_reference { zend_do_begin_lambda_function_declaration(&$$, &$1, $2.op_type, 0 TSRMLS_CC); } - '(' parameter_list ')' lexical_vars - '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); $$ = $3; } - | T_STATIC function is_reference { zend_do_begin_lambda_function_declaration(&$$, &$2, $3.op_type, 1 TSRMLS_CC); } - '(' parameter_list ')' lexical_vars - '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); $$ = $4; } + | lambda_function { $$ = $1; } ; yield_expr: @@ -863,6 +867,8 @@ function_call: function_call_parameter_list { zend_do_end_function_call(NULL, &$$, &$5, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} | variable_without_objects { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_dynamic_function_call(&$1, 0 TSRMLS_CC); } function_call_parameter_list { zend_do_end_function_call(&$1, &$$, &$3, 0, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} + | parenthesis_expr { zend_do_begin_variable_parse(TSRMLS_C); zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_dynamic_function_call(&$1, 0 TSRMLS_CC); } + function_call_parameter_list { zend_do_end_function_call(&$1, &$$, &$3, 0, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } ; class_name: diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index a85648f06466..8de7c38b060f 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2673,18 +2673,26 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); - } else if (OP2_TYPE != IS_CONST && OP2_TYPE != IS_TMP_VAR && + } else if (OP2_TYPE != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { if (call->object) { - Z_ADDREF_P(call->object); + if (OP2_TYPE == IS_TMP_VAR && + call->object == function_name) { + zval *obj; + ALLOC_ZVAL(obj); + INIT_PZVAL_COPY(obj, call->object); + call->object = obj; + } else { + Z_ADDREF_P(call->object); + } } if (OP2_TYPE == IS_VAR && OP2_FREE && call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ call->fbc->common.prototype = (zend_function*)function_name; - } else { + } else if (OP2_TYPE != IS_TMP_VAR) { FREE_OP2(); } call->is_ctor_call = 0; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 81711bc4c32b..c08c11f281d3 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1256,18 +1256,26 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); - } else if (IS_CONST != IS_CONST && IS_CONST != IS_TMP_VAR && + } else if (IS_CONST != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { if (call->object) { - Z_ADDREF_P(call->object); + if (IS_CONST == IS_TMP_VAR && + call->object == function_name) { + zval *obj; + ALLOC_ZVAL(obj); + INIT_PZVAL_COPY(obj, call->object); + call->object = obj; + } else { + Z_ADDREF_P(call->object); + } } if (IS_CONST == IS_VAR && 0 && call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ call->fbc->common.prototype = (zend_function*)function_name; - } else { + } else if (IS_CONST != IS_TMP_VAR) { } call->is_ctor_call = 0; @@ -1583,18 +1591,26 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); - } else if (IS_TMP_VAR != IS_CONST && IS_TMP_VAR != IS_TMP_VAR && + } else if (IS_TMP_VAR != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { if (call->object) { - Z_ADDREF_P(call->object); + if (IS_TMP_VAR == IS_TMP_VAR && + call->object == function_name) { + zval *obj; + ALLOC_ZVAL(obj); + INIT_PZVAL_COPY(obj, call->object); + call->object = obj; + } else { + Z_ADDREF_P(call->object); + } } if (IS_TMP_VAR == IS_VAR && 1 && call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ call->fbc->common.prototype = (zend_function*)function_name; - } else { + } else if (IS_TMP_VAR != IS_TMP_VAR) { zval_dtor(free_op2.var); } call->is_ctor_call = 0; @@ -1770,18 +1786,26 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); - } else if (IS_VAR != IS_CONST && IS_VAR != IS_TMP_VAR && + } else if (IS_VAR != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { if (call->object) { - Z_ADDREF_P(call->object); + if (IS_VAR == IS_TMP_VAR && + call->object == function_name) { + zval *obj; + ALLOC_ZVAL(obj); + INIT_PZVAL_COPY(obj, call->object); + call->object = obj; + } else { + Z_ADDREF_P(call->object); + } } if (IS_VAR == IS_VAR && (free_op2.var != NULL) && call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ call->fbc->common.prototype = (zend_function*)function_name; - } else { + } else if (IS_VAR != IS_TMP_VAR) { if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; } call->is_ctor_call = 0; @@ -1995,18 +2019,26 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA EX(call) = call; CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); - } else if (IS_CV != IS_CONST && IS_CV != IS_TMP_VAR && + } else if (IS_CV != IS_CONST && EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { if (call->object) { - Z_ADDREF_P(call->object); + if (IS_CV == IS_TMP_VAR && + call->object == function_name) { + zval *obj; + ALLOC_ZVAL(obj); + INIT_PZVAL_COPY(obj, call->object); + call->object = obj; + } else { + Z_ADDREF_P(call->object); + } } if (IS_CV == IS_VAR && 0 && call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ call->fbc->common.prototype = (zend_function*)function_name; - } else { + } else if (IS_CV != IS_TMP_VAR) { } call->is_ctor_call = 0; From 98a36c853a14abe873753b5ac5e7e2d5e6538640 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 9 Mar 2013 10:45:26 +0800 Subject: [PATCH 3/4] Fix invalid free --- Zend/zend_vm_def.h | 4 ++- Zend/zend_vm_execute.h | 80 +++++++++++++++++++++++++++++++----------- 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 8de7c38b060f..597ac447bb76 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2482,7 +2482,9 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMP|VAR|UNUSED|CV, CONST|TMP|V if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (IS_OP1_TMP_FREE()) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index c08c11f281d3..8597cbfe0b0e 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3735,7 +3735,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_CONST_HANDLER(ZEND_OP if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (0) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -4910,7 +4912,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_TMP_HANDLER(ZEND_OPCO if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (0) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -5955,7 +5959,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_VAR_HANDLER(ZEND_OPCO if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (0) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -7715,7 +7721,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CONST_CV_HANDLER(ZEND_OPCOD if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (0) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -9887,7 +9895,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CONST_HANDLER(ZEND_OPCO if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (1) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -10853,7 +10863,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (1) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -11824,7 +11836,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (1) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -13370,7 +13384,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_ if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (1) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -16609,7 +16625,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CONST_HANDLER(ZEND_OPCO if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (0) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -18960,7 +18978,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (0) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -21276,7 +21296,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (0) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -24730,7 +24752,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_ if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (0) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -26369,7 +26393,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CONST_HANDLER(ZEND_O if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (0) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -27784,7 +27810,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_TMP_HANDLER(ZEND_OPC if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (0) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -29105,7 +29133,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_VAR_HANDLER(ZEND_OPC if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (0) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -30847,7 +30877,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_CV_HANDLER(ZEND_OPCO if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (0) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -34089,7 +34121,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCOD if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (0) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -36209,7 +36243,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_ if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (0) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -38388,7 +38424,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_ if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (0) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; @@ -41559,7 +41597,9 @@ static int ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HANDLER(ZEND_OPCODE_H if ((call->fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) { call->object = NULL; } else { - if (!PZVAL_IS_REF(call->object)) { + if (0) { + MAKE_REAL_ZVAL_PTR(call->object); + } else if (!PZVAL_IS_REF(call->object)) { Z_ADDREF_P(call->object); /* For $this pointer */ } else { zval *this_ptr; From 95bce5e2c93c35d174cd937b8c46861fdc010874 Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Sat, 9 Mar 2013 11:10:19 +0800 Subject: [PATCH 4/4] better macros --- Zend/zend_vm_def.h | 9 +++------ Zend/zend_vm_execute.h | 36 ++++++++++++------------------------ 2 files changed, 15 insertions(+), 30 deletions(-) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 597ac447bb76..7e4ffcbf0f19 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2680,12 +2680,9 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) Z_OBJ_HANDLER_P(function_name, get_closure) && Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { if (call->object) { - if (OP2_TYPE == IS_TMP_VAR && + if (IS_OP2_TMP_FREE() && call->object == function_name) { - zval *obj; - ALLOC_ZVAL(obj); - INIT_PZVAL_COPY(obj, call->object); - call->object = obj; + MAKE_REAL_ZVAL_PTR(call->object); } else { Z_ADDREF_P(call->object); } @@ -2694,7 +2691,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ call->fbc->common.prototype = (zend_function*)function_name; - } else if (OP2_TYPE != IS_TMP_VAR) { + } else if (!IS_OP2_TMP_FREE()) { FREE_OP2(); } call->is_ctor_call = 0; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 8597cbfe0b0e..ace43104fcb2 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1261,12 +1261,9 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE Z_OBJ_HANDLER_P(function_name, get_closure) && Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { if (call->object) { - if (IS_CONST == IS_TMP_VAR && + if (0 && call->object == function_name) { - zval *obj; - ALLOC_ZVAL(obj); - INIT_PZVAL_COPY(obj, call->object); - call->object = obj; + MAKE_REAL_ZVAL_PTR(call->object); } else { Z_ADDREF_P(call->object); } @@ -1275,7 +1272,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ call->fbc->common.prototype = (zend_function*)function_name; - } else if (IS_CONST != IS_TMP_VAR) { + } else if (!0) { } call->is_ctor_call = 0; @@ -1596,12 +1593,9 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H Z_OBJ_HANDLER_P(function_name, get_closure) && Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { if (call->object) { - if (IS_TMP_VAR == IS_TMP_VAR && + if (1 && call->object == function_name) { - zval *obj; - ALLOC_ZVAL(obj); - INIT_PZVAL_COPY(obj, call->object); - call->object = obj; + MAKE_REAL_ZVAL_PTR(call->object); } else { Z_ADDREF_P(call->object); } @@ -1610,7 +1604,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_TMP_HANDLER(ZEND_OPCODE_H call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ call->fbc->common.prototype = (zend_function*)function_name; - } else if (IS_TMP_VAR != IS_TMP_VAR) { + } else if (!1) { zval_dtor(free_op2.var); } call->is_ctor_call = 0; @@ -1791,12 +1785,9 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H Z_OBJ_HANDLER_P(function_name, get_closure) && Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { if (call->object) { - if (IS_VAR == IS_TMP_VAR && + if (0 && call->object == function_name) { - zval *obj; - ALLOC_ZVAL(obj); - INIT_PZVAL_COPY(obj, call->object); - call->object = obj; + MAKE_REAL_ZVAL_PTR(call->object); } else { Z_ADDREF_P(call->object); } @@ -1805,7 +1796,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_VAR_HANDLER(ZEND_OPCODE_H call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ call->fbc->common.prototype = (zend_function*)function_name; - } else if (IS_VAR != IS_TMP_VAR) { + } else if (!0) { if (free_op2.var) {zval_ptr_dtor(&free_op2.var);}; } call->is_ctor_call = 0; @@ -2024,12 +2015,9 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA Z_OBJ_HANDLER_P(function_name, get_closure) && Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &call->called_scope, &call->fbc, &call->object TSRMLS_CC) == SUCCESS) { if (call->object) { - if (IS_CV == IS_TMP_VAR && + if (0 && call->object == function_name) { - zval *obj; - ALLOC_ZVAL(obj); - INIT_PZVAL_COPY(obj, call->object); - call->object = obj; + MAKE_REAL_ZVAL_PTR(call->object); } else { Z_ADDREF_P(call->object); } @@ -2038,7 +2026,7 @@ static int ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CV_HANDLER(ZEND_OPCODE_HA call->fbc->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ call->fbc->common.prototype = (zend_function*)function_name; - } else if (IS_CV != IS_TMP_VAR) { + } else if (!0) { } call->is_ctor_call = 0;