Last active
August 29, 2015 14:07
-
-
Save dstogov/799c115792973129f5ba to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c | |
index 5d3ee24..a8bfdb1 100644 | |
--- a/Zend/zend_compile.c | |
+++ b/Zend/zend_compile.c | |
@@ -2281,8 +2281,6 @@ void zend_compile_assign(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */ | |
opline->opcode = ZEND_ASSIGN_DIM; | |
opline = zend_emit_op_data(&expr_node TSRMLS_CC); | |
- opline->op2.var = get_temporary_variable(CG(active_op_array)); | |
- opline->op2_type = IS_VAR; | |
return; | |
case ZEND_AST_PROP: | |
offset = zend_delayed_compile_begin(TSRMLS_C); | |
@@ -2374,8 +2372,6 @@ void zend_compile_compound_assign(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ | |
opline->extended_value = ZEND_ASSIGN_DIM; | |
opline = zend_emit_op_data(&expr_node TSRMLS_CC); | |
- opline->op2.var = get_temporary_variable(CG(active_op_array)); | |
- opline->op2_type = IS_VAR; | |
return; | |
case ZEND_AST_PROP: | |
offset = zend_delayed_compile_begin(TSRMLS_C); | |
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c | |
index 58038c9..7c6deca 100644 | |
--- a/Zend/zend_execute.c | |
+++ b/Zend/zend_execute.c | |
@@ -1048,12 +1048,61 @@ str_index: | |
return retval; | |
} | |
-static zend_always_inline zval *zend_fetch_dimension_address(zval *result, zval *container_ptr, zval *dim, int dim_type, int type, int is_ref, int allow_str_offset TSRMLS_DC) | |
+static zend_never_inline zend_long zend_check_string_offset(zval *container, zval *dim, int type TSRMLS_DC) | |
+{ | |
+ zend_long offset; | |
+ | |
+ if (dim == NULL) { | |
+ zend_error_noreturn(E_ERROR, "[] operator not supported for strings"); | |
+ } | |
+ | |
+ 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; | |
+ default: | |
+ zend_error(E_WARNING, "Illegal offset type"); | |
+ break; | |
+ } | |
+ | |
+ offset = zval_get_long(dim); | |
+ } else { | |
+ offset = Z_LVAL_P(dim); | |
+ } | |
+ | |
+ return offset; | |
+} | |
+ | |
+static zend_always_inline zend_long zend_fetch_string_offset(zval *container, zval *dim, int type TSRMLS_DC) | |
+{ | |
+ zend_long offset = zend_check_string_offset(container, dim, type TSRMLS_CC); | |
+ | |
+ 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_always_inline void zend_fetch_dimension_address(zval *result, zval *container, zval *dim, int dim_type, int type, int is_ref TSRMLS_DC) | |
{ | |
zval *retval; | |
- zval *container = container_ptr; | |
- ZVAL_DEREF(container); | |
if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { | |
SEPARATE_ARRAY(container); | |
fetch_from_array: | |
@@ -1071,8 +1120,6 @@ fetch_from_array: | |
} | |
ZVAL_INDIRECT(result, retval); | |
} else if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) { | |
- zend_long offset; | |
- | |
if (type != BP_VAR_UNSET && UNEXPECTED(Z_STRLEN_P(container) == 0)) { | |
zval_ptr_dtor_nogc(container); | |
convert_to_array: | |
@@ -1081,49 +1128,9 @@ convert_to_array: | |
goto fetch_from_array; | |
} | |
- if (dim == NULL) { | |
- zend_error_noreturn(E_ERROR, "[] operator not supported for strings"); | |
- } | |
- | |
- 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; | |
- default: | |
- zend_error(E_WARNING, "Illegal offset type"); | |
- break; | |
- } | |
- | |
- offset = zval_get_long(dim); | |
- } else { | |
- offset = Z_LVAL_P(dim); | |
- } | |
- | |
- if (allow_str_offset) { | |
- if (Z_REFCOUNTED_P(container)) { | |
- if (Z_REFCOUNT_P(container) > 1) { | |
- Z_DELREF_P(container); | |
- zval_copy_ctor_func(container); | |
- } | |
- Z_ADDREF_P(container); | |
- } | |
- ZVAL_LONG(result, offset); | |
- return container; /* assignment to string offset */ | |
- } else { | |
- ZVAL_INDIRECT(result, NULL); /* wrong string offset */ | |
- } | |
+ zend_check_string_offset(container, dim, type TSRMLS_CC); | |
+ | |
+ ZVAL_INDIRECT(result, NULL); /* wrong string offset */ | |
} else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { | |
if (!Z_OBJ_HT_P(container)->read_dimension) { | |
zend_error_noreturn(E_ERROR, "Cannot use object as array"); | |
@@ -1185,32 +1192,26 @@ convert_to_array: | |
ZVAL_INDIRECT(result, &EG(error_zval)); | |
} | |
} | |
- return NULL; /* not an assignment to string offset */ | |
} | |
static zend_never_inline void zend_fetch_dimension_address_W(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC) | |
{ | |
- zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W, 0, 0 TSRMLS_CC); | |
-} | |
- | |
-static zend_never_inline zval *zend_fetch_dimension_address_W_str(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC) | |
-{ | |
- return zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W, 0, 1 TSRMLS_CC); | |
+ zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W, 0 TSRMLS_CC); | |
} | |
static zend_never_inline void zend_fetch_dimension_address_W_ref(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC) | |
{ | |
- zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W, 1, 0 TSRMLS_CC); | |
+ zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_W, 1 TSRMLS_CC); | |
} | |
static zend_never_inline void zend_fetch_dimension_address_RW(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC) | |
{ | |
- zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_RW, 0, 0 TSRMLS_CC); | |
+ zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_RW, 0 TSRMLS_CC); | |
} | |
static zend_never_inline void zend_fetch_dimension_address_UNSET(zval *result, zval *container_ptr, zval *dim, int dim_type TSRMLS_DC) | |
{ | |
- zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_UNSET, 0, 0 TSRMLS_CC); | |
+ zend_fetch_dimension_address(result, container_ptr, dim, dim_type, BP_VAR_UNSET, 0 TSRMLS_CC); | |
} | |
static zend_always_inline void zend_fetch_dimension_address_read(zval *result, zval *container, zval *dim, int dim_type, int type TSRMLS_DC) | |
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h | |
index 0c5ef75..f41365b 100644 | |
--- a/Zend/zend_vm_def.h | |
+++ b/Zend/zend_vm_def.h | |
@@ -423,15 +423,19 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMP|VAR | |
ZEND_VM_HELPER_EX(zend_binary_assign_op_dim_helper, VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV, int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC)) | |
{ | |
USE_OPLINE | |
- zend_free_op free_op1, free_op2, free_op_data2, free_op_data1; | |
- zval *var_ptr; | |
+ zend_free_op free_op1, free_op2, free_op_data1; | |
+ zval *var_ptr, rv; | |
zval *value, *container; | |
SAVE_OPLINE(); | |
container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW); | |
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { | |
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); | |
- } else if (OP1_TYPE == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { | |
+ } | |
+ if (OP1_TYPE != IS_UNUSED) { | |
+ ZVAL_DEREF(container); | |
+ } | |
+ if (OP1_TYPE == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { | |
if (OP1_TYPE == IS_VAR && !OP1_FREE) { | |
Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ | |
} | |
@@ -439,9 +443,10 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_dim_helper, VAR|UNUSED|CV, CONST|TMP|VAR | |
} else { | |
zval *dim = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R); | |
- zend_fetch_dimension_address_RW(EX_VAR((opline+1)->op2.var), container, dim, OP2_TYPE TSRMLS_CC); | |
+ zend_fetch_dimension_address_RW(&rv, container, dim, OP2_TYPE TSRMLS_CC); | |
value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); | |
- var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); | |
+ ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); | |
+ var_ptr = Z_INDIRECT(rv); | |
} | |
if (UNEXPECTED(var_ptr == NULL)) { | |
@@ -465,7 +470,6 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_dim_helper, VAR|UNUSED|CV, CONST|TMP|VAR | |
FREE_OP2(); | |
FREE_OP(free_op_data1); | |
- FREE_OP_VAR_PTR(free_op_data2); | |
FREE_OP1_VAR_PTR(); | |
CHECK_EXCEPTION(); | |
ZEND_VM_INC_OPCODE(); | |
@@ -1195,6 +1199,7 @@ ZEND_VM_HANDLER(84, ZEND_FETCH_DIM_W, VAR|CV, CONST|TMP|VAR|UNUSED|CV) | |
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { | |
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); | |
} | |
+ ZVAL_DEREF(container); | |
if (EXPECTED(opline->extended_value == 0)) { | |
zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R), OP2_TYPE TSRMLS_CC); | |
} else { | |
@@ -1221,6 +1226,7 @@ ZEND_VM_HANDLER(87, ZEND_FETCH_DIM_RW, VAR|CV, CONST|TMP|VAR|UNUSED|CV) | |
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { | |
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); | |
} | |
+ ZVAL_DEREF(container); | |
zend_fetch_dimension_address_RW(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R), OP2_TYPE TSRMLS_CC); | |
FREE_OP2(); | |
if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1.var)) { | |
@@ -1262,6 +1268,7 @@ ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, CONST|TMP|VAR|CV, CONST|TMP|VAR|UNU | |
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { | |
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); | |
} | |
+ ZVAL_DEREF(container); | |
zend_fetch_dimension_address_W(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R), OP2_TYPE TSRMLS_CC); | |
if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1.var)) { | |
EXTRACT_ZVAL_PTR(EX_VAR(opline->result.var)); | |
@@ -1293,6 +1300,7 @@ ZEND_VM_HANDLER(96, ZEND_FETCH_DIM_UNSET, VAR|CV, CONST|TMP|VAR|CV) | |
if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { | |
zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); | |
} | |
+ ZVAL_DEREF(container); | |
zend_fetch_dimension_address_UNSET(EX_VAR(opline->result.var), container, GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R), OP2_TYPE TSRMLS_CC); | |
FREE_OP2(); | |
if (OP1_TYPE == IS_VAR && READY_TO_DESTROY(free_op1.var)) { | |
@@ -1549,19 +1557,25 @@ ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMP|VAR|UNUSED|CV) | |
zend_assign_to_object(RETURN_VALUE_USED(opline)?EX_VAR(opline->result.var):NULL, object_ptr, OP1_TYPE, property_name, (opline+1)->op1_type, &(opline+1)->op1, execute_data, ZEND_ASSIGN_DIM, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property_name)) : NULL) TSRMLS_CC); | |
FREE_OP2(); | |
} else { | |
- zend_free_op free_op2, free_op_data1, free_op_data2; | |
+ zend_free_op free_op2, free_op_data1; | |
+ zval rv; | |
zval *value; | |
zval *dim = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R); | |
zval *variable_ptr; | |
- variable_ptr = zend_fetch_dimension_address_W_str(EX_VAR((opline+1)->op2.var), object_ptr, dim, OP2_TYPE TSRMLS_CC); | |
- FREE_OP2(); | |
- value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); | |
- if (UNEXPECTED(variable_ptr != NULL)) { | |
- zend_assign_to_string_offset(variable_ptr, Z_LVAL_P(EX_VAR((opline+1)->op2.var)), value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); | |
+ if (UNEXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && | |
+ EXPECTED(Z_STRLEN_P(object_ptr) != 0)) { | |
+ zend_long offset = zend_fetch_string_offset(object_ptr, dim, BP_VAR_W TSRMLS_CC); | |
+ FREE_OP2(); | |
+ value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); | |
+ zend_assign_to_string_offset(object_ptr, offset, value, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); | |
FREE_OP(free_op_data1); | |
} else { | |
- variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); | |
+ zend_fetch_dimension_address_W(&rv, object_ptr, dim, OP2_TYPE TSRMLS_CC); | |
+ FREE_OP2(); | |
+ value = get_zval_ptr_deref((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); | |
+ ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); | |
+ variable_ptr = Z_INDIRECT(rv); | |
if (UNEXPECTED(variable_ptr == &EG(error_zval))) { | |
FREE_OP(free_op_data1); | |
if (RETURN_VALUE_USED(opline)) { | |
@@ -1575,7 +1589,6 @@ ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMP|VAR|UNUSED|CV) | |
if (RETURN_VALUE_USED(opline)) { | |
ZVAL_COPY(EX_VAR(opline->result.var), value); | |
} | |
- FREE_OP_VAR_PTR(free_op_data2); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment