From: Nikita Popov Date: Tue, 15 Sep 2020 09:38:40 +0000 (+0200) Subject: Add GC_TRY_ADDREF macro X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=da0663a337b608a4b0008672b494e3a71e6e4cfc;p=php Add GC_TRY_ADDREF macro That adds a ref if not immutable. Also audit uses of GC_IMMUTABLE to either use GC_TRY_ADDREF or GC_TRY_PROTECT_RECURSION. --- diff --git a/Zend/zend.c b/Zend/zend.c index 4d781e6a10..cbd5aef42b 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -404,9 +404,7 @@ ZEND_API void zend_print_flat_zval_r(zval *expr) /* {{{ */ } print_flat_hash(Z_ARRVAL_P(expr)); ZEND_PUTS(")"); - if (!(GC_FLAGS(Z_ARRVAL_P(expr)) & GC_IMMUTABLE)) { - GC_UNPROTECT_RECURSION(Z_ARRVAL_P(expr)); - } + GC_TRY_UNPROTECT_RECURSION(Z_ARRVAL_P(expr)); break; case IS_OBJECT: { @@ -452,9 +450,7 @@ static void zend_print_zval_r_to_buf(smart_str *buf, zval *expr, int indent) /* GC_PROTECT_RECURSION(Z_ARRVAL_P(expr)); } print_hash(buf, Z_ARRVAL_P(expr), indent, 0); - if (!(GC_FLAGS(Z_ARRVAL_P(expr)) & GC_IMMUTABLE)) { - GC_UNPROTECT_RECURSION(Z_ARRVAL_P(expr)); - } + GC_TRY_UNPROTECT_RECURSION(Z_ARRVAL_P(expr)); break; case IS_OBJECT: { diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index abda03edf6..c92b869569 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -2658,13 +2658,9 @@ ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t co zend_error_noreturn(E_ERROR, "Nesting level too deep - recursive dependency?"); } - if (!(GC_FLAGS(ht1) & GC_IMMUTABLE)) { - GC_PROTECT_RECURSION(ht1); - } + GC_TRY_PROTECT_RECURSION(ht1); result = zend_hash_compare_impl(ht1, ht2, compar, ordered); - if (!(GC_FLAGS(ht1) & GC_IMMUTABLE)) { - GC_UNPROTECT_RECURSION(ht1); - } + GC_TRY_UNPROTECT_RECURSION(ht1); return result; } diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index a4ee0feda8..be8ab3aca7 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1776,8 +1776,8 @@ ZEND_API HashTable *zend_std_get_properties_for(zend_object *obj, zend_prop_purp if (obj->handlers->get_debug_info) { int is_temp; ht = obj->handlers->get_debug_info(obj, &is_temp); - if (ht && !is_temp && !(GC_FLAGS(ht) & GC_IMMUTABLE)) { - GC_ADDREF(ht); + if (ht && !is_temp) { + GC_TRY_ADDREF(ht); } return ht; } @@ -1787,8 +1787,8 @@ ZEND_API HashTable *zend_std_get_properties_for(zend_object *obj, zend_prop_purp case ZEND_PROP_PURPOSE_VAR_EXPORT: case ZEND_PROP_PURPOSE_JSON: ht = obj->handlers->get_properties(obj); - if (ht && !(GC_FLAGS(ht) & GC_IMMUTABLE)) { - GC_ADDREF(ht); + if (ht) { + GC_TRY_ADDREF(ht); } return ht; default: diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 745be6e938..3b1ec85452 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -612,6 +612,7 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) { #define GC_DELREF(p) zend_gc_delref(&(p)->gc) #define GC_ADDREF_EX(p, rc) zend_gc_addref_ex(&(p)->gc, rc) #define GC_DELREF_EX(p, rc) zend_gc_delref_ex(&(p)->gc, rc) +#define GC_TRY_ADDREF(p) zend_gc_try_addref(&(p)->gc) #define GC_TYPE_MASK 0x0000000f #define GC_FLAGS_MASK 0x000003f0 @@ -1160,6 +1161,13 @@ static zend_always_inline uint32_t zend_gc_addref(zend_refcounted_h *p) { return ++(p->refcount); } +static zend_always_inline void zend_gc_try_addref(zend_refcounted_h *p) { + if (!(p->u.type_info & GC_IMMUTABLE)) { + ZEND_RC_MOD_CHECK(p); + ++p->refcount; + } +} + static zend_always_inline uint32_t zend_gc_delref(zend_refcounted_h *p) { ZEND_ASSERT(p->refcount > 0); ZEND_RC_MOD_CHECK(p); diff --git a/ext/json/json_encoder.c b/ext/json/json_encoder.c index d08a466643..92e4a10933 100644 --- a/ext/json/json_encoder.c +++ b/ext/json/json_encoder.c @@ -113,15 +113,15 @@ static inline void php_json_encode_double(smart_str *buf, double d, int options) #define PHP_JSON_HASH_PROTECT_RECURSION(_tmp_ht) \ do { \ - if (_tmp_ht && !(GC_FLAGS(_tmp_ht) & GC_IMMUTABLE)) { \ - GC_PROTECT_RECURSION(_tmp_ht); \ + if (_tmp_ht) { \ + GC_TRY_PROTECT_RECURSION(_tmp_ht); \ } \ } while (0) #define PHP_JSON_HASH_UNPROTECT_RECURSION(_tmp_ht) \ do { \ - if (_tmp_ht && !(GC_FLAGS(_tmp_ht) & GC_IMMUTABLE)) { \ - GC_UNPROTECT_RECURSION(_tmp_ht); \ + if (_tmp_ht) { \ + GC_TRY_UNPROTECT_RECURSION(_tmp_ht); \ } \ } while (0) diff --git a/ext/standard/array.c b/ext/standard/array.c index cb5e6e7dee..58c4d815b7 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -716,10 +716,7 @@ PHPAPI zend_long php_count_recursive(HashTable *ht) /* {{{ */ } } ZEND_HASH_FOREACH_END(); - if (!(GC_FLAGS(ht) & GC_IMMUTABLE)) { - GC_UNPROTECT_RECURSION(ht); - } - + GC_TRY_UNPROTECT_RECURSION(ht); return cnt; } /* }}} */ @@ -3644,12 +3641,12 @@ PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src) /* {{{ */ src_zval = &tmp; } if (Z_TYPE_P(src_zval) == IS_ARRAY) { - if (thash && !(GC_FLAGS(thash) & GC_IMMUTABLE)) { - GC_PROTECT_RECURSION(thash); + if (thash) { + GC_TRY_PROTECT_RECURSION(thash); } ret = php_array_merge_recursive(Z_ARRVAL_P(dest_zval), Z_ARRVAL_P(src_zval)); - if (thash && !(GC_FLAGS(thash) & GC_IMMUTABLE)) { - GC_UNPROTECT_RECURSION(thash); + if (thash) { + GC_TRY_UNPROTECT_RECURSION(thash); } if (!ret) { return 0; diff --git a/ext/standard/http.c b/ext/standard/http.c index 3819065894..804940fd1a 100644 --- a/ext/standard/http.c +++ b/ext/standard/http.c @@ -146,13 +146,9 @@ PHPAPI int php_url_encode_hash_ex(HashTable *ht, smart_str *formstr, *(p++) = 'B'; *p = '\0'; } - if (!(GC_FLAGS(ht) & GC_IMMUTABLE)) { - GC_PROTECT_RECURSION(ht); - } + GC_TRY_PROTECT_RECURSION(ht); php_url_encode_hash_ex(HASH_OF(zdata), formstr, NULL, 0, newprefix, newprefix_len, "%5D", 3, (Z_TYPE_P(zdata) == IS_OBJECT ? zdata : NULL), arg_sep, enc_type); - if (!(GC_FLAGS(ht) & GC_IMMUTABLE)) { - GC_UNPROTECT_RECURSION(ht); - } + GC_TRY_UNPROTECT_RECURSION(ht); efree(newprefix); } else if (Z_TYPE_P(zdata) == IS_NULL || Z_TYPE_P(zdata) == IS_RESOURCE) { /* Skip these types */