]> granicus.if.org Git - php/commitdiff
fix 64 bit string index usage
authorAnatol Belski <ab@php.net>
Sat, 6 Sep 2014 22:54:47 +0000 (00:54 +0200)
committerAnatol Belski <ab@php.net>
Sat, 6 Sep 2014 22:55:36 +0000 (00:55 +0200)
Zend/zend_execute.c
Zend/zend_types.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index 5cddebd2a467f39247e4c079f9894ac393290f66..586eddec59cf0182cf37a720778bc031dcc5c47d 100644 (file)
@@ -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");
index 548bd5a2e0727cdddf9a613f117b076320443947..389d3e5cd2916ce876cfad69ced38f3fde89423a 100644 (file)
@@ -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)
 
index fc8f28b47ef965ff936989fed70a0760f61efa7f..2d0ea7e002ff6737a4f6d8f7820192cefd6b5275 100644 (file)
@@ -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);
                }
index fbbc46125a048142b36ee5fcb3ba2a3ad24e3212..690b07ef94f633d3c930ca625efaaf4232d91ba2 100644 (file)
@@ -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);
                }