From: Anatol Belski Date: Sat, 6 Sep 2014 22:54:47 +0000 (+0200) Subject: fix 64 bit string index usage X-Git-Tag: PRE_PHP7_REMOVALS~105 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=acad6f4700aa92cb7ba4a66a1472ebc4485b9e16;p=php fix 64 bit string index usage --- diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 5cddebd2a4..586eddec59 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -755,17 +755,46 @@ static inline void zend_assign_to_object(zval *retval, zval *object_ptr, zval *p FREE_OP_IF_VAR(free_value); } -static void zend_assign_to_string_offset(zval *str_offset, zval *value, int value_type, zval *result TSRMLS_DC) +static zend_always_inline zend_long zend_fetch_dimension_str_offset(zval *dim, int type TSRMLS_DC) +{ + zend_long offset; + + 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 void zend_assign_to_string_offset(zval *str_offset, zend_long offset, zval *value, int value_type, zval *result TSRMLS_DC) { zval *str = Z_STR_OFFSET_STR_P(str_offset); - /* XXX String offset is uint32_t in _zval_struct, so can address only 2^32+1 space. - To make the offset get over that barier, we need to make str_offset size_t and that - would grow zval size by 8 bytes (currently from 16 to 24) on 64 bit build. */ - uint32_t offset = Z_STR_OFFSET_IDX_P(str_offset); zend_string *old_str; - if ((int)offset < 0) { - zend_error(E_WARNING, "Illegal string offset: %d", offset); + if (offset < 0) { + zend_error(E_WARNING, "Illegal string offset: " ZEND_LONG_FMT, offset); zend_string_release(Z_STR_P(str)); if (result) { ZVAL_NULL(result); @@ -775,7 +804,7 @@ static void zend_assign_to_string_offset(zval *str_offset, zval *value, int valu old_str = Z_STR_P(str); if (offset >= Z_STRLEN_P(str)) { - int old_len = Z_STRLEN_P(str); + zend_long old_len = Z_STRLEN_P(str); Z_STR_P(str) = zend_string_realloc(Z_STR_P(str), offset + 1, 0); Z_TYPE_INFO_P(str) = IS_STRING_EX; memset(Z_STRVAL_P(str) + old_len, ' ', offset - old_len); @@ -1141,6 +1170,7 @@ convert_to_array: zend_hash_init(Z_ARRVAL_P(container), 8, NULL, ZVAL_PTR_DTOR, 0); goto fetch_from_array; } + if (dim == NULL) { zend_error_noreturn(E_ERROR, "[] operator not supported for strings"); } @@ -1149,34 +1179,13 @@ convert_to_array: SEPARATE_STRING(container); } - 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); - } + /* This is a dummy, the offset is broken if we're here. + What matters is merely the IS_STR_OFFSET type set below.*/ + offset = zend_fetch_dimension_str_offset(dim, type TSRMLS_CC); if (!IS_INTERNED(Z_STR_P(container))) zend_string_addref(Z_STR_P(container)); ZVAL_STR_OFFSET(result, container, 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"); diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 548bd5a2e0..389d3e5cd2 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -131,7 +131,6 @@ struct _zval_struct { union { uint32_t var_flags; uint32_t next; /* hash collision chain */ - uint32_t str_offset; /* string offset */ uint32_t cache_slot; /* literal cache slot */ uint32_t lineno; /* line number (for ast nodes) */ uint32_t silence_num; /* BEGIN_SILENCE op number */ @@ -656,12 +655,8 @@ static inline zend_uchar zval_get_type(const zval* pz) { #define Z_STR_OFFSET_STR(zval) Z_INDIRECT(zval) #define Z_STR_OFFSET_STR_P(zval_p) Z_STR_OFFSET_STR(*(zval_p)) -#define Z_STR_OFFSET_IDX(zval) (zval).u2.str_offset -#define Z_STR_OFFSET_IDX_P(zval_p) Z_STR_OFFSET_IDX(*(zval_p)) - #define ZVAL_STR_OFFSET(z, s, i) do { \ Z_STR_OFFSET_STR_P(z) = (s); \ - Z_STR_OFFSET_IDX_P(z) = (i); \ Z_TYPE_INFO_P(z) = IS_STR_OFFSET; \ } while (0) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index fc8f28b47e..2d0ea7e002 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1635,15 +1635,34 @@ ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMP|VAR|UNUSED|CV) zend_free_op free_op2, free_op_data1, free_op_data2; zval *value; zval *dim = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R); - zval *variable_ptr; + zval *variable_ptr = EX_VAR((opline+1)->op2.var); + zend_long offset = 0; - zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, OP2_TYPE TSRMLS_CC); + if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { + + if (UNEXPECTED(Z_STRLEN_P(object_ptr) == 0)) { + goto string_failed; + } + if (dim == NULL) { + zend_error_noreturn(E_ERROR, "[] operator not supported for strings"); + } + + SEPARATE_STRING(object_ptr); + + offset = zend_fetch_dimension_str_offset(dim, BP_VAR_W TSRMLS_CC); + + if (!IS_INTERNED(Z_STR_P(object_ptr))) zend_string_addref(Z_STR_P(object_ptr)); + ZVAL_STR_OFFSET(variable_ptr, object_ptr, offset); + } else { +string_failed: + zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, OP2_TYPE TSRMLS_CC); + } FREE_OP2(); value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + zend_assign_to_string_offset(variable_ptr, offset, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) { if (IS_TMP_FREE(free_op_data1)) { zval_dtor(value); @@ -1685,9 +1704,7 @@ ZEND_VM_HANDLER(38, ZEND_ASSIGN, VAR|CV, CONST|TMP|VAR|CV) value = GET_OP2_ZVAL_PTR(BP_VAR_R); variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); - if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, OP2_TYPE, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); - } else if (OP1_TYPE == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { + if (OP1_TYPE == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { if (IS_OP2_TMP_FREE()) { zval_dtor(value); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index fbbc46125a..690b07ef94 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -18345,14 +18345,33 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HAN zend_free_op free_op_data1, free_op_data2; zval *value; zval *dim = opline->op2.zv; - zval *variable_ptr; + zval *variable_ptr = EX_VAR((opline+1)->op2.var); + zend_long offset = 0; - zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_CONST TSRMLS_CC); + if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { + + if (UNEXPECTED(Z_STRLEN_P(object_ptr) == 0)) { + goto string_failed; + } + if (dim == NULL) { + zend_error_noreturn(E_ERROR, "[] operator not supported for strings"); + } + + SEPARATE_STRING(object_ptr); + + offset = zend_fetch_dimension_str_offset(dim, BP_VAR_W TSRMLS_CC); + + if (!IS_INTERNED(Z_STR_P(object_ptr))) zend_string_addref(Z_STR_P(object_ptr)); + ZVAL_STR_OFFSET(variable_ptr, object_ptr, offset); + } else { +string_failed: + zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_CONST TSRMLS_CC); + } value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + zend_assign_to_string_offset(variable_ptr, offset, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) { if (IS_TMP_FREE(free_op_data1)) { zval_dtor(value); @@ -18394,9 +18413,7 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER value = opline->op2.zv; variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, IS_CONST, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); - } else if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { + if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { if (0) { zval_dtor(value); } @@ -20584,15 +20601,34 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDL zend_free_op free_op2, free_op_data1, free_op_data2; zval *value; zval *dim = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - zval *variable_ptr; + zval *variable_ptr = EX_VAR((opline+1)->op2.var); + zend_long offset = 0; + + if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { + + if (UNEXPECTED(Z_STRLEN_P(object_ptr) == 0)) { + goto string_failed; + } + if (dim == NULL) { + zend_error_noreturn(E_ERROR, "[] operator not supported for strings"); + } + + SEPARATE_STRING(object_ptr); - zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_TMP_VAR TSRMLS_CC); + offset = zend_fetch_dimension_str_offset(dim, BP_VAR_W TSRMLS_CC); + + if (!IS_INTERNED(Z_STR_P(object_ptr))) zend_string_addref(Z_STR_P(object_ptr)); + ZVAL_STR_OFFSET(variable_ptr, object_ptr, offset); + } else { +string_failed: + zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_TMP_VAR TSRMLS_CC); + } zval_dtor(free_op2.var); value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + zend_assign_to_string_offset(variable_ptr, offset, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) { if (IS_TMP_FREE(free_op_data1)) { zval_dtor(value); @@ -20634,9 +20670,7 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_A value = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, IS_TMP_VAR, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); - } else if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { + if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { if (1) { zval_dtor(value); } @@ -22732,15 +22766,34 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDL zend_free_op free_op2, free_op_data1, free_op_data2; zval *value; zval *dim = _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - zval *variable_ptr; + zval *variable_ptr = EX_VAR((opline+1)->op2.var); + zend_long offset = 0; + + if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { + + if (UNEXPECTED(Z_STRLEN_P(object_ptr) == 0)) { + goto string_failed; + } + if (dim == NULL) { + zend_error_noreturn(E_ERROR, "[] operator not supported for strings"); + } - zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_VAR TSRMLS_CC); + SEPARATE_STRING(object_ptr); + + offset = zend_fetch_dimension_str_offset(dim, BP_VAR_W TSRMLS_CC); + + if (!IS_INTERNED(Z_STR_P(object_ptr))) zend_string_addref(Z_STR_P(object_ptr)); + ZVAL_STR_OFFSET(variable_ptr, object_ptr, offset); + } else { +string_failed: + zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_VAR TSRMLS_CC); + } zval_ptr_dtor_nogc(free_op2.var); value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + zend_assign_to_string_offset(variable_ptr, offset, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) { if (IS_TMP_FREE(free_op_data1)) { zval_dtor(value); @@ -22782,9 +22835,7 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_A value = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, IS_VAR, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); - } else if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { + if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { if (0) { zval_dtor(value); } @@ -24388,14 +24439,33 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HA zend_free_op free_op_data1, free_op_data2; zval *value; zval *dim = NULL; - zval *variable_ptr; + zval *variable_ptr = EX_VAR((opline+1)->op2.var); + zend_long offset = 0; + + if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { + + if (UNEXPECTED(Z_STRLEN_P(object_ptr) == 0)) { + goto string_failed; + } + if (dim == NULL) { + zend_error_noreturn(E_ERROR, "[] operator not supported for strings"); + } + + SEPARATE_STRING(object_ptr); + + offset = zend_fetch_dimension_str_offset(dim, BP_VAR_W TSRMLS_CC); - zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_UNUSED TSRMLS_CC); + if (!IS_INTERNED(Z_STR_P(object_ptr))) zend_string_addref(Z_STR_P(object_ptr)); + ZVAL_STR_OFFSET(variable_ptr, object_ptr, offset); + } else { +string_failed: + zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_UNUSED TSRMLS_CC); + } value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + zend_assign_to_string_offset(variable_ptr, offset, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) { if (IS_TMP_FREE(free_op_data1)) { zval_dtor(value); @@ -26129,14 +26199,33 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLE zend_free_op free_op_data1, free_op_data2; zval *value; zval *dim = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); - zval *variable_ptr; + zval *variable_ptr = EX_VAR((opline+1)->op2.var); + zend_long offset = 0; + + if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { + + if (UNEXPECTED(Z_STRLEN_P(object_ptr) == 0)) { + goto string_failed; + } + if (dim == NULL) { + zend_error_noreturn(E_ERROR, "[] operator not supported for strings"); + } + + SEPARATE_STRING(object_ptr); + + offset = zend_fetch_dimension_str_offset(dim, BP_VAR_W TSRMLS_CC); - zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_CV TSRMLS_CC); + if (!IS_INTERNED(Z_STR_P(object_ptr))) zend_string_addref(Z_STR_P(object_ptr)); + ZVAL_STR_OFFSET(variable_ptr, object_ptr, offset); + } else { +string_failed: + zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_CV TSRMLS_CC); + } value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + zend_assign_to_string_offset(variable_ptr, offset, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) { if (IS_TMP_FREE(free_op_data1)) { zval_dtor(value); @@ -26178,9 +26267,7 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_AR value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC); - if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, IS_CV, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); - } else if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { + if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { if (0) { zval_dtor(value); } @@ -35598,14 +35685,33 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HAND zend_free_op free_op_data1, free_op_data2; zval *value; zval *dim = opline->op2.zv; - zval *variable_ptr; + zval *variable_ptr = EX_VAR((opline+1)->op2.var); + zend_long offset = 0; - zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_CONST TSRMLS_CC); + if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { + + if (UNEXPECTED(Z_STRLEN_P(object_ptr) == 0)) { + goto string_failed; + } + if (dim == NULL) { + zend_error_noreturn(E_ERROR, "[] operator not supported for strings"); + } + + SEPARATE_STRING(object_ptr); + + offset = zend_fetch_dimension_str_offset(dim, BP_VAR_W TSRMLS_CC); + + if (!IS_INTERNED(Z_STR_P(object_ptr))) zend_string_addref(Z_STR_P(object_ptr)); + ZVAL_STR_OFFSET(variable_ptr, object_ptr, offset); + } else { +string_failed: + zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_CONST TSRMLS_CC); + } value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + zend_assign_to_string_offset(variable_ptr, offset, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) { if (IS_TMP_FREE(free_op_data1)) { zval_dtor(value); @@ -35647,9 +35753,7 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ value = opline->op2.zv; variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); - if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, IS_CONST, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); - } else if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { + if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { if (0) { zval_dtor(value); } @@ -37651,15 +37755,34 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLE zend_free_op free_op2, free_op_data1, free_op_data2; zval *value; zval *dim = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - zval *variable_ptr; + zval *variable_ptr = EX_VAR((opline+1)->op2.var); + zend_long offset = 0; + + if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { + + if (UNEXPECTED(Z_STRLEN_P(object_ptr) == 0)) { + goto string_failed; + } + if (dim == NULL) { + zend_error_noreturn(E_ERROR, "[] operator not supported for strings"); + } + + SEPARATE_STRING(object_ptr); - zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_TMP_VAR TSRMLS_CC); + offset = zend_fetch_dimension_str_offset(dim, BP_VAR_W TSRMLS_CC); + + if (!IS_INTERNED(Z_STR_P(object_ptr))) zend_string_addref(Z_STR_P(object_ptr)); + ZVAL_STR_OFFSET(variable_ptr, object_ptr, offset); + } else { +string_failed: + zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_TMP_VAR TSRMLS_CC); + } zval_dtor(free_op2.var); value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + zend_assign_to_string_offset(variable_ptr, offset, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) { if (IS_TMP_FREE(free_op_data1)) { zval_dtor(value); @@ -37701,9 +37824,7 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR value = _get_zval_ptr_tmp(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); - if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, IS_TMP_VAR, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); - } else if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { + if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { if (1) { zval_dtor(value); } @@ -39680,15 +39801,34 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLE zend_free_op free_op2, free_op_data1, free_op_data2; zval *value; zval *dim = _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); - zval *variable_ptr; + zval *variable_ptr = EX_VAR((opline+1)->op2.var); + zend_long offset = 0; + + if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { + + if (UNEXPECTED(Z_STRLEN_P(object_ptr) == 0)) { + goto string_failed; + } + if (dim == NULL) { + zend_error_noreturn(E_ERROR, "[] operator not supported for strings"); + } - zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_VAR TSRMLS_CC); + SEPARATE_STRING(object_ptr); + + offset = zend_fetch_dimension_str_offset(dim, BP_VAR_W TSRMLS_CC); + + if (!IS_INTERNED(Z_STR_P(object_ptr))) zend_string_addref(Z_STR_P(object_ptr)); + ZVAL_STR_OFFSET(variable_ptr, object_ptr, offset); + } else { +string_failed: + zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_VAR TSRMLS_CC); + } zval_ptr_dtor_nogc(free_op2.var); value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + zend_assign_to_string_offset(variable_ptr, offset, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) { if (IS_TMP_FREE(free_op_data1)) { zval_dtor(value); @@ -39730,9 +39870,7 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR value = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2 TSRMLS_CC); variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); - if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, IS_VAR, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); - } else if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { + if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { if (0) { zval_dtor(value); } @@ -41216,14 +41354,33 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HAN zend_free_op free_op_data1, free_op_data2; zval *value; zval *dim = NULL; - zval *variable_ptr; + zval *variable_ptr = EX_VAR((opline+1)->op2.var); + zend_long offset = 0; + + if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { + + if (UNEXPECTED(Z_STRLEN_P(object_ptr) == 0)) { + goto string_failed; + } + if (dim == NULL) { + zend_error_noreturn(E_ERROR, "[] operator not supported for strings"); + } + + SEPARATE_STRING(object_ptr); + + offset = zend_fetch_dimension_str_offset(dim, BP_VAR_W TSRMLS_CC); - zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_UNUSED TSRMLS_CC); + if (!IS_INTERNED(Z_STR_P(object_ptr))) zend_string_addref(Z_STR_P(object_ptr)); + ZVAL_STR_OFFSET(variable_ptr, object_ptr, offset); + } else { +string_failed: + zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_UNUSED TSRMLS_CC); + } value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + zend_assign_to_string_offset(variable_ptr, offset, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) { if (IS_TMP_FREE(free_op_data1)) { zval_dtor(value); @@ -42821,14 +42978,33 @@ static int ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER zend_free_op free_op_data1, free_op_data2; zval *value; zval *dim = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); - zval *variable_ptr; + zval *variable_ptr = EX_VAR((opline+1)->op2.var); + zend_long offset = 0; + + if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { + + if (UNEXPECTED(Z_STRLEN_P(object_ptr) == 0)) { + goto string_failed; + } + if (dim == NULL) { + zend_error_noreturn(E_ERROR, "[] operator not supported for strings"); + } + + SEPARATE_STRING(object_ptr); + + offset = zend_fetch_dimension_str_offset(dim, BP_VAR_W TSRMLS_CC); - zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_CV TSRMLS_CC); + if (!IS_INTERNED(Z_STR_P(object_ptr))) zend_string_addref(Z_STR_P(object_ptr)); + ZVAL_STR_OFFSET(variable_ptr, object_ptr, offset); + } else { +string_failed: + zend_fetch_dimension_address_W(EX_VAR((opline+1)->op2.var), object_ptr, dim, IS_CV TSRMLS_CC); + } value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC); if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); + zend_assign_to_string_offset(variable_ptr, offset, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) { if (IS_TMP_FREE(free_op_data1)) { zval_dtor(value); @@ -42870,9 +43046,7 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC); - if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) { - zend_assign_to_string_offset(variable_ptr, value, IS_CV, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC); - } else if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { + if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { if (0) { zval_dtor(value); }