From: Dmitry Stogov Date: Mon, 30 Jun 2014 10:17:17 +0000 (+0400) Subject: Fixed support for extra arguments in conjunction with variadiv argument. X-Git-Tag: POST_PHPNG_MERGE~90^2~11 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3f0ee308a04819f520c861b8edb34703eabf377c;p=php Fixed support for extra arguments in conjunction with variadiv argument. Use compile time flags to check if we call constructor and result of ZEND_NEW is used or not. --- diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index d084c564e7..df81c5d666 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -409,7 +409,7 @@ ZEND_FUNCTION(func_num_args) Get the $arg_num'th argument that was passed to the function */ ZEND_FUNCTION(func_get_arg) { - int arg_count; + int arg_count, first_extra_arg; zval *arg; long requested_offset; zend_execute_data *ex; @@ -436,8 +436,12 @@ ZEND_FUNCTION(func_get_arg) RETURN_FALSE; } - if (requested_offset >= ex->func->op_array.num_args && (ex->num_args > ex->func->op_array.num_args)) { - arg = EX_VAR_NUM_2(ex, ex->func->op_array.last_var + ex->func->op_array.T) + (requested_offset - ex->func->op_array.num_args); + first_extra_arg = ex->func->op_array.num_args; + if (ex->func->op_array.fn_flags & ZEND_ACC_VARIADIC) { + first_extra_arg--; + } + if (requested_offset >= first_extra_arg && (ex->num_args > first_extra_arg)) { + arg = EX_VAR_NUM_2(ex, ex->func->op_array.last_var + ex->func->op_array.T) + (requested_offset - first_extra_arg); } else { arg = ZEND_CALL_ARG(ex, requested_offset + 1); } @@ -450,7 +454,7 @@ ZEND_FUNCTION(func_get_arg) ZEND_FUNCTION(func_get_args) { zval *p; - int arg_count; + int arg_count, first_extra_arg; int i; zend_execute_data *ex = EG(current_execute_data); @@ -465,12 +469,16 @@ ZEND_FUNCTION(func_get_args) if (arg_count) { Bucket *q; + first_extra_arg = ex->func->op_array.num_args; + if (ex->func->op_array.fn_flags & ZEND_ACC_VARIADIC) { + first_extra_arg--; + } zend_hash_real_init(Z_ARRVAL_P(return_value), 1); i = 0; q = Z_ARRVAL_P(return_value)->arData; p = ZEND_CALL_ARG(ex, 1); - if (ex->num_args > ex->func->op_array.num_args) { - while (i < ex->func->op_array.num_args) { + if (ex->num_args > first_extra_arg) { + while (i < first_extra_arg) { q->h = i; q->key = NULL; if (!Z_ISREF_P(p)) { @@ -1985,14 +1993,21 @@ static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array TS int i = 0; zval *p = ZEND_CALL_ARG(call, 1); - if (call->func->type == ZEND_USER_FUNCTION && (call->num_args > call->func->op_array.num_args)) { - while (i < call->func->op_array.num_args) { - if (Z_REFCOUNTED_P(p)) Z_ADDREF_P(p); - zend_hash_next_index_insert_new(Z_ARRVAL_P(arg_array), p); - p++; - i++; + if (call->func->type == ZEND_USER_FUNCTION) { + int first_extra_arg = call->func->op_array.num_args; + + if (call->func->op_array.fn_flags & ZEND_ACC_VARIADIC) { + first_extra_arg--; + } + if (call->num_args > first_extra_arg) { + while (i < first_extra_arg) { + if (Z_REFCOUNTED_P(p)) Z_ADDREF_P(p); + zend_hash_next_index_insert_new(Z_ARRVAL_P(arg_array), p); + p++; + i++; + } + p = EX_VAR_NUM_2(call, call->func->op_array.last_var + call->func->op_array.T); } - p = EX_VAR_NUM_2(call, call->func->op_array.last_var + call->func->op_array.T); } while (i < num_args) { diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 0434e7c754..a49195d407 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1461,6 +1461,11 @@ void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */ && opline->result.var == op1->u.op.var) { if (opline->opcode == ZEND_NEW) { opline->result_type |= EXT_TYPE_UNUSED; + opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1]; + while (opline->opcode != ZEND_DO_FCALL || opline->op1.num != ZEND_CALL_CTOR) { + opline--; + } + opline->op1.num |= ZEND_CALL_CTOR_RESULT_UNUSED; } break; } @@ -2544,13 +2549,20 @@ void zend_do_end_function_call(znode *function_name, znode *result, int is_metho } opline = &CG(active_op_array)->opcodes[Z_LVAL(function_name->u.constant)]; } else { + zend_uint call_flags = 0; + opline = &CG(active_op_array)->opcodes[fcall->op_number]; opline->extended_value = fcall->arg_num; + if (opline->opcode == ZEND_NEW) { + call_flags = ZEND_CALL_CTOR; + } + opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_DO_FCALL; SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); + opline->op1.num = call_flags; } opline->result.var = get_temporary_variable(CG(active_op_array)); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 5c4aae7fbb..b053ee9820 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -379,7 +379,7 @@ struct _zend_execute_data { }; #define ZEND_CALL_CTOR (1 << 0) -#define ZEND_CALL_CTOR_RESULT_USED (1 << 1) +#define ZEND_CALL_CTOR_RESULT_UNUSED (1 << 1) #define ZEND_CALL_DONE (1 << 2) #define ZEND_CALL_FRAME_SLOT \ @@ -741,7 +741,6 @@ int zend_add_literal(zend_op_array *op_array, zval *zv TSRMLS_DC); #define ZEND_PARSED_NEW (1<<6) #define ZEND_PARSED_LIST_EXPR (1<<7) - /* unset types */ #define ZEND_UNSET_REG 0 diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 7e94642aa8..5318bbe2d3 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1556,18 +1556,22 @@ static zend_always_inline void i_init_execute_data(zend_execute_data *execute_da EG(opline_ptr) = &EX(opline); EX(opline) = UNEXPECTED((op_array->fn_flags & ZEND_ACC_INTERACTIVE) != 0) && EG(start_op) ? EG(start_op) : op_array->opcodes; -//??? EX(func) = (zend_function*)op_array; EX(scope) = EG(scope); EX(symbol_table) = EG(active_symbol_table); if (UNEXPECTED(EX(symbol_table) != NULL)) { zend_attach_symbol_table(execute_data); } else { - - if (UNEXPECTED(EX(num_args) > op_array->num_args)) { + zend_uint first_extra_arg = op_array->num_args; + + if (UNEXPECTED((op_array->fn_flags & ZEND_ACC_VARIADIC) != 0)) { + first_extra_arg--; + } + if (UNEXPECTED(EX(num_args) > first_extra_arg)) { /* move extra args into separate array after all CV and TMP vars */ zval *extra_args = EX_VAR_NUM(op_array->last_var + op_array->T); - memmove(extra_args, EX_VAR_NUM(op_array->num_args), sizeof(zval) * (EX(num_args) - op_array->num_args)); + + memmove(extra_args, EX_VAR_NUM(first_extra_arg), sizeof(zval) * (EX(num_args) - first_extra_arg)); } do { diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 9202262189..40f42ae2dd 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -211,7 +211,7 @@ static zend_always_inline void zend_vm_stack_extend(int count TSRMLS_DC) EG(argument_stack) = p; } -static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(zend_function *func, zend_uint num_args, zend_uint flags, zend_class_entry *called_scope, zend_object *object, zend_execute_data *prev TSRMLS_DC) +static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(zend_function *func, zend_uint num_args, zend_uchar flags, zend_class_entry *called_scope, zend_object *object, zend_execute_data *prev TSRMLS_DC) { int used_stack = ZEND_CALL_FRAME_SLOT + num_args; zend_execute_data *call; @@ -223,7 +223,7 @@ static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(zend_ call = (zend_execute_data*)EG(argument_stack)->top; EG(argument_stack)->top += used_stack; call->func = func; - call->num_args = 0; //??? num_args; + call->num_args = 0; call->flags = flags; call->called_scope = called_scope; call->object = object; @@ -233,9 +233,11 @@ static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(zend_ static zend_always_inline void zend_vm_stack_free_extra_args(zend_execute_data *call TSRMLS_DC) { - if (UNEXPECTED(call->num_args > call->func->op_array.num_args)) { + zend_uint first_extra_arg = call->func->op_array.num_args - ((call->func->common.fn_flags & ZEND_ACC_VARIADIC) != 0); + + if (UNEXPECTED(call->num_args > first_extra_arg)) { zval *end = EX_VAR_NUM_2(call, call->func->op_array.last_var + call->func->op_array.T); - zval *p = end + (call->num_args - call->func->op_array.num_args); + zval *p = end + (call->num_args - first_extra_arg); do { p--; i_zval_ptr_dtor_nogc(p ZEND_FILE_LINE_CC TSRMLS_CC); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 2a9af52d67..54a33fe1af 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1773,7 +1773,6 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) { vm_frame_kind frame_kind = EX(frame_kind); zend_execute_data *prev_nested_call; - zend_uint call_flags; EG(current_execute_data) = EX(prev_execute_data); @@ -1785,7 +1784,6 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_CLOSURE) != 0) && EX(func)->op_array.prototype) { zval_ptr_dtor((zval*)EX(func)->op_array.prototype); } - call_flags = EX(flags); prev_nested_call = EX(prev_nested_call); zend_vm_stack_free_extra_args(execute_data TSRMLS_CC); zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); @@ -1797,8 +1795,8 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) EG(active_symbol_table) = EX(symbol_table); if (Z_OBJ(EG(This))) { - if (UNEXPECTED(EG(exception) != NULL) && (call_flags & ZEND_CALL_CTOR)) { - if (call_flags & ZEND_CALL_CTOR_RESULT_USED) { + if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) { + if (!(EX(opline)->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) { Z_DELREF(EG(This)); } if (Z_REFCOUNT(EG(This)) == 1) { @@ -2576,10 +2574,9 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) USE_OPLINE zend_execute_data *call = EX(call); zend_function *fbc = call->func; - zend_uint call_flags = call->flags; SAVE_OPLINE(); - call->flags |= ZEND_CALL_DONE; + call->flags = ZEND_CALL_DONE; if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name->val, fbc->common.function_name->val); @@ -2753,8 +2750,8 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) ZEND_VM_C_LABEL(fcall_end_change_scope): if (Z_OBJ(EG(This))) { - if (UNEXPECTED(EG(exception) != NULL) && (call_flags & ZEND_CALL_CTOR)) { - if (call_flags & ZEND_CALL_CTOR_RESULT_USED) { + if (UNEXPECTED(EG(exception) != NULL) && (opline->op1.num & ZEND_CALL_CTOR)) { + if (!(opline->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) { Z_DELREF(EG(This)); } if (Z_REFCOUNT(EG(This)) == 1) { @@ -3343,31 +3340,23 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, ANY, ANY) params = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); if (arg_num <= arg_count) { - zval *param, tmp; + zval *param; - ZVAL_COPY_VALUE(&tmp, params); array_init_size(params, arg_count - arg_num + 1); param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T); if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zend_verify_arg_type(EX(func), arg_num, &tmp, opline->extended_value TSRMLS_CC); - zend_hash_next_index_insert_new(Z_ARRVAL_P(params), &tmp); - if (param) { - while (++arg_num <= arg_count) { - zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); - zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); - if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); - param++; - } - } + do { + zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); + zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); + if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); + param++; + } while (++arg_num <= arg_count); } else { - zend_hash_next_index_insert_new(Z_ARRVAL_P(params), &tmp); - if (param) { - while (++arg_num <= arg_count) { - zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); - if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); - param++; - } - } + do { + zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); + if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); + param++; + } while (++arg_num <= arg_count); } } else { array_init(params); @@ -3495,7 +3484,7 @@ ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY) EX(call) = zend_vm_stack_push_call_frame( constructor, opline->extended_value, RETURN_VALUE_USED(opline) ? - (ZEND_CALL_CTOR | ZEND_CALL_CTOR_RESULT_USED) : ZEND_CALL_CTOR, + ZEND_CALL_CTOR : (ZEND_CALL_CTOR | ZEND_CALL_CTOR_RESULT_UNUSED), Z_CE_P(EX_VAR(opline->op1.var)), Z_OBJ(object_zval), EX(call) TSRMLS_CC); @@ -5177,7 +5166,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) if (call->object) { if (call->flags & ZEND_CALL_CTOR) { - if (call->flags & ZEND_CALL_CTOR_RESULT_USED) { + if (!(call->flags & ZEND_CALL_CTOR_RESULT_UNUSED)) { GC_REFCOUNT(call->object)--; } if (GC_REFCOUNT(call->object) == 1) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 80aefc1d7f..6f87261b55 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -396,7 +396,6 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) { vm_frame_kind frame_kind = EX(frame_kind); zend_execute_data *prev_nested_call; - zend_uint call_flags; EG(current_execute_data) = EX(prev_execute_data); @@ -408,7 +407,6 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_CLOSURE) != 0) && EX(func)->op_array.prototype) { zval_ptr_dtor((zval*)EX(func)->op_array.prototype); } - call_flags = EX(flags); prev_nested_call = EX(prev_nested_call); zend_vm_stack_free_extra_args(execute_data TSRMLS_CC); zend_vm_stack_free_call_frame(execute_data TSRMLS_CC); @@ -420,8 +418,8 @@ static int ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) EG(active_symbol_table) = EX(symbol_table); if (Z_OBJ(EG(This))) { - if (UNEXPECTED(EG(exception) != NULL) && (call_flags & ZEND_CALL_CTOR)) { - if (call_flags & ZEND_CALL_CTOR_RESULT_USED) { + if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) { + if (!(EX(opline)->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) { Z_DELREF(EG(This)); } if (Z_REFCOUNT(EG(This)) == 1) { @@ -528,10 +526,9 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) USE_OPLINE zend_execute_data *call = EX(call); zend_function *fbc = call->func; - zend_uint call_flags = call->flags; SAVE_OPLINE(); - call->flags |= ZEND_CALL_DONE; + call->flags = ZEND_CALL_DONE; if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name->val, fbc->common.function_name->val); @@ -705,8 +702,8 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) fcall_end_change_scope: if (Z_OBJ(EG(This))) { - if (UNEXPECTED(EG(exception) != NULL) && (call_flags & ZEND_CALL_CTOR)) { - if (call_flags & ZEND_CALL_CTOR_RESULT_USED) { + if (UNEXPECTED(EG(exception) != NULL) && (opline->op1.num & ZEND_CALL_CTOR)) { + if (!(opline->op1.num & ZEND_CALL_CTOR_RESULT_UNUSED)) { Z_DELREF(EG(This)); } if (Z_REFCOUNT(EG(This)) == 1) { @@ -945,31 +942,23 @@ static int ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR params = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC); if (arg_num <= arg_count) { - zval *param, tmp; + zval *param; - ZVAL_COPY_VALUE(&tmp, params); array_init_size(params, arg_count - arg_num + 1); param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T); if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zend_verify_arg_type(EX(func), arg_num, &tmp, opline->extended_value TSRMLS_CC); - zend_hash_next_index_insert_new(Z_ARRVAL_P(params), &tmp); - if (param) { - while (++arg_num <= arg_count) { - zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); - zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); - if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); - param++; - } - } + do { + zend_verify_arg_type(EX(func), arg_num, param, opline->extended_value TSRMLS_CC); + zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); + if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); + param++; + } while (++arg_num <= arg_count); } else { - zend_hash_next_index_insert_new(Z_ARRVAL_P(params), &tmp); - if (param) { - while (++arg_num <= arg_count) { - zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); - if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); - param++; - } - } + do { + zend_hash_next_index_insert_new(Z_ARRVAL_P(params), param); + if (Z_REFCOUNTED_P(param)) Z_ADDREF_P(param); + param++; + } while (++arg_num <= arg_count); } } else { array_init(params); @@ -1010,7 +999,7 @@ static int ZEND_FASTCALL ZEND_NEW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) EX(call) = zend_vm_stack_push_call_frame( constructor, opline->extended_value, RETURN_VALUE_USED(opline) ? - (ZEND_CALL_CTOR | ZEND_CALL_CTOR_RESULT_USED) : ZEND_CALL_CTOR, + ZEND_CALL_CTOR : (ZEND_CALL_CTOR | ZEND_CALL_CTOR_RESULT_UNUSED), Z_CE_P(EX_VAR(opline->op1.var)), Z_OBJ(object_zval), EX(call) TSRMLS_CC); @@ -1246,7 +1235,7 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER if (call->object) { if (call->flags & ZEND_CALL_CTOR) { - if (call->flags & ZEND_CALL_CTOR_RESULT_USED) { + if (!(call->flags & ZEND_CALL_CTOR_RESULT_UNUSED)) { GC_REFCOUNT(call->object)--; } if (GC_REFCOUNT(call->object) == 1) {