diff options
Diffstat (limited to 'Zend/zend_compile.c')
-rw-r--r-- | Zend/zend_compile.c | 102 |
1 files changed, 64 insertions, 38 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 625957f74a..8df612e18b 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -97,6 +97,13 @@ ZEND_API zend_compiler_globals compiler_globals; ZEND_API zend_executor_globals executor_globals; #endif +static void zend_push_function_call_entry(zend_function *fbc TSRMLS_DC) /* {{{ */ +{ + zend_function_call_entry fcall = { fbc }; + zend_stack_push(&CG(function_call_stack), &fcall, sizeof(zend_function_call_entry)); +} +/* }}} */ + static void zend_duplicate_property_info(zend_property_info *property_info) /* {{{ */ { STR_ADDREF(property_info->name); @@ -1611,6 +1618,11 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static"); } + + } else if ((name->len == sizeof(ZEND_DEBUGINFO_FUNC_NAME)-1) && (!memcmp(lcname->val, ZEND_DEBUGINFO_FUNC_NAME, sizeof(ZEND_DEBUGINFO_FUNC_NAME)-1))) { + if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { + zend_error(E_WARNING, "The magic method __debugInfo() must have public visibility and cannot be static"); + } } } else { char *class_lcname; @@ -1671,6 +1683,11 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { zend_error(E_WARNING, "The magic method __invoke() must have public visibility and cannot be static"); } + } else if ((name->len == sizeof(ZEND_DEBUGINFO_FUNC_NAME)-1) && (!memcmp(lcname->val, ZEND_DEBUGINFO_FUNC_NAME, sizeof(ZEND_DEBUGINFO_FUNC_NAME)-1))) { + if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) { + zend_error(E_WARNING, "The magic method __debugInfo() must have public visibility and cannot be static"); + } + CG(active_class_entry)->__debugInfo = (zend_function *) CG(active_op_array); } else if (!(fn_flags & ZEND_ACC_STATIC)) { CG(active_op_array)->fn_flags |= ZEND_ACC_ALLOW_STATIC; } @@ -1981,7 +1998,7 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace STR_RELEASE(Z_STR(function_name->u.constant)); Z_STR(function_name->u.constant) = lcname; - zend_stack_push(&CG(function_call_stack), (void *) &function, sizeof(zend_function *)); + zend_push_function_call_entry(function TSRMLS_CC); if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) { CG(active_op_array)->nested_calls = CG(context).nested_calls + 1; } @@ -1994,7 +2011,6 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */ { zend_op *last_op; int last_op_number; - unsigned char *ptr = NULL; zend_do_end_variable_parse(left_bracket, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_variable_parse(TSRMLS_C); @@ -2038,7 +2054,7 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */ } } - zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); + zend_push_function_call_entry(NULL TSRMLS_CC); if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { CG(active_op_array)->nested_calls = CG(context).nested_calls; } @@ -2061,7 +2077,6 @@ void zend_do_clone(znode *result, znode *expr TSRMLS_DC) /* {{{ */ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRMLS_DC) /* {{{ */ { - unsigned char *ptr = NULL; zend_op *opline; opline = get_next_op(CG(active_op_array) TSRMLS_CC); @@ -2087,7 +2102,7 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int ns_call TSRML } } - zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); + zend_push_function_call_entry(NULL TSRMLS_CC); if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { CG(active_op_array)->nested_calls = CG(context).nested_calls; } @@ -2489,7 +2504,6 @@ void zend_do_build_full_name(znode *result, znode *prefix, znode *name, int is_c int zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC) /* {{{ */ { znode class_node; - unsigned char *ptr = NULL; zend_op *opline; if (method_name->op_type == IS_CONST) { @@ -2538,7 +2552,7 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na SET_NODE(opline->op2, method_name); } - zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); + zend_push_function_call_entry(NULL TSRMLS_CC); if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { CG(active_op_array)->nested_calls = CG(context).nested_calls; } @@ -2547,22 +2561,21 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na } /* }}} */ -void zend_do_end_function_call(znode *function_name, znode *result, const znode *argument_list, int is_method, int is_dynamic_fcall TSRMLS_DC) /* {{{ */ +void zend_do_end_function_call(znode *function_name, znode *result, int is_method, int is_dynamic_fcall TSRMLS_DC) /* {{{ */ { zend_op *opline; + zend_function_call_entry *fcall; + zend_stack_top(&CG(function_call_stack), (void **) &fcall); if (is_method && function_name && function_name->op_type == IS_UNUSED) { /* clone */ - if (Z_LVAL(argument_list->u.constant) != 0) { + if (fcall->arg_num != 0) { zend_error(E_WARNING, "Clone method does not require arguments"); } opline = &CG(active_op_array)->opcodes[Z_LVAL(function_name->u.constant)]; } else { - zend_function **function_ptr_ptr; - zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr); - opline = get_next_op(CG(active_op_array) TSRMLS_CC); - if (*function_ptr_ptr) { + if (fcall->fbc) { opline->opcode = ZEND_DO_FCALL; SET_NODE(opline->op1, function_name); SET_UNUSED(opline->op2); @@ -2586,33 +2599,39 @@ void zend_do_end_function_call(znode *function_name, znode *result, const znode opline->result.var = get_temporary_variable(CG(active_op_array)); opline->result_type = IS_VAR; GET_NODE(result, opline->result); - - zend_stack_del_top(&CG(function_call_stack)); - opline->extended_value = Z_LVAL(argument_list->u.constant); + opline->extended_value = fcall->arg_num; if (CG(context).used_stack + 1 > CG(active_op_array)->used_stack) { CG(active_op_array)->used_stack = CG(context).used_stack + 1; } - CG(context).used_stack -= Z_LVAL(argument_list->u.constant); + CG(context).used_stack -= fcall->arg_num; + zend_stack_del_top(&CG(function_call_stack)); } /* }}} */ -void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{{ */ +void zend_do_pass_param(znode *param, zend_uchar op TSRMLS_DC) /* {{{ */ { zend_op *opline; int original_op = op; - zend_function **function_ptr_ptr, *function_ptr; + zend_function_call_entry *fcall; + zend_function *function_ptr; int send_by_reference = 0; int send_function = 0; - zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr); - function_ptr = *function_ptr_ptr; + zend_stack_top(&CG(function_call_stack), (void **) &fcall); + function_ptr = fcall->fbc; + fcall->arg_num++; + + if (fcall->uses_argument_unpacking) { + zend_error_noreturn(E_COMPILE_ERROR, + "Cannot use positional argument after argument unpacking"); + } if (original_op == ZEND_SEND_REF) { if (function_ptr && function_ptr->common.function_name && function_ptr->common.type == ZEND_USER_FUNCTION && - !ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) { + !ARG_SHOULD_BE_SENT_BY_REF(function_ptr, fcall->arg_num)) { zend_error_noreturn(E_COMPILE_ERROR, "Call-time pass-by-reference has been removed; " "If you would like to pass argument by reference, modify the declaration of %s().", @@ -2624,7 +2643,7 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{ } if (function_ptr) { - if (ARG_MAY_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) { + if (ARG_MAY_BE_SENT_BY_REF(function_ptr, fcall->arg_num)) { if (op == ZEND_SEND_VAR && param->op_type & (IS_VAR|IS_CV)) { send_by_reference = ZEND_ARG_SEND_BY_REF; if (zend_is_function_or_method_call(param)) { @@ -2635,7 +2654,7 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{ } else { op = ZEND_SEND_VAL; } - } else if (ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) { + } else if (ARG_SHOULD_BE_SENT_BY_REF(function_ptr, fcall->arg_num)) { send_by_reference = ZEND_ARG_SEND_BY_REF; } } @@ -2670,7 +2689,7 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{ if (function_ptr) { zend_do_end_variable_parse(param, BP_VAR_R, 0 TSRMLS_CC); } else { - zend_do_end_variable_parse(param, BP_VAR_FUNC_ARG, offset TSRMLS_CC); + zend_do_end_variable_parse(param, BP_VAR_FUNC_ARG, fcall->arg_num TSRMLS_CC); } break; case ZEND_SEND_REF: @@ -2696,7 +2715,7 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{ } opline->opcode = op; SET_NODE(opline->op1, param); - opline->op2.opline_num = offset; + opline->op2.opline_num = fcall->arg_num; SET_UNUSED(opline->op2); if (++CG(context).used_stack > CG(active_op_array)->used_stack) { @@ -2705,18 +2724,20 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{ } /* }}} */ -void zend_do_unpack_params(znode *params, int offset TSRMLS_DC) /* {{{ */ +void zend_do_unpack_params(znode *params TSRMLS_DC) /* {{{ */ { zend_op *opline; - zend_function **function_ptr_ptr; + zend_function_call_entry *fcall; - zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr); - if (*function_ptr_ptr) { + zend_stack_top(&CG(function_call_stack), (void **) &fcall); + fcall->uses_argument_unpacking = 1; + + if (fcall->fbc) { /* If argument unpacking is used argument numbers and sending modes can no longer be * computed at compile time, thus we need access to EX(call). In order to have it we * retroactively emit a ZEND_INIT_FCALL_BY_NAME opcode. */ zval func_name; - ZVAL_STR(&func_name, STR_COPY((*function_ptr_ptr)->common.function_name)); + ZVAL_STR(&func_name, STR_COPY(fcall->fbc->common.function_name)); opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_INIT_FCALL_BY_NAME; @@ -2727,14 +2748,14 @@ void zend_do_unpack_params(znode *params, int offset TSRMLS_DC) /* {{{ */ GET_CACHE_SLOT(opline->op2.constant); ++CG(context).nested_calls; - *function_ptr_ptr = NULL; + fcall->fbc = NULL; } opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_SEND_UNPACK; SET_NODE(opline->op1, params); SET_UNUSED(opline->op2); - opline->op2.num = (zend_uint) offset; + opline->op2.num = fcall->arg_num; } /* }}} */ @@ -3134,6 +3155,9 @@ static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */ if (!ce->destructor) { ce->destructor = ce->parent->destructor; } + if (!ce->__debugInfo) { + ce->__debugInfo = ce->parent->__debugInfo; + } if (ce->constructor) { if (ce->parent->constructor && ce->parent->constructor->common.fn_flags & ZEND_ACC_FINAL) { zend_error(E_ERROR, "Cannot override final %s::%s() with %s::%s()", @@ -3469,7 +3493,7 @@ static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{ zval zv; ZVAL_DUP(&zv, precv->op2.zv); - zval_update_constant_ex(&zv, (void*)1, fptr->common.scope TSRMLS_CC); + zval_update_constant_ex(&zv, 1, fptr->common.scope TSRMLS_CC); if (Z_TYPE(zv) == IS_BOOL) { if (Z_LVAL(zv)) { memcpy(offset, "true", 4); @@ -4006,6 +4030,8 @@ static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zen ce->__callstatic = fe; } else if (!strncmp(mname->val, ZEND_TOSTRING_FUNC_NAME, mname->len)) { ce->__tostring = fe; + } else if (!strncmp(mname->val, ZEND_DEBUGINFO_FUNC_NAME, mname->len)) { + ce->__debugInfo = fe; } else if (ce->name->len == mname->len) { zend_string *lowercase_name = STR_ALLOC(ce->name->len, 0); zend_str_tolower_copy(lowercase_name->val, ce->name->val, ce->name->len); @@ -5602,7 +5628,6 @@ void zend_do_pop_object(znode *object TSRMLS_DC) /* {{{ */ void zend_do_begin_new_object(znode *new_token, znode *class_type TSRMLS_DC) /* {{{ */ { zend_op *opline; - unsigned char *ptr = NULL; new_token->u.op.opline_num = get_next_op_number(CG(active_op_array)); opline = get_next_op(CG(active_op_array) TSRMLS_CC); @@ -5613,18 +5638,18 @@ void zend_do_begin_new_object(znode *new_token, znode *class_type TSRMLS_DC) /* SET_NODE(opline->op1, class_type); SET_UNUSED(opline->op2); - zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(unsigned char *)); + zend_push_function_call_entry(NULL TSRMLS_CC); if (++CG(context).nested_calls > CG(active_op_array)->nested_calls) { CG(active_op_array)->nested_calls = CG(context).nested_calls; } } /* }}} */ -void zend_do_end_new_object(znode *result, const znode *new_token, const znode *argument_list TSRMLS_DC) /* {{{ */ +void zend_do_end_new_object(znode *result, const znode *new_token TSRMLS_DC) /* {{{ */ { znode ctor_result; - zend_do_end_function_call(NULL, &ctor_result, argument_list, 1, 0 TSRMLS_CC); + zend_do_end_function_call(NULL, &ctor_result, 1, 0 TSRMLS_CC); zend_do_free(&ctor_result TSRMLS_CC); CG(active_op_array)->opcodes[new_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); @@ -6986,6 +7011,7 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify ce->unserialize = NULL; ce->serialize_func = NULL; ce->unserialize_func = NULL; + ce->__debugInfo = NULL; if (ce->type == ZEND_INTERNAL_CLASS) { ce->info.internal.module = NULL; ce->info.internal.builtin_functions = NULL; |