summaryrefslogtreecommitdiff
path: root/Zend/zend_execute.c
diff options
context:
space:
mode:
authorJakub Zelenka <bukka@php.net>2016-06-19 17:05:48 +0100
committerJakub Zelenka <bukka@php.net>2016-06-19 17:05:48 +0100
commite63a8540a60e95aa5bd8e269add1b02afcc1b79b (patch)
treeb83a144eec24cc81adab0b9a778f7a730d8df79e /Zend/zend_execute.c
parent7a4cc73641bb3eb878f7184bcbd026ee663cf2a9 (diff)
parent53071e647049f099f7f7a0771ddb63fc2cdd621c (diff)
downloadphp-git-e63a8540a60e95aa5bd8e269add1b02afcc1b79b.tar.gz
Merge branch 'openssl_error_store' into openssl_aead
Diffstat (limited to 'Zend/zend_execute.c')
-rw-r--r--Zend/zend_execute.c1212
1 files changed, 754 insertions, 458 deletions
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
index de5875fdba..a41c9dd594 100644
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@ -40,6 +40,7 @@
#include "zend_vm.h"
#include "zend_dtrace.h"
#include "zend_inheritance.h"
+#include "zend_type_info.h"
/* Virtual current working directory support */
#include "zend_virtual_cwd.h"
@@ -64,9 +65,9 @@ typedef int (ZEND_FASTCALL *incdec_t)(zval *);
#define get_obj_zval_ptr_ptr(op_type, node, ex, should_free, type) _get_obj_zval_ptr_ptr(op_type, node, ex, should_free, type)
/* Prototypes */
-static void zend_extension_statement_handler(const zend_extension *extension, zend_op_array *op_array);
-static void zend_extension_fcall_begin_handler(const zend_extension *extension, zend_op_array *op_array);
-static void zend_extension_fcall_end_handler(const zend_extension *extension, zend_op_array *op_array);
+static void zend_extension_statement_handler(const zend_extension *extension, zend_execute_data *frame);
+static void zend_extension_fcall_begin_handler(const zend_extension *extension, zend_execute_data *frame);
+static void zend_extension_fcall_end_handler(const zend_extension *extension, zend_execute_data *frame);
#define RETURN_VALUE_USED(opline) ((opline)->result_type != IS_UNUSED)
@@ -74,7 +75,7 @@ static ZEND_FUNCTION(pass)
{
}
-static const zend_internal_function zend_pass_function = {
+ZEND_API const zend_internal_function zend_pass_function = {
ZEND_INTERNAL_FUNCTION, /* type */
{0, 0, 0}, /* arg_flags */
0, /* fn_flags */
@@ -85,7 +86,8 @@ static const zend_internal_function zend_pass_function = {
0, /* required_num_args */
NULL, /* arg_info */
ZEND_FN(pass), /* handler */
- NULL /* module */
+ NULL, /* module */
+ {NULL,NULL,NULL,NULL} /* reserved */
};
#undef zval_ptr_dtor
@@ -116,21 +118,8 @@ static const zend_internal_function zend_pass_function = {
zval_ptr_dtor_nogc(should_free); \
}
-/* End of zend_execute_locks.h */
-
#define CV_DEF_OF(i) (EX(func)->op_array.vars[i])
-#define CTOR_CALL_BIT 0x1
-#define CTOR_USED_BIT 0x2
-
-#define IS_CTOR_CALL(ce) (((zend_uintptr_t)(ce)) & CTOR_CALL_BIT)
-#define IS_CTOR_USED(ce) (((zend_uintptr_t)(ce)) & CTOR_USED_BIT)
-
-#define ENCODE_CTOR(ce, used) \
- ((zend_class_entry*)(((zend_uintptr_t)(ce)) | CTOR_CALL_BIT | ((used) ? CTOR_USED_BIT : 0)))
-#define DECODE_CTOR(ce) \
- ((zend_class_entry*)(((zend_uintptr_t)(ce)) & ~(CTOR_CALL_BIT|CTOR_USED_BIT)))
-
#define ZEND_VM_MAIN_STACK_PAGE_SLOTS (16 * 1024) /* should be a power of 2 */
#define ZEND_VM_GENERATOR_STACK_PAGE_SLOTS (256)
@@ -397,6 +386,11 @@ static zend_always_inline zval *_get_zval_ptr_cv_undef_BP_VAR_RW(const zend_exec
return EX_VAR(var);
}
+static zend_always_inline zval *_get_zval_ptr_cv_undef_BP_VAR_UNSET(const zend_execute_data *execute_data, uint32_t var)
+{
+ return EX_VAR(var);
+}
+
static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_W(const zend_execute_data *execute_data, uint32_t var)
{
zval *ret = EX_VAR(var);
@@ -624,7 +618,7 @@ static zend_always_inline zend_class_entry* zend_verify_arg_class_kind(const zen
return zend_fetch_class(cur_arg_info->class_name, (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD));
}
-static ZEND_COLD void zend_verify_arg_error(const zend_function *zf, uint32_t arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind, zval *arg)
+static ZEND_COLD void zend_verify_arg_error(const zend_function *zf, uint32_t arg_num, const char *need_msg, const char *need_kind, const char *given_msg, const char *given_kind)
{
zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data;
const char *fname = ZSTR_VAL(zf->common.function_name);
@@ -652,19 +646,19 @@ static ZEND_COLD void zend_verify_arg_error(const zend_function *zf, uint32_t ar
}
}
-static int is_null_constant(zval *default_value)
+static int is_null_constant(zend_class_entry *scope, zval *default_value)
{
if (Z_CONSTANT_P(default_value)) {
zval constant;
- ZVAL_COPY_VALUE(&constant, default_value);
- if (UNEXPECTED(zval_update_constant_ex(&constant, 0, NULL) != SUCCESS)) {
+ ZVAL_COPY(&constant, default_value);
+ if (UNEXPECTED(zval_update_constant_ex(&constant, scope) != SUCCESS)) {
return 0;
}
if (Z_TYPE(constant) == IS_NULL) {
return 1;
}
- zval_dtor(&constant);
+ zval_ptr_dtor(&constant);
}
return 0;
}
@@ -750,25 +744,25 @@ static int zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, zv
if (cur_arg_info->class_name) {
need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info*)cur_arg_info, &class_name, &ce);
if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce)) {
- zend_verify_arg_error(zf, arg_num, need_msg, class_name, "instance of ", ZSTR_VAL(Z_OBJCE_P(arg)->name), arg);
+ zend_verify_arg_error(zf, arg_num, need_msg, class_name, "instance of ", ZSTR_VAL(Z_OBJCE_P(arg)->name));
return 0;
}
}
} else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) {
if (cur_arg_info->class_name) {
need_msg = zend_verify_internal_arg_class_kind((zend_internal_arg_info*)cur_arg_info, &class_name, &ce);
- zend_verify_arg_error(zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "", arg);
+ zend_verify_arg_error(zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "");
return 0;
} else if (cur_arg_info->type_hint == IS_CALLABLE) {
if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL)) {
- zend_verify_arg_error(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
+ zend_verify_arg_error(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "");
return 0;
}
} else if (cur_arg_info->type_hint == _IS_BOOL &&
EXPECTED(Z_TYPE_P(arg) == IS_FALSE || Z_TYPE_P(arg) == IS_TRUE)) {
/* pass */
} else if (UNEXPECTED(!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
- zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg);
+ zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "");
return 0;
}
}
@@ -776,6 +770,23 @@ static int zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, zv
return 1;
}
+static zend_never_inline int zend_verify_internal_arg_types(zend_function *fbc, zend_execute_data *call)
+{
+ uint32_t i;
+ uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
+ zval *p = ZEND_CALL_ARG(call, 1);
+
+ for (i = 0; i < num_args; ++i) {
+ if (UNEXPECTED(!zend_verify_internal_arg_type(fbc, i + 1, p))) {
+ EG(current_execute_data) = call->prev_execute_data;
+ zend_vm_stack_free_args(call);
+ return 0;
+ }
+ p++;
+ }
+ return 1;
+}
+
static zend_always_inline int zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value, void **cache_slot)
{
zend_arg_info *cur_arg_info;
@@ -799,7 +810,7 @@ static zend_always_inline int zend_verify_arg_type(zend_function *zf, uint32_t a
} else {
ce = zend_verify_arg_class_kind(cur_arg_info);
if (UNEXPECTED(!ce)) {
- zend_verify_arg_error(zf, arg_num, "be an instance of ", ZSTR_VAL(cur_arg_info->class_name), "instance of ", ZSTR_VAL(Z_OBJCE_P(arg)->name), arg);
+ zend_verify_arg_error(zf, arg_num, "be an instance of ", ZSTR_VAL(cur_arg_info->class_name), "instance of ", ZSTR_VAL(Z_OBJCE_P(arg)->name));
return 0;
}
*cache_slot = (void*)ce;
@@ -808,11 +819,11 @@ static zend_always_inline int zend_verify_arg_type(zend_function *zf, uint32_t a
need_msg =
(ce->ce_flags & ZEND_ACC_INTERFACE) ?
"implement interface " : "be an instance of ";
- zend_verify_arg_error(zf, arg_num, need_msg, ZSTR_VAL(ce->name), "instance of ", ZSTR_VAL(Z_OBJCE_P(arg)->name), arg);
+ zend_verify_arg_error(zf, arg_num, need_msg, ZSTR_VAL(ce->name), "instance of ", ZSTR_VAL(Z_OBJCE_P(arg)->name));
return 0;
}
}
- } else if (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value)))) {
+ } else if (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(zf->common.scope, default_value)))) {
if (cur_arg_info->class_name) {
if (EXPECTED(*cache_slot)) {
ce = (zend_class_entry*)*cache_slot;
@@ -820,9 +831,9 @@ static zend_always_inline int zend_verify_arg_type(zend_function *zf, uint32_t a
ce = zend_verify_arg_class_kind(cur_arg_info);
if (UNEXPECTED(!ce)) {
if (Z_TYPE_P(arg) == IS_OBJECT) {
- zend_verify_arg_error(zf, arg_num, "be an instance of ", ZSTR_VAL(cur_arg_info->class_name), "instance of ", ZSTR_VAL(Z_OBJCE_P(arg)->name), arg);
+ zend_verify_arg_error(zf, arg_num, "be an instance of ", ZSTR_VAL(cur_arg_info->class_name), "instance of ", ZSTR_VAL(Z_OBJCE_P(arg)->name));
} else {
- zend_verify_arg_error(zf, arg_num, "be an instance of ", ZSTR_VAL(cur_arg_info->class_name), "", zend_zval_type_name(arg), arg);
+ zend_verify_arg_error(zf, arg_num, "be an instance of ", ZSTR_VAL(cur_arg_info->class_name), "", zend_zval_type_name(arg));
}
return 0;
}
@@ -831,18 +842,18 @@ static zend_always_inline int zend_verify_arg_type(zend_function *zf, uint32_t a
need_msg =
(ce->ce_flags & ZEND_ACC_INTERFACE) ?
"implement interface " : "be an instance of ";
- zend_verify_arg_error(zf, arg_num, need_msg, ZSTR_VAL(ce->name), zend_zval_type_name(arg), "", arg);
+ zend_verify_arg_error(zf, arg_num, need_msg, ZSTR_VAL(ce->name), zend_zval_type_name(arg), "");
return 0;
} else if (cur_arg_info->type_hint == IS_CALLABLE) {
if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL)) {
- zend_verify_arg_error(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
+ zend_verify_arg_error(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "");
return 0;
}
} else if (cur_arg_info->type_hint == _IS_BOOL &&
EXPECTED(Z_TYPE_P(arg) == IS_FALSE || Z_TYPE_P(arg) == IS_TRUE)) {
/* pass */
} else if (UNEXPECTED(!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg, ZEND_ARG_USES_STRICT_TYPES()))) {
- zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg);
+ zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "");
return 0;
}
}
@@ -850,60 +861,28 @@ static zend_always_inline int zend_verify_arg_type(zend_function *zf, uint32_t a
return 1;
}
-static zend_always_inline int zend_verify_missing_arg_type(zend_function *zf, uint32_t arg_num, void **cache_slot)
+ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(zend_execute_data *execute_data)
{
- zend_arg_info *cur_arg_info;
- char *need_msg;
- zend_class_entry *ce;
+ zend_execute_data *ptr = EX(prev_execute_data);
- if (EXPECTED(arg_num <= zf->common.num_args)) {
- cur_arg_info = &zf->common.arg_info[arg_num-1];
- } else if (UNEXPECTED(zf->common.fn_flags & ZEND_ACC_VARIADIC)) {
- cur_arg_info = &zf->common.arg_info[zf->common.num_args];
+ if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) {
+ zend_throw_error(NULL, "Too few arguments to function %s%s%s(), %d passed in %s on line %d and %s %d expected",
+ EX(func)->common.scope ? ZSTR_VAL(EX(func)->common.scope->name) : "",
+ EX(func)->common.scope ? "::" : "",
+ ZSTR_VAL(EX(func)->common.function_name),
+ EX_NUM_ARGS(),
+ ZSTR_VAL(ptr->func->op_array.filename),
+ ptr->opline->lineno,
+ EX(func)->common.required_num_args == EX(func)->common.num_args ? "exactly" : "at least",
+ EX(func)->common.required_num_args);
} else {
- return 1;
- }
-
- if (cur_arg_info->type_hint) {
- if (cur_arg_info->class_name) {
- if (EXPECTED(*cache_slot)) {
- ce = (zend_class_entry*)*cache_slot;
- } else {
- ce = zend_verify_arg_class_kind(cur_arg_info);
- if (UNEXPECTED(!ce)) {
- zend_verify_arg_error(zf, arg_num, "be an instance of ", ZSTR_VAL(cur_arg_info->class_name), "none", "", NULL);
- return 0;
- }
- *cache_slot = (void*)ce;
- }
- need_msg =
- (ce->ce_flags & ZEND_ACC_INTERFACE) ?
- "implement interface " : "be an instance of ";
- zend_verify_arg_error(zf, arg_num, need_msg, ZSTR_VAL(ce->name), "none", "", NULL);
- } else if (cur_arg_info->type_hint == IS_CALLABLE) {
- zend_verify_arg_error(zf, arg_num, "be callable", "", "none", "", NULL);
- } else {
- zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), "none", "", NULL);
- }
- return 0;
- }
- return 1;
-}
-
-static ZEND_COLD void zend_verify_missing_arg(zend_execute_data *execute_data, uint32_t arg_num, void **cache_slot)
-{
- if (EXPECTED(!(EX(func)->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) ||
- UNEXPECTED(zend_verify_missing_arg_type(EX(func), arg_num, cache_slot))) {
- const char *class_name = EX(func)->common.scope ? ZSTR_VAL(EX(func)->common.scope->name) : "";
- const char *space = EX(func)->common.scope ? "::" : "";
- const char *func_name = EX(func)->common.function_name ? ZSTR_VAL(EX(func)->common.function_name) : "main";
- zend_execute_data *ptr = EX(prev_execute_data);
-
- if (ptr && ptr->func && ZEND_USER_CODE(ptr->func->common.type)) {
- zend_error(E_WARNING, "Missing argument %u for %s%s%s(), called in %s on line %d and defined", arg_num, class_name, space, func_name, ZSTR_VAL(ptr->func->op_array.filename), ptr->opline->lineno);
- } else {
- zend_error(E_WARNING, "Missing argument %u for %s%s%s()", arg_num, class_name, space, func_name);
- }
+ zend_throw_error(NULL, "Too few arguments to function %s%s%s(), %d passed and %s %d expected",
+ EX(func)->common.scope ? ZSTR_VAL(EX(func)->common.scope->name) : "",
+ EX(func)->common.scope ? "::" : "",
+ ZSTR_VAL(EX(func)->common.function_name),
+ EX_NUM_ARGS(),
+ EX(func)->common.required_num_args == EX(func)->common.num_args ? "exactly" : "at least",
+ EX(func)->common.required_num_args);
}
}
@@ -925,6 +904,7 @@ static ZEND_COLD void zend_verify_return_error(const zend_function *zf, const ch
fclass, fsep, fname, need_msg, need_kind, returned_msg, returned_kind);
}
+#if ZEND_DEBUG
static ZEND_COLD void zend_verify_internal_return_error(const zend_function *zf, const char *need_msg, const char *need_kind, const char *returned_msg, const char *returned_kind)
{
const char *fname = ZSTR_VAL(zf->common.function_name);
@@ -961,7 +941,6 @@ static ZEND_COLD void zend_verify_void_return_error(const zend_function *zf, con
fclass, fsep, fname, returned_msg, returned_kind);
}
-#if ZEND_DEBUG
static int zend_verify_internal_return_type(zend_function *zf, zval *ret)
{
zend_arg_info *ret_info = zf->common.arg_info - 1;
@@ -1098,38 +1077,14 @@ static ZEND_COLD int zend_verify_missing_return_type(zend_function *zf, void **c
return 1;
}
-static zend_never_inline void zend_assign_to_object_dim(zval *retval, zval *object, zval *property_name, int value_type, znode_op value_op, const zend_execute_data *execute_data)
+static zend_never_inline void zend_assign_to_object_dim(zval *object, zval *dim, zval *value)
{
- zend_free_op free_value;
- zval *value = get_zval_ptr_deref(value_type, value_op, execute_data, &free_value, BP_VAR_R);
- zval tmp;
-
- /* Note: property_name in this case is really the array index! */
- if (!Z_OBJ_HT_P(object)->write_dimension) {
+ if (UNEXPECTED(!Z_OBJ_HT_P(object)->write_dimension)) {
zend_throw_error(NULL, "Cannot use object as array");
- FREE_OP(free_value);
return;
}
- /* separate our value if necessary */
- if (value_type == IS_CONST) {
- if (UNEXPECTED(Z_OPT_COPYABLE_P(value))) {
- ZVAL_COPY_VALUE(&tmp, value);
- zval_copy_ctor_func(&tmp);
- value = &tmp;
- }
- }
-
- Z_OBJ_HT_P(object)->write_dimension(object, property_name, value);
-
- if (retval && EXPECTED(!EG(exception))) {
- ZVAL_COPY(retval, value);
- }
- if (value_type == IS_CONST) {
- zval_ptr_dtor_nogc(value);
- } else {
- FREE_OP(free_value);
- }
+ Z_OBJ_HT_P(object)->write_dimension(object, dim, value);
}
static zend_never_inline void zend_binary_assign_op_obj_dim(zval *object, zval *property, zval *value, zval *retval, binary_op_type binary_op)
@@ -1166,16 +1121,170 @@ static zend_never_inline void zend_binary_assign_op_obj_dim(zval *object, zval *
}
}
-static void zend_assign_to_string_offset(zval *str, zend_long offset, zval *value, zval *result)
+static zend_never_inline zend_long zend_check_string_offset(zval *dim, int type)
+{
+ zend_long offset;
+
+try_again:
+ if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
+ switch(Z_TYPE_P(dim)) {
+ case IS_STRING:
+ if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) {
+ break;
+ }
+ if (type != BP_VAR_UNSET) {
+ zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
+ }
+ break;
+ case IS_UNDEF:
+ zval_undefined_cv(EG(current_execute_data)->opline->op2.var, EG(current_execute_data));
+ case IS_DOUBLE:
+ case IS_NULL:
+ case IS_FALSE:
+ case IS_TRUE:
+ zend_error(E_NOTICE, "String offset cast occurred");
+ break;
+ case IS_REFERENCE:
+ dim = Z_REFVAL_P(dim);
+ goto try_again;
+ default:
+ zend_error(E_WARNING, "Illegal offset type");
+ break;
+ }
+
+ offset = _zval_get_long_func(dim);
+ } else {
+ offset = Z_LVAL_P(dim);
+ }
+
+ return offset;
+}
+
+static zend_never_inline ZEND_COLD void zend_wrong_string_offset(void)
+{
+ const char *msg = NULL;
+ const zend_op *opline = EG(current_execute_data)->opline;
+ const zend_op *end;
+ uint32_t var;
+
+ switch (opline->opcode) {
+ case ZEND_ASSIGN_ADD:
+ case ZEND_ASSIGN_SUB:
+ case ZEND_ASSIGN_MUL:
+ case ZEND_ASSIGN_DIV:
+ case ZEND_ASSIGN_MOD:
+ case ZEND_ASSIGN_SL:
+ case ZEND_ASSIGN_SR:
+ case ZEND_ASSIGN_CONCAT:
+ case ZEND_ASSIGN_BW_OR:
+ case ZEND_ASSIGN_BW_AND:
+ case ZEND_ASSIGN_BW_XOR:
+ case ZEND_ASSIGN_POW:
+ msg = "Cannot use assign-op operators with string offsets";
+ break;
+ case ZEND_FETCH_DIM_W:
+ case ZEND_FETCH_DIM_RW:
+ case ZEND_FETCH_DIM_FUNC_ARG:
+ case ZEND_FETCH_DIM_UNSET:
+ /* TODO: Encode the "reason" into opline->extended_value??? */
+ var = opline->result.var;
+ opline++;
+ end = EG(current_execute_data)->func->op_array.opcodes +
+ EG(current_execute_data)->func->op_array.last;
+ while (opline < end) {
+ if (opline->op1_type == IS_VAR && opline->op1.var == var) {
+ switch (opline->opcode) {
+ case ZEND_ASSIGN_ADD:
+ case ZEND_ASSIGN_SUB:
+ case ZEND_ASSIGN_MUL:
+ case ZEND_ASSIGN_DIV:
+ case ZEND_ASSIGN_MOD:
+ case ZEND_ASSIGN_SL:
+ case ZEND_ASSIGN_SR:
+ case ZEND_ASSIGN_CONCAT:
+ case ZEND_ASSIGN_BW_OR:
+ case ZEND_ASSIGN_BW_AND:
+ case ZEND_ASSIGN_BW_XOR:
+ case ZEND_ASSIGN_POW:
+ if (opline->extended_value == ZEND_ASSIGN_OBJ) {
+ msg = "Cannot use string offset as an object";
+ } else if (opline->extended_value == ZEND_ASSIGN_DIM) {
+ msg = "Cannot use string offset as an array";
+ } else {
+ msg = "Cannot use assign-op operators with string offsets";
+ }
+ break;
+ case ZEND_PRE_INC_OBJ:
+ case ZEND_PRE_DEC_OBJ:
+ case ZEND_POST_INC_OBJ:
+ case ZEND_POST_DEC_OBJ:
+ case ZEND_PRE_INC:
+ case ZEND_PRE_DEC:
+ case ZEND_POST_INC:
+ case ZEND_POST_DEC:
+ msg = "Cannot increment/decrement string offsets";
+ break;
+ case ZEND_FETCH_DIM_W:
+ case ZEND_FETCH_DIM_RW:
+ case ZEND_FETCH_DIM_FUNC_ARG:
+ case ZEND_FETCH_DIM_UNSET:
+ case ZEND_ASSIGN_DIM:
+ msg = "Cannot use string offset as an array";
+ break;
+ case ZEND_FETCH_OBJ_W:
+ case ZEND_FETCH_OBJ_RW:
+ case ZEND_FETCH_OBJ_FUNC_ARG:
+ case ZEND_FETCH_OBJ_UNSET:
+ case ZEND_ASSIGN_OBJ:
+ msg = "Cannot use string offset as an object";
+ break;
+ case ZEND_ASSIGN_REF:
+ case ZEND_ADD_ARRAY_ELEMENT:
+ case ZEND_INIT_ARRAY:
+ msg = "Cannot create references to/from string offsets";
+ break;
+ case ZEND_RETURN_BY_REF:
+ msg = "Cannot return string offsets by reference";
+ break;
+ case ZEND_UNSET_DIM:
+ case ZEND_UNSET_OBJ:
+ msg = "Cannot unset string offsets";
+ break;
+ case ZEND_YIELD:
+ msg = "Cannot yield string offsets by reference";
+ break;
+ case ZEND_SEND_REF:
+ case ZEND_SEND_VAR_EX:
+ msg = "Only variables can be passed by reference";
+ break;
+ EMPTY_SWITCH_DEFAULT_CASE();
+ }
+ break;
+ }
+ if (opline->op2_type == IS_VAR && opline->op2.var == var) {
+ ZEND_ASSERT(opline->opcode == ZEND_ASSIGN_REF);
+ msg = "Cannot create references to/from string offsets";
+ break;
+ }
+ }
+ break;
+ EMPTY_SWITCH_DEFAULT_CASE();
+ }
+ ZEND_ASSERT(msg != NULL);
+ zend_throw_error(NULL, msg);
+}
+
+static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, zval *value, zval *result)
{
zend_string *old_str;
zend_uchar c;
size_t string_len;
+ zend_long offset;
- if (offset < 0) {
+ offset = zend_check_string_offset(dim, BP_VAR_W);
+ if (offset < (zend_long)(-Z_STRLEN_P(str))) {
/* Error on negative offset */
zend_error(E_WARNING, "Illegal string offset: " ZEND_LONG_FMT, offset);
- zend_string_release(Z_STR_P(str));
if (result) {
ZVAL_NULL(result);
}
@@ -1197,14 +1306,16 @@ static void zend_assign_to_string_offset(zval *str, zend_long offset, zval *valu
if (string_len == 0) {
/* Error on empty input string */
zend_error(E_WARNING, "Cannot assign an empty string to a string offset");
- zend_string_release(Z_STR_P(str));
if (result) {
ZVAL_NULL(result);
}
return;
}
- old_str = Z_STR_P(str);
+ if (offset < 0) { /* Handle negative offset */
+ offset += (zend_long)Z_STRLEN_P(str);
+ }
+
if ((size_t)offset >= Z_STRLEN_P(str)) {
/* Extend string if needed */
zend_long old_len = Z_STRLEN_P(str);
@@ -1213,13 +1324,16 @@ static void zend_assign_to_string_offset(zval *str, zend_long offset, zval *valu
memset(Z_STRVAL_P(str) + old_len, ' ', offset - old_len);
Z_STRVAL_P(str)[offset+1] = 0;
} else if (!Z_REFCOUNTED_P(str)) {
+ old_str = Z_STR_P(str);
Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
Z_TYPE_INFO_P(str) = IS_STRING_EX;
+ zend_string_release(old_str);
+ } else {
+ SEPARATE_STRING(str);
}
Z_STRVAL_P(str)[offset] = c;
- zend_string_release(old_str);
if (result) {
/* Return the new character */
if (CG(one_char_string)[c]) {
@@ -1362,26 +1476,26 @@ static zend_never_inline void zend_assign_op_overloaded_property(zval *object, z
}
/* Utility Functions for Extensions */
-static void zend_extension_statement_handler(const zend_extension *extension, zend_op_array *op_array)
+static void zend_extension_statement_handler(const zend_extension *extension, zend_execute_data *frame)
{
if (extension->statement_handler) {
- extension->statement_handler(op_array);
+ extension->statement_handler(frame);
}
}
-static void zend_extension_fcall_begin_handler(const zend_extension *extension, zend_op_array *op_array)
+static void zend_extension_fcall_begin_handler(const zend_extension *extension, zend_execute_data *frame)
{
if (extension->fcall_begin_handler) {
- extension->fcall_begin_handler(op_array);
+ extension->fcall_begin_handler(frame);
}
}
-static void zend_extension_fcall_end_handler(const zend_extension *extension, zend_op_array *op_array)
+static void zend_extension_fcall_end_handler(const zend_extension *extension, zend_execute_data *frame)
{
if (extension->fcall_end_handler) {
- extension->fcall_end_handler(op_array);
+ extension->fcall_end_handler(frame);
}
}
@@ -1395,7 +1509,7 @@ static zend_always_inline HashTable *zend_get_target_symbol_table(zend_execute_d
ht = &EG(symbol_table);
} else {
ZEND_ASSERT(fetch_type == ZEND_FETCH_LOCAL);
- if (!EX(symbol_table)) {
+ if (!(EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE)) {
zend_rebuild_symbol_table();
}
ht = EX(symbol_table);
@@ -1413,24 +1527,24 @@ try_again:
if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) {
hval = Z_LVAL_P(dim);
num_index:
- retval = zend_hash_index_find(ht, hval);
- if (retval == NULL) {
- switch (type) {
- case BP_VAR_R:
- zend_error(E_NOTICE,"Undefined offset: " ZEND_LONG_FMT, hval);
- /* break missing intentionally */
- case BP_VAR_UNSET:
- case BP_VAR_IS:
- retval = &EG(uninitialized_zval);
- break;
- case BP_VAR_RW:
- zend_error(E_NOTICE,"Undefined offset: " ZEND_LONG_FMT, hval);
- retval = zend_hash_index_update(ht, hval, &EG(uninitialized_zval));
- break;
- case BP_VAR_W:
- retval = zend_hash_index_add_new(ht, hval, &EG(uninitialized_zval));
- break;
- }
+ ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
+ return retval;
+num_undef:
+ switch (type) {
+ case BP_VAR_R:
+ zend_error(E_NOTICE,"Undefined offset: " ZEND_LONG_FMT, hval);
+ /* break missing intentionally */
+ case BP_VAR_UNSET:
+ case BP_VAR_IS:
+ retval = &EG(uninitialized_zval);
+ break;
+ case BP_VAR_RW:
+ zend_error(E_NOTICE,"Undefined offset: " ZEND_LONG_FMT, hval);
+ retval = zend_hash_index_update(ht, hval, &EG(uninitialized_zval));
+ break;
+ case BP_VAR_W:
+ retval = zend_hash_index_add_new(ht, hval, &EG(uninitialized_zval));
+ break;
}
} else if (EXPECTED(Z_TYPE_P(dim) == IS_STRING)) {
offset_key = Z_STR_P(dim);
@@ -1483,6 +1597,9 @@ str_index:
}
} else {
switch (Z_TYPE_P(dim)) {
+ case IS_UNDEF:
+ zval_undefined_cv(EG(current_execute_data)->opline->op2.var, EG(current_execute_data));
+ /* break missing intentionally */
case IS_NULL:
offset_key = ZSTR_EMPTY_ALLOC();
goto str_index;
@@ -1511,169 +1628,24 @@ str_index:
return retval;
}
-static zend_never_inline zend_long zend_check_string_offset(zval *dim, int type)
+static zend_never_inline zval* ZEND_FASTCALL zend_fetch_dimension_address_inner_W(HashTable *ht, const zval *dim)
{
- zend_long offset;
-
-try_again:
- if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
- switch(Z_TYPE_P(dim)) {
- case IS_STRING:
- if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) {
- break;
- }
- if (type != BP_VAR_UNSET) {
- zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
- }
- break;
- case IS_DOUBLE:
- case IS_NULL:
- case IS_FALSE:
- case IS_TRUE:
- zend_error(E_NOTICE, "String offset cast occurred");
- break;
- case IS_REFERENCE:
- dim = Z_REFVAL_P(dim);
- goto try_again;
- default:
- zend_error(E_WARNING, "Illegal offset type");
- break;
- }
-
- offset = zval_get_long(dim);
- } else {
- offset = Z_LVAL_P(dim);
- }
-
- return offset;
+ return zend_fetch_dimension_address_inner(ht, dim, IS_TMP_VAR, BP_VAR_W);
}
-static zend_never_inline ZEND_COLD void zend_wrong_string_offset(void)
+static zend_never_inline zval* ZEND_FASTCALL zend_fetch_dimension_address_inner_W_CONST(HashTable *ht, const zval *dim)
{
- const char *msg = NULL;
- const zend_op *opline = EG(current_execute_data)->opline;
- const zend_op *end;
- uint32_t var;
-
- switch (opline->opcode) {
- case ZEND_ASSIGN_ADD:
- case ZEND_ASSIGN_SUB:
- case ZEND_ASSIGN_MUL:
- case ZEND_ASSIGN_DIV:
- case ZEND_ASSIGN_MOD:
- case ZEND_ASSIGN_SL:
- case ZEND_ASSIGN_SR:
- case ZEND_ASSIGN_CONCAT:
- case ZEND_ASSIGN_BW_OR:
- case ZEND_ASSIGN_BW_AND:
- case ZEND_ASSIGN_BW_XOR:
- case ZEND_ASSIGN_POW:
- msg = "Cannot use assign-op operators with string offsets";
- break;
- case ZEND_FETCH_DIM_W:
- case ZEND_FETCH_DIM_RW:
- case ZEND_FETCH_DIM_FUNC_ARG:
- case ZEND_FETCH_DIM_UNSET:
- /* TODO: Encode the "reason" into opline->extended_value??? */
- var = opline->result.var;
- opline++;
- end = EG(current_execute_data)->func->op_array.opcodes +
- EG(current_execute_data)->func->op_array.last;
- while (opline < end) {
- if (opline->op1_type == IS_VAR && opline->op1.var == var) {
- switch (opline->opcode) {
- case ZEND_ASSIGN_ADD:
- case ZEND_ASSIGN_SUB:
- case ZEND_ASSIGN_MUL:
- case ZEND_ASSIGN_DIV:
- case ZEND_ASSIGN_MOD:
- case ZEND_ASSIGN_SL:
- case ZEND_ASSIGN_SR:
- case ZEND_ASSIGN_CONCAT:
- case ZEND_ASSIGN_BW_OR:
- case ZEND_ASSIGN_BW_AND:
- case ZEND_ASSIGN_BW_XOR:
- case ZEND_ASSIGN_POW:
- if (opline->extended_value == ZEND_ASSIGN_OBJ) {
- msg = "Cannot use string offset as an object";
- } else if (opline->extended_value == ZEND_ASSIGN_DIM) {
- msg = "Cannot use string offset as an array";
- } else {
- msg = "Cannot use assign-op operators with string offsets";
- }
- break;
- case ZEND_PRE_INC_OBJ:
- case ZEND_PRE_DEC_OBJ:
- case ZEND_POST_INC_OBJ:
- case ZEND_POST_DEC_OBJ:
- case ZEND_PRE_INC:
- case ZEND_PRE_DEC:
- case ZEND_POST_INC:
- case ZEND_POST_DEC:
- msg = "Cannot increment/decrement string offsets";
- break;
- case ZEND_FETCH_DIM_W:
- case ZEND_FETCH_DIM_RW:
- case ZEND_FETCH_DIM_FUNC_ARG:
- case ZEND_FETCH_DIM_UNSET:
- case ZEND_ASSIGN_DIM:
- msg = "Cannot use string offset as an array";
- break;
- case ZEND_FETCH_OBJ_W:
- case ZEND_FETCH_OBJ_RW:
- case ZEND_FETCH_OBJ_FUNC_ARG:
- case ZEND_FETCH_OBJ_UNSET:
- case ZEND_ASSIGN_OBJ:
- msg = "Cannot use string offset as an object";
- break;
- case ZEND_ASSIGN_REF:
- case ZEND_ADD_ARRAY_ELEMENT:
- case ZEND_INIT_ARRAY:
- msg = "Cannot create references to/from string offsets";
- break;
- case ZEND_RETURN_BY_REF:
- msg = "Cannot return string offsets by reference";
- break;
- case ZEND_UNSET_DIM:
- case ZEND_UNSET_OBJ:
- msg = "Cannot unset string offsets";
- break;
- case ZEND_YIELD:
- msg = "Cannot yield string offsets by reference";
- break;
- case ZEND_SEND_REF:
- case ZEND_SEND_VAR_EX:
- msg = "Only variables can be passed by reference";
- break;
- EMPTY_SWITCH_DEFAULT_CASE();
- }
- break;
- }
- if (opline->op2_type == IS_VAR && opline->op2.var == var) {
- ZEND_ASSERT(opline->opcode == ZEND_ASSIGN_REF);
- msg = "Cannot create references to/from string offsets";
- break;
- }
- }
- break;
- EMPTY_SWITCH_DEFAULT_CASE();
- }
- ZEND_ASSERT(msg != NULL);
- zend_throw_error(NULL, msg);
+ return zend_fetch_dimension_address_inner(ht, dim, IS_CONST, BP_VAR_W);
}
-static zend_always_inline zend_long zend_fetch_string_offset(zval *container, zval *dim, int type)
+static zend_never_inline zval* ZEND_FASTCALL zend_fetch_dimension_address_inner_RW(HashTable *ht, const zval *dim)
{
- zend_long offset = zend_check_string_offset(dim, type);
+ return zend_fetch_dimension_address_inner(ht, dim, IS_TMP_VAR, BP_VAR_RW);
+}
- if (Z_REFCOUNTED_P(container)) {
- if (Z_REFCOUNT_P(container) > 1) {
- Z_DELREF_P(container);
- zval_copy_ctor_func(container);
- }
- Z_ADDREF_P(container);
- }
- return offset;
+static zend_never_inline zval* ZEND_FASTCALL zend_fetch_dimension_address_inner_RW_CONST(HashTable *ht, const zval *dim)
+{
+ return zend_fetch_dimension_address_inner(ht, dim, IS_CONST, BP_VAR_RW);
}
static zend_always_inline void zend_fetch_dimension_address(zval *result, zval *container, zval *dim, int dim_type, int type)
@@ -1706,15 +1678,7 @@ fetch_from_array:
goto try_array;
}
}
- if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) {
- if (type != BP_VAR_UNSET && UNEXPECTED(Z_STRLEN_P(container) == 0)) {
- zval_ptr_dtor_nogc(container);
-convert_to_array:
- ZVAL_NEW_ARR(container);
- zend_hash_init(Z_ARRVAL_P(container), 8, NULL, ZVAL_PTR_DTOR, 0);
- goto fetch_from_array;
- }
-
+ if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) {
if (dim == NULL) {
zend_throw_error(NULL, "[] operator not supported for strings");
} else {
@@ -1723,6 +1687,10 @@ convert_to_array:
}
ZVAL_ERROR(result);
} else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
+ if (/*dim_type == IS_CV &&*/ dim && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
+ zval_undefined_cv(EG(current_execute_data)->opline->op2.var, EG(current_execute_data));
+ dim = &EG(uninitialized_zval);
+ }
if (!Z_OBJ_HT_P(container)->read_dimension) {
zend_throw_error(NULL, "Cannot use object as array");
ZVAL_ERROR(result);
@@ -1761,22 +1729,32 @@ convert_to_array:
ZVAL_ERROR(result);
}
}
- } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) {
- if (type != BP_VAR_UNSET) {
- goto convert_to_array;
- } else {
- /* for read-mode only */
- ZVAL_NULL(result);
- }
- } else if (EXPECTED(Z_ISERROR_P(container))) {
- ZVAL_ERROR(result);
} else {
- if (type == BP_VAR_UNSET) {
- zend_error(E_WARNING, "Cannot unset offset in a non-array variable");
- ZVAL_NULL(result);
- } else {
- zend_error(E_WARNING, "Cannot use a scalar value as an array");
+ if (type != BP_VAR_W && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
+ zval_undefined_cv(EG(current_execute_data)->opline->op1.var, EG(current_execute_data));
+ }
+ if (/*dim_type == IS_CV &&*/ dim && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
+ zval_undefined_cv(EG(current_execute_data)->opline->op2.var, EG(current_execute_data));
+ }
+ if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) {
+ if (type != BP_VAR_UNSET) {
+ ZVAL_NEW_ARR(container);
+ zend_hash_init(Z_ARRVAL_P(container), 8, NULL, ZVAL_PTR_DTOR, 0);
+ goto fetch_from_array;
+ } else {
+ /* for read-mode only */
+ ZVAL_NULL(result);
+ }
+ } else if (EXPECTED(Z_ISERROR_P(container))) {
ZVAL_ERROR(result);
+ } else {
+ if (type == BP_VAR_UNSET) {
+ zend_error(E_WARNING, "Cannot unset offset in a non-array variable");
+ ZVAL_NULL(result);
+ } else {
+ zend_error(E_WARNING, "Cannot use a scalar value as an array");
+ ZVAL_ERROR(result);
+ }
}
}
}
@@ -1796,27 +1774,29 @@ static zend_never_inline void zend_fetch_dimension_address_UNSET(zval *result, z
zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_UNSET);
}
-static zend_always_inline void zend_fetch_dimension_address_read(zval *result, zval *container, zval *dim, int dim_type, int type)
+static zend_always_inline void zend_fetch_dimension_address_read(zval *result, zval *container, zval *dim, int dim_type, int type, int support_strings, int slow)
{
zval *retval;
- if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
-try_array:
- retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type);
- ZVAL_COPY(result, retval);
- return;
- } else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) {
- container = Z_REFVAL_P(container);
+ if (!slow) {
if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
- goto try_array;
+try_array:
+ retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type);
+ ZVAL_COPY(result, retval);
+ return;
+ } else if (EXPECTED(Z_TYPE_P(container) == IS_REFERENCE)) {
+ container = Z_REFVAL_P(container);
+ if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) {
+ goto try_array;
+ }
}
}
- if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) {
+ if (support_strings && EXPECTED(Z_TYPE_P(container) == IS_STRING)) {
zend_long offset;
try_string_offset:
if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
- switch(Z_TYPE_P(dim)) {
+ switch (Z_TYPE_P(dim)) {
/* case IS_LONG: */
case IS_STRING:
if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) {
@@ -1828,6 +1808,8 @@ try_string_offset:
}
zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
break;
+ case IS_UNDEF:
+ zval_undefined_cv(EG(current_execute_data)->opline->op2.var, EG(current_execute_data));
case IS_DOUBLE:
case IS_NULL:
case IS_FALSE:
@@ -1844,12 +1826,12 @@ try_string_offset:
break;
}
- offset = zval_get_long(dim);
+ offset = _zval_get_long_func(dim);
} else {
offset = Z_LVAL_P(dim);
}
- if (UNEXPECTED(offset < 0) || UNEXPECTED(Z_STRLEN_P(container) <= (size_t)offset)) {
+ if (UNEXPECTED(Z_STRLEN_P(container) < (size_t)((offset < 0) ? -offset : (offset + 1)))) {
if (type != BP_VAR_IS) {
zend_error(E_NOTICE, "Uninitialized string offset: %pd", offset);
ZVAL_EMPTY_STRING(result);
@@ -1857,15 +1839,24 @@ try_string_offset:
ZVAL_NULL(result);
}
} else {
- zend_uchar c = (zend_uchar)Z_STRVAL_P(container)[offset];
+ zend_uchar c;
+ zend_long real_offset;
+
+ real_offset = (UNEXPECTED(offset < 0)) /* Handle negative offset */
+ ? (zend_long)Z_STRLEN_P(container) + offset : offset;
+ c = (zend_uchar)Z_STRVAL_P(container)[real_offset];
if (CG(one_char_string)[c]) {
ZVAL_INTERNED_STR(result, CG(one_char_string)[c]);
} else {
- ZVAL_NEW_STR(result, zend_string_init(Z_STRVAL_P(container) + offset, 1, 0));
+ ZVAL_NEW_STR(result, zend_string_init(Z_STRVAL_P(container) + real_offset, 1, 0));
}
}
} else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
+ if (/*dim_type == IS_CV &&*/ UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
+ zval_undefined_cv(EG(current_execute_data)->opline->op2.var, EG(current_execute_data));
+ dim = &EG(uninitialized_zval);
+ }
if (!Z_OBJ_HT_P(container)->read_dimension) {
zend_throw_error(NULL, "Cannot use object as array");
ZVAL_NULL(result);
@@ -1882,18 +1873,34 @@ try_string_offset:
}
}
} else {
+ if (type != BP_VAR_IS && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
+ zval_undefined_cv(EG(current_execute_data)->opline->op1.var, EG(current_execute_data));
+ }
+ if (/*dim_type == IS_CV &&*/ UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
+ zval_undefined_cv(EG(current_execute_data)->opline->op2.var, EG(current_execute_data));
+ }
ZVAL_NULL(result);
}
}
static zend_never_inline void zend_fetch_dimension_address_read_R(zval *result, zval *container, zval *dim, int dim_type)
{
- zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R);
+ zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_R, 1, 0);
+}
+
+static zend_never_inline void zend_fetch_dimension_address_read_R_slow(zval *result, zval *container, zval *dim)
+{
+ zend_fetch_dimension_address_read(result, container, dim, IS_CV, BP_VAR_R, 1, 1);
}
static zend_never_inline void zend_fetch_dimension_address_read_IS(zval *result, zval *container, zval *dim, int dim_type)
{
- zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS);
+ zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS, 1, 0);
+}
+
+static zend_never_inline void zend_fetch_dimension_address_read_LIST(zval *result, zval *container, zval *dim)
+{
+ zend_fetch_dimension_address_read(result, container, dim, IS_TMP_VAR, BP_VAR_R, 0, 0);
}
ZEND_API void zend_fetch_dimension_by_zval(zval *result, zval *container, zval *dim)
@@ -1901,15 +1908,16 @@ ZEND_API void zend_fetch_dimension_by_zval(zval *result, zval *container, zval *
zend_fetch_dimension_address_read_R(result, container, dim, IS_TMP_VAR);
}
+ZEND_API void zend_fetch_dimension_by_zval_is(zval *result, zval *container, zval *dim, int dim_type)
+{
+ zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS, 1, 0);
+}
+
+
static zend_always_inline void zend_fetch_property_address(zval *result, zval *container, uint32_t container_op_type, zval *prop_ptr, uint32_t prop_op_type, void **cache_slot, int type)
{
if (container_op_type != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) {
do {
- if (container_op_type == IS_VAR && UNEXPECTED(Z_ISERROR_P(container))) {
- ZVAL_ERROR(result);
- return;
- }
-
if (Z_ISREF_P(container)) {
container = Z_REFVAL_P(container);
if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
@@ -1924,7 +1932,9 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c
zval_ptr_dtor_nogc(container);
object_init(container);
} else {
- zend_error(E_WARNING, "Attempt to modify property of non-object");
+ if (container_op_type != IS_VAR || EXPECTED(!Z_ISERROR_P(container))) {
+ zend_error(E_WARNING, "Attempt to modify property of non-object");
+ }
ZVAL_ERROR(result);
return;
}
@@ -1960,6 +1970,7 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c
zval *ptr = Z_OBJ_HT_P(container)->get_property_ptr_ptr(container, prop_ptr, type, cache_slot);
if (NULL == ptr) {
if (EXPECTED(Z_OBJ_HT_P(container)->read_property)) {
+use_read_property:
ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type, cache_slot, result);
if (ptr != result) {
ZVAL_INDIRECT(result, ptr);
@@ -1974,12 +1985,7 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c
ZVAL_INDIRECT(result, ptr);
}
} else if (EXPECTED(Z_OBJ_HT_P(container)->read_property)) {
- zval *ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type, cache_slot, result);
- if (ptr != result) {
- ZVAL_INDIRECT(result, ptr);
- } else if (UNEXPECTED(Z_ISREF_P(ptr) && Z_REFCOUNT_P(ptr) == 1)) {
- ZVAL_UNREF(ptr);
- }
+ goto use_read_property;
} else {
zend_error(E_WARNING, "This object doesn't support property references");
ZVAL_ERROR(result);
@@ -2047,7 +2053,7 @@ static zend_always_inline void i_free_compiled_variables(zend_execute_data *exec
if (!Z_DELREF_P(cv)) {
zend_refcounted *r = Z_COUNTED_P(cv);
ZVAL_NULL(cv);
- zval_dtor_func_for_ptr(r);
+ zval_dtor_func(r);
} else {
GC_ZVAL_CHECK_POSSIBLE_ROOT(cv);
}
@@ -2063,16 +2069,17 @@ void zend_free_compiled_variables(zend_execute_data *execute_data) /* {{{ */
}
/* }}} */
-#ifdef ZEND_WIN32
-# define ZEND_VM_INTERRUPT_CHECK() do { \
- if (EG(timed_out)) { \
- zend_timeout(0); \
+static zend_never_inline ZEND_COLD ZEND_NORETURN void ZEND_FASTCALL zend_interrupt(void) /* {{{ */
+{
+ zend_timeout(0);
+}
+/* }}} */
+
+#define ZEND_VM_INTERRUPT_CHECK() do { \
+ if (UNEXPECTED(EG(timed_out))) { \
+ zend_interrupt(); \
} \
} while (0)
-#else
-# define ZEND_VM_INTERRUPT_CHECK() do { \
- } while (0)
-#endif
/*
* Stack Frame Layout (the whole stack frame is allocated at once)
@@ -2094,7 +2101,7 @@ void zend_free_compiled_variables(zend_execute_data *execute_data) /* {{{ */
* +----------------------------------------+
*/
-static zend_always_inline void i_init_func_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value, int check_this) /* {{{ */
+static zend_always_inline void i_init_func_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value) /* {{{ */
{
uint32_t first_extra_arg, num_args;
ZEND_ASSERT(EX(func) == (zend_function*)op_array);
@@ -2152,20 +2159,18 @@ static zend_always_inline void i_init_func_execute_data(zend_execute_data *execu
} while (var != end);
}
- if (check_this && op_array->this_var != (uint32_t)-1 && EXPECTED(Z_OBJ(EX(This)))) {
- ZVAL_OBJ(EX_VAR(op_array->this_var), Z_OBJ(EX(This)));
- GC_REFCOUNT(Z_OBJ(EX(This)))++;
- }
-
- if (UNEXPECTED(!op_array->run_time_cache)) {
- op_array->run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
- memset(op_array->run_time_cache, 0, op_array->cache_size);
- }
EX_LOAD_RUN_TIME_CACHE(op_array);
EX_LOAD_LITERALS(op_array);
EG(current_execute_data) = execute_data;
- ZEND_VM_INTERRUPT_CHECK();
+}
+/* }}} */
+
+static zend_never_inline void ZEND_FASTCALL init_func_run_time_cache(zend_op_array *op_array) /* {{{ */
+{
+ ZEND_ASSERT(op_array->run_time_cache == NULL);
+ op_array->run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
+ memset(op_array->run_time_cache, 0, op_array->cache_size);
}
/* }}} */
@@ -2177,13 +2182,6 @@ static zend_always_inline void i_init_code_execute_data(zend_execute_data *execu
EX(call) = NULL;
EX(return_value) = return_value;
- if (UNEXPECTED(op_array->this_var != (uint32_t)-1) && EXPECTED(Z_OBJ(EX(This)))) {
- GC_REFCOUNT(Z_OBJ(EX(This)))++;
- if (!zend_hash_str_add(EX(symbol_table), "this", sizeof("this")-1, &EX(This))) {
- GC_REFCOUNT(Z_OBJ(EX(This)))--;
- }
- }
-
zend_attach_symbol_table(execute_data);
if (!op_array->run_time_cache) {
@@ -2194,7 +2192,6 @@ static zend_always_inline void i_init_code_execute_data(zend_execute_data *execu
EX_LOAD_LITERALS(op_array);
EG(current_execute_data) = execute_data;
- ZEND_VM_INTERRUPT_CHECK();
}
/* }}} */
@@ -2206,14 +2203,7 @@ static zend_always_inline void i_init_execute_data(zend_execute_data *execute_da
EX(call) = NULL;
EX(return_value) = return_value;
- if (UNEXPECTED(EX(symbol_table) != NULL)) {
- if (UNEXPECTED(op_array->this_var != (uint32_t)-1) && EXPECTED(Z_OBJ(EX(This)))) {
- GC_REFCOUNT(Z_OBJ(EX(This)))++;
- if (!zend_hash_str_add(EX(symbol_table), "this", sizeof("this")-1, &EX(This))) {
- GC_REFCOUNT(Z_OBJ(EX(This)))--;
- }
- }
-
+ if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) {
zend_attach_symbol_table(execute_data);
} else {
uint32_t first_extra_arg, num_args;
@@ -2266,11 +2256,6 @@ static zend_always_inline void i_init_execute_data(zend_execute_data *execute_da
var++;
} while (var != end);
}
-
- if (op_array->this_var != (uint32_t)-1 && EXPECTED(Z_OBJ(EX(This)))) {
- ZVAL_OBJ(EX_VAR(op_array->this_var), Z_OBJ(EX(This)));
- GC_REFCOUNT(Z_OBJ(EX(This)))++;
- }
}
if (!op_array->run_time_cache) {
@@ -2285,65 +2270,6 @@ static zend_always_inline void i_init_execute_data(zend_execute_data *execute_da
EX_LOAD_LITERALS(op_array);
EG(current_execute_data) = execute_data;
- ZEND_VM_INTERRUPT_CHECK();
-}
-/* }}} */
-
-ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data *call, zend_op_array *op_array, zval *return_value) /* {{{ */
-{
- /*
- * Normally the execute_data is allocated on the VM stack (because it does
- * not actually do any allocation and thus is faster). For generators
- * though this behavior would be suboptimal, because the (rather large)
- * structure would have to be copied back and forth every time execution is
- * suspended or resumed. That's why for generators the execution context
- * is allocated using a separate VM stack, thus allowing to save and
- * restore it simply by replacing a pointer.
- */
- zend_execute_data *execute_data;
- uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
- size_t stack_size = (ZEND_CALL_FRAME_SLOT + MAX(op_array->last_var + op_array->T, num_args)) * sizeof(zval);
- uint32_t call_info;
-
- EG(vm_stack) = zend_vm_stack_new_page(
- EXPECTED(stack_size < ZEND_VM_STACK_FREE_PAGE_SIZE(1)) ?
- ZEND_VM_STACK_PAGE_SIZE(1) :
- ZEND_VM_STACK_PAGE_ALIGNED_SIZE(1, stack_size),
- NULL);
- EG(vm_stack_top) = EG(vm_stack)->top;
- EG(vm_stack_end) = EG(vm_stack)->end;
-
- call_info = ZEND_CALL_TOP_FUNCTION | ZEND_CALL_ALLOCATED | (ZEND_CALL_INFO(call) & (ZEND_CALL_CLOSURE|ZEND_CALL_RELEASE_THIS));
- if (Z_OBJ(call->This)) {
- call_info |= ZEND_CALL_RELEASE_THIS;
- }
- execute_data = zend_vm_stack_push_call_frame(
- call_info,
- (zend_function*)op_array,
- num_args,
- call->called_scope,
- Z_OBJ(call->This));
- EX(prev_execute_data) = NULL;
- EX_NUM_ARGS() = num_args;
-
- /* copy arguments */
- if (num_args > 0) {
- zval *arg_src = ZEND_CALL_ARG(call, 1);
- zval *arg_dst = ZEND_CALL_ARG(execute_data, 1);
- zval *end = arg_src + num_args;
-
- do {
- ZVAL_COPY_VALUE(arg_dst, arg_src);
- arg_src++;
- arg_dst++;
- } while (arg_src != end);
- }
-
- EX(symbol_table) = NULL;
-
- i_init_func_execute_data(execute_data, op_array, return_value, 1);
-
- return execute_data;
}
/* }}} */
@@ -2373,7 +2299,7 @@ static zend_execute_data *zend_vm_stack_copy_call_frame(zend_execute_data *call,
/* copy call frame into new stack segment */
new_call = zend_vm_stack_extend(used_stack * sizeof(zval));
*new_call = *call;
- ZEND_SET_CALL_INFO(new_call, ZEND_CALL_INFO(new_call) | ZEND_CALL_ALLOCATED);
+ ZEND_ADD_CALL_FLAG(new_call, ZEND_CALL_ALLOCATED);
if (passed_args) {
zval *src = ZEND_CALL_ARG(call, 1);
@@ -2473,6 +2399,7 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o
case ZEND_SEND_VAR_EX:
case ZEND_SEND_REF:
case ZEND_SEND_VAR_NO_REF:
+ case ZEND_SEND_VAR_NO_REF_EX:
case ZEND_SEND_USER:
if (level == 0) {
ZEND_CALL_NUM_ARGS(call) = opline->op2.num;
@@ -2601,6 +2528,356 @@ void zend_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t
cleanup_live_vars(execute_data, op_num, catch_op_num);
}
+static void zend_swap_operands(zend_op *op) /* {{{ */
+{
+ znode_op tmp;
+ zend_uchar tmp_type;
+
+ tmp = op->op1;
+ tmp_type = op->op1_type;
+ op->op1 = op->op2;
+ op->op1_type = op->op2_type;
+ op->op2 = tmp;
+ op->op2_type = tmp_type;
+}
+/* }}} */
+
+static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_string *function, uint32_t num_args) /* {{{ */
+{
+ zend_function *fbc;
+ zval *func;
+ zend_class_entry *called_scope;
+ zend_string *lcname;
+ const char *colon;
+
+ if ((colon = zend_memrchr(ZSTR_VAL(function), ':', ZSTR_LEN(function))) != NULL &&
+ colon > ZSTR_VAL(function) &&
+ *(colon-1) == ':'
+ ) {
+ zend_string *mname;
+ size_t cname_length = colon - ZSTR_VAL(function) - 1;
+ size_t mname_length = ZSTR_LEN(function) - cname_length - (sizeof("::") - 1);
+
+ lcname = zend_string_init(ZSTR_VAL(function), cname_length, 0);
+
+ called_scope = zend_fetch_class_by_name(lcname, NULL, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
+ if (UNEXPECTED(called_scope == NULL)) {
+ zend_string_release(lcname);
+ return NULL;
+ }
+
+ mname = zend_string_init(ZSTR_VAL(function) + (cname_length + sizeof("::") - 1), mname_length, 0);
+
+ if (called_scope->get_static_method) {
+ fbc = called_scope->get_static_method(called_scope, mname);
+ } else {
+ fbc = zend_std_get_static_method(called_scope, mname, NULL);
+ }
+ if (UNEXPECTED(fbc == NULL)) {
+ if (EXPECTED(!EG(exception))) {
+ zend_throw_error(NULL, "Call to undefined method %s::%s()", ZSTR_VAL(called_scope->name), ZSTR_VAL(mname));
+ }
+ zend_string_release(lcname);
+ zend_string_release(mname);
+ return NULL;
+ }
+
+ zend_string_release(lcname);
+ zend_string_release(mname);
+
+ if (UNEXPECTED(!(fbc->common.fn_flags & ZEND_ACC_STATIC))) {
+ if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
+ zend_error(E_DEPRECATED,
+ "Non-static method %s::%s() should not be called statically",
+ ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ return NULL;
+ }
+ } else {
+ zend_throw_error(
+ zend_ce_error,
+ "Non-static method %s::%s() cannot be called statically",
+ ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
+ return NULL;
+ }
+ }
+ } else {
+ if (ZSTR_VAL(function)[0] == '\\') {
+ lcname = zend_string_alloc(ZSTR_LEN(function) - 1, 0);
+ zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(function) + 1, ZSTR_LEN(function) - 1);
+ } else {
+ lcname = zend_string_tolower(function);
+ }
+ if (UNEXPECTED((func = zend_hash_find(EG(function_table), lcname)) == NULL)) {
+ zend_throw_error(NULL, "Call to undefined function %s()", ZSTR_VAL(function));
+ zend_string_release(lcname);
+ return NULL;
+ }
+ zend_string_release(lcname);
+
+ fbc = Z_FUNC_P(func);
+ called_scope = NULL;
+ }
+
+ if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
+ init_func_run_time_cache(&fbc->op_array);
+ }
+
+ return zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC,
+ fbc, num_args, called_scope, NULL);
+}
+/* }}} */
+
+static zend_never_inline zend_execute_data *zend_init_dynamic_call_object(zval *function, uint32_t num_args) /* {{{ */
+{
+ zend_function *fbc;
+ zend_class_entry *called_scope;
+ zend_object *object;
+ uint32_t call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC;
+
+ if (EXPECTED(Z_OBJ_HANDLER_P(function, get_closure)) &&
+ EXPECTED(Z_OBJ_HANDLER_P(function, get_closure)(function, &called_scope, &fbc, &object) == SUCCESS)) {
+
+ if (fbc->common.fn_flags & ZEND_ACC_CLOSURE) {
+ /* Delay closure destruction until its invocation */
+ ZEND_ASSERT(GC_TYPE((zend_object*)fbc->common.prototype) == IS_OBJECT);
+ GC_REFCOUNT((zend_object*)fbc->common.prototype)++;
+ call_info |= ZEND_CALL_CLOSURE;
+ } else if (object) {
+ call_info |= ZEND_CALL_RELEASE_THIS;
+ GC_REFCOUNT(object)++; /* For $this pointer */
+ }
+ } else {
+ zend_throw_error(NULL, "Function name must be a string");
+ return NULL;
+ }
+
+ if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
+ init_func_run_time_cache(&fbc->op_array);
+ }
+
+ return zend_vm_stack_push_call_frame(call_info,
+ fbc, num_args, called_scope, object);
+}
+/* }}} */
+
+static zend_never_inline zend_execute_data *zend_init_dynamic_call_array(zend_array *function, uint32_t num_args) /* {{{ */
+{
+ zend_function *fbc;
+ zend_class_entry *called_scope;
+ zend_object *object;
+ uint32_t call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC;
+
+ if (zend_hash_num_elements(function) == 2) {
+ zval *obj;
+ zval *method;
+ obj = zend_hash_index_find(function, 0);
+ method = zend_hash_index_find(function, 1);
+
+ if (UNEXPECTED(!obj) || UNEXPECTED(!method)) {
+ zend_throw_error(NULL, "Array callback has to contain indices 0 and 1");
+ return NULL;
+ }
+
+ ZVAL_DEREF(obj);
+ if (UNEXPECTED(Z_TYPE_P(obj) != IS_STRING) && UNEXPECTED(Z_TYPE_P(obj) != IS_OBJECT)) {
+ zend_throw_error(NULL, "First array member is not a valid class name or object");
+ return NULL;
+ }
+
+ ZVAL_DEREF(method);
+ if (UNEXPECTED(Z_TYPE_P(method) != IS_STRING)) {
+ zend_throw_error(NULL, "Second array member is not a valid method");
+ return NULL;
+ }
+
+ if (Z_TYPE_P(obj) == IS_STRING) {
+ object = NULL;
+ called_scope = zend_fetch_class_by_name(Z_STR_P(obj), NULL, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
+ if (UNEXPECTED(called_scope == NULL)) {
+ return NULL;
+ }
+
+ if (called_scope->get_static_method) {
+ fbc = called_scope->get_static_method(called_scope, Z_STR_P(method));
+ } else {
+ fbc = zend_std_get_static_method(called_scope, Z_STR_P(method), NULL);
+ }
+ if (UNEXPECTED(fbc == NULL)) {
+ if (EXPECTED(!EG(exception))) {
+ zend_throw_error(NULL, "Call to undefined method %s::%s()", ZSTR_VAL(called_scope->name), Z_STRVAL_P(method));
+ }
+ return NULL;
+ }
+ if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) {
+ if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
+ zend_error(E_DEPRECATED,
+ "Non-static method %s::%s() should not be called statically",
+ ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ return NULL;
+ }
+ } else {
+ zend_throw_error(
+ zend_ce_error,
+ "Non-static method %s::%s() cannot be called statically",
+ ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
+ return NULL;
+ }
+ }
+ } else {
+ called_scope = Z_OBJCE_P(obj);
+ object = Z_OBJ_P(obj);
+
+ fbc = Z_OBJ_HT_P(obj)->get_method(&object, Z_STR_P(method), NULL);
+ if (UNEXPECTED(fbc == NULL)) {
+ if (EXPECTED(!EG(exception))) {
+ zend_throw_error(NULL, "Call to undefined method %s::%s()", ZSTR_VAL(object->ce->name), Z_STRVAL_P(method));
+ }
+ return NULL;
+ }
+
+ if ((fbc->common.fn_flags & ZEND_ACC_STATIC) != 0) {
+ object = NULL;
+ } else {
+ call_info |= ZEND_CALL_RELEASE_THIS;
+ GC_REFCOUNT(object)++; /* For $this pointer */
+ }
+ }
+ } else {
+ zend_throw_error(NULL, "Function name must be a string");
+ return NULL;
+ }
+
+ if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!fbc->op_array.run_time_cache)) {
+ init_func_run_time_cache(&fbc->op_array);
+ }
+
+ return zend_vm_stack_push_call_frame(call_info,
+ fbc, num_args, called_scope, object);
+}
+/* }}} */
+
+#define ZEND_FAKE_OP_ARRAY ((zend_op_array*)(zend_intptr_t)-1)
+
+static zend_never_inline zend_op_array* ZEND_FASTCALL zend_include_or_eval(zval *inc_filename, int type) /* {{{ */
+{
+ zend_op_array *new_op_array = NULL;
+ zval tmp_inc_filename;
+
+ ZVAL_UNDEF(&tmp_inc_filename);
+ if (Z_TYPE_P(inc_filename) != IS_STRING) {
+ ZVAL_STR(&tmp_inc_filename, zval_get_string(inc_filename));
+ inc_filename = &tmp_inc_filename;
+ }
+
+ if (type != ZEND_EVAL && strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename)) {
+ if (type == ZEND_INCLUDE_ONCE || type == ZEND_INCLUDE) {
+ zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename));
+ } else {
+ zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename));
+ }
+ } else {
+ switch (type) {
+ case ZEND_INCLUDE_ONCE:
+ case ZEND_REQUIRE_ONCE: {
+ zend_file_handle file_handle;
+ zend_string *resolved_path;
+
+ resolved_path = zend_resolve_path(Z_STRVAL_P(inc_filename), (int)Z_STRLEN_P(inc_filename));
+ if (resolved_path) {
+ if (zend_hash_exists(&EG(included_files), resolved_path)) {
+ goto already_compiled;
+ }
+ } else {
+ resolved_path = zend_string_copy(Z_STR_P(inc_filename));
+ }
+
+ if (SUCCESS == zend_stream_open(ZSTR_VAL(resolved_path), &file_handle)) {
+
+ if (!file_handle.opened_path) {
+ file_handle.opened_path = zend_string_copy(resolved_path);
+ }
+
+ if (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path)) {
+ zend_op_array *op_array = zend_compile_file(&file_handle, (type==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE));
+ zend_destroy_file_handle(&file_handle);
+ zend_string_release(resolved_path);
+ if (Z_TYPE(tmp_inc_filename) != IS_UNDEF) {
+ zend_string_release(Z_STR(tmp_inc_filename));
+ }
+ return op_array;
+ } else {
+ zend_file_handle_dtor(&file_handle);
+already_compiled:
+ new_op_array = ZEND_FAKE_OP_ARRAY;
+ }
+ } else {
+ if (type == ZEND_INCLUDE_ONCE) {
+ zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename));
+ } else {
+ zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename));
+ }
+ }
+ zend_string_release(resolved_path);
+ }
+ break;
+ case ZEND_INCLUDE:
+ case ZEND_REQUIRE:
+ new_op_array = compile_filename(type, inc_filename);
+ break;
+ case ZEND_EVAL: {
+ char *eval_desc = zend_make_compiled_string_description("eval()'d code");
+ new_op_array = zend_compile_string(inc_filename, eval_desc);
+ efree(eval_desc);
+ }
+ break;
+ EMPTY_SWITCH_DEFAULT_CASE()
+ }
+ }
+ if (Z_TYPE(tmp_inc_filename) != IS_UNDEF) {
+ zend_string_release(Z_STR(tmp_inc_filename));
+ }
+ return new_op_array;
+}
+/* }}} */
+
+static zend_never_inline int zend_do_fcall_overloaded(zend_function *fbc, zend_execute_data *call, zval *ret) /* {{{ */
+{
+ zend_object *object;
+
+ /* Not sure what should be done here if it's a static method */
+ if (UNEXPECTED(Z_TYPE(call->This) != IS_OBJECT)) {
+ zend_vm_stack_free_args(call);
+ if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
+ zend_string_release(fbc->common.function_name);
+ }
+ efree(fbc);
+ zend_vm_stack_free_call_frame(call);
+
+ zend_throw_error(NULL, "Cannot call overloaded function for non-object");
+ return 0;
+ }
+
+ object = Z_OBJ(call->This);
+
+ ZVAL_NULL(ret);
+
+ EG(current_execute_data) = call;
+ object->handlers->call_method(fbc->common.function_name, object, call, ret);
+ EG(current_execute_data) = call->prev_execute_data;
+
+ zend_vm_stack_free_args(call);
+
+ if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
+ zend_string_release(fbc->common.function_name);
+ }
+ efree(fbc);
+
+ return 1;
+}
+/* }}} */
+
#ifdef HAVE_GCC_GLOBAL_REGS
# if defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(i386)
# define ZEND_VM_FP_GLOBAL_REG "%esi"
@@ -2686,10 +2963,34 @@ void zend_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t
} \
ZEND_VM_CONTINUE(); \
} while (0)
+# define ZEND_VM_SMART_BRANCH_JMPZ(_result, _check) do { \
+ if ((_check) && UNEXPECTED(EG(exception))) { \
+ HANDLE_EXCEPTION(); \
+ } \
+ if (_result) { \
+ ZEND_VM_SET_NEXT_OPCODE(opline + 2); \
+ } else { \
+ ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline + 1, (opline+1)->op2)); \
+ } \
+ ZEND_VM_CONTINUE(); \
+ } while (0)
+# define ZEND_VM_SMART_BRANCH_JMPNZ(_result, _check) do { \
+ if ((_check) && UNEXPECTED(EG(exception))) { \
+ HANDLE_EXCEPTION(); \
+ } \
+ if (!(_result)) { \
+ ZEND_VM_SET_NEXT_OPCODE(opline + 2); \
+ } else { \
+ ZEND_VM_SET_OPCODE(OP_JMP_ADDR(opline + 1, (opline+1)->op2)); \
+ } \
+ ZEND_VM_CONTINUE(); \
+ } while (0)
#else
# define ZEND_VM_REPEATABLE_OPCODE
# define ZEND_VM_REPEAT_OPCODE(_opcode)
# define ZEND_VM_SMART_BRANCH(_result, _check)
+# define ZEND_VM_SMART_BRANCH_JMPZ(_result, _check)
+# define ZEND_VM_SMART_BRANCH_JMPNZ(_result, _check)
#endif
#ifdef __GNUC__
@@ -2740,11 +3041,6 @@ ZEND_API int ZEND_FASTCALL zend_check_arg_type(zend_function *zf, uint32_t arg_n
return zend_verify_arg_type(zf, arg_num, arg, default_value, cache_slot);
}
-ZEND_API void ZEND_FASTCALL zend_check_missing_arg(zend_execute_data *execute_data, uint32_t arg_num, void **cache_slot)
-{
- zend_verify_missing_arg(execute_data, arg_num, cache_slot);
-}
-
/*
* Local variables:
* tab-width: 4