diff --git a/Zend/tests/str_offset_005.phpt b/Zend/tests/str_offset_005.phpt new file mode 100644 index 00000000000..6d70f82a782 --- /dev/null +++ b/Zend/tests/str_offset_005.phpt @@ -0,0 +1,12 @@ +--TEST-- +string offset 005 indirect string modification by error handler +--FILE-- + +--EXPECT-- +string(1) "a" +int(8) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 79c0e6133c6..7a3462a5aa1 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2361,6 +2361,7 @@ try_array: } } if (!is_list && EXPECTED(Z_TYPE_P(container) == IS_STRING)) { + zend_string *str = Z_STR_P(container); zend_long offset; try_string_offset: @@ -2386,13 +2387,33 @@ try_string_offset: return; } case IS_UNDEF: + /* The string may be destroyed while throwing the notice. + * Temporarily increase the refcount to detect this situation. */ + if (!(GC_FLAGS(str) & IS_ARRAY_IMMUTABLE)) { + GC_ADDREF(str); + } ZVAL_UNDEFINED_OP2(); + if (!(GC_FLAGS(str) & IS_ARRAY_IMMUTABLE) && GC_DELREF(str) == 0) { + zend_string_release_ex(str, 0); + ZVAL_NULL(result); + return; + } case IS_DOUBLE: case IS_NULL: case IS_FALSE: case IS_TRUE: if (type != BP_VAR_IS) { + /* The string may be destroyed while throwing the notice. + * Temporarily increase the refcount to detect this situation. */ + if (!(GC_FLAGS(str) & IS_ARRAY_IMMUTABLE)) { + GC_ADDREF(str); + } zend_error(E_WARNING, "String offset cast occurred"); + if (!(GC_FLAGS(str) & IS_ARRAY_IMMUTABLE) && GC_DELREF(str) == 0) { + zend_string_release_ex(str, 0); + ZVAL_NULL(result); + return; + } } break; case IS_REFERENCE: @@ -2410,7 +2431,7 @@ try_string_offset: } out: - if (UNEXPECTED(Z_STRLEN_P(container) < ((offset < 0) ? -(size_t)offset : ((size_t)offset + 1)))) { + if (UNEXPECTED(ZSTR_LEN(str) < ((offset < 0) ? -(size_t)offset : ((size_t)offset + 1)))) { if (type != BP_VAR_IS) { zend_error(E_WARNING, "Uninitialized string offset " ZEND_LONG_FMT, offset); ZVAL_EMPTY_STRING(result); @@ -2422,8 +2443,8 @@ try_string_offset: 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]; + ? (zend_long)ZSTR_LEN(str) + offset : offset; + c = (zend_uchar)ZSTR_VAL(str)[real_offset]; ZVAL_CHAR(result, c); }