From 37ac707cac2bb6efc68f91f35b50e870d2f3294a Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 2 Dec 2021 11:18:08 +0300 Subject: [PATCH] Add missing zend_string_release_ex(tmp, 0) and cleanup - use GC_DELREF() instead of zend_string_release_ex() - add expectations for exceptional cases - replace IS_ARRAY_IMMUTABLE by IS_STR_INTERNED --- Zend/zend_execute.c | 19 +++++++++++-------- ext/opcache/jit/zend_jit_helpers.c | 11 +++++++---- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 859adcf3244..db04a2d22d4 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1540,7 +1540,7 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, s = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0); ZSTR_H(s) = ZSTR_H(Z_STR_P(str)); if (Z_REFCOUNTED_P(str)) { - zend_string_release_ex(Z_STR_P(str), 0); + GC_DELREF(Z_STR_P(str)); } ZVAL_NEW_STR(str, s); } @@ -1552,7 +1552,7 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, * Temporarily increase the refcount to detect this situation. */ GC_ADDREF(s); offset = zend_check_string_offset(dim, BP_VAR_W EXECUTE_DATA_CC); - if (GC_DELREF(s) == 0) { + if (UNEXPECTED(GC_DELREF(s) == 0)) { zend_string_efree(s); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); @@ -1592,8 +1592,11 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, } /* Convert to string, just the time to pick the 1st byte */ tmp = zval_try_get_string_func(value); - if (GC_DELREF(s) == 0) { + if (UNEXPECTED(GC_DELREF(s) == 0)) { zend_string_efree(s); + if (tmp) { + zend_string_release_ex(tmp, 0); + } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } @@ -1628,7 +1631,7 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, * Temporarily increase the refcount to detect this situation. */ GC_ADDREF(s); zend_error(E_WARNING, "Only the first byte will be assigned to the string offset"); - if (GC_DELREF(s) == 0) { + if (UNEXPECTED(GC_DELREF(s) == 0)) { zend_string_efree(s); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); @@ -2439,11 +2442,11 @@ try_string_offset: 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)) { + if (!(GC_FLAGS(str) & IS_STR_INTERNED)) { GC_ADDREF(str); } ZVAL_UNDEFINED_OP2(); - if (!(GC_FLAGS(str) & IS_ARRAY_IMMUTABLE) && GC_DELREF(str) == 0) { + if (!(GC_FLAGS(str) & IS_STR_INTERNED) && UNEXPECTED(GC_DELREF(str) == 0)) { zend_string_efree(str); ZVAL_NULL(result); return; @@ -2455,11 +2458,11 @@ try_string_offset: 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)) { + if (!(GC_FLAGS(str) & IS_STR_INTERNED)) { GC_ADDREF(str); } zend_error(E_WARNING, "String offset cast occurred"); - if (!(GC_FLAGS(str) & IS_ARRAY_IMMUTABLE) && GC_DELREF(str) == 0) { + if (!(GC_FLAGS(str) & IS_STR_INTERNED) && UNEXPECTED(GC_DELREF(str) == 0)) { zend_string_efree(str); ZVAL_NULL(result); return; diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index be26a60aaa5..3d7163d3706 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -1137,7 +1137,7 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, s = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0); ZSTR_H(s) = ZSTR_H(Z_STR_P(str)); if (Z_REFCOUNTED_P(str)) { - zend_string_release_ex(Z_STR_P(str), 0); + GC_DELREF(Z_STR_P(str)); } ZVAL_NEW_STR(str, s); } @@ -1147,7 +1147,7 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, * Temporarily increase the refcount to detect this situation. */ GC_ADDREF(s); offset = zend_check_string_offset(dim/*, BP_VAR_W*/); - if (GC_DELREF(s) == 0) { + if (UNEXPECTED(GC_DELREF(s) == 0)) { zend_string_efree(s); if (result) { ZVAL_NULL(result); @@ -1189,8 +1189,11 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, /* Convert to string, just the time to pick the 1st byte */ tmp = zval_try_get_string_func(value); - if (GC_DELREF(s) == 0) { + if (UNEXPECTED(GC_DELREF(s) == 0)) { zend_string_efree(s); + if (tmp) { + zend_string_release_ex(tmp, 0); + } if (result) { ZVAL_NULL(result); } @@ -1233,7 +1236,7 @@ static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, * Temporarily increase the refcount to detect this situation. */ GC_ADDREF(s); zend_error(E_WARNING, "Only the first byte will be assigned to the string offset"); - if (GC_DELREF(s) == 0) { + if (UNEXPECTED(GC_DELREF(s) == 0)) { zend_string_efree(s); if (result) { ZVAL_NULL(result);