From 22bde0951932e66f3fda41c01864a8e436952eff Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+ndossche@users.noreply.github.com> Date: Fri, 7 Nov 2025 23:57:47 +0100 Subject: [PATCH 1/2] standard: Avoid double hash table lookup in iptcparse() --- Zend/zend_hash.c | 7 +++++++ Zend/zend_hash.h | 1 + ext/standard/iptc.c | 8 +++----- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 6064b42218327..d0ce34dfcb7d9 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -1062,6 +1062,13 @@ ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_new(HashTable *ht, const char *st return _zend_hash_str_add_or_update_i(ht, str, len, h, pData, HASH_ADD_NEW); } +ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_lookup(HashTable *ht, const char *str, size_t len) +{ + zend_ulong h = zend_hash_func(str, len); + + return _zend_hash_str_add_or_update_i(ht, str, len, h, NULL, HASH_LOOKUP); +} + ZEND_API zval* ZEND_FASTCALL zend_hash_index_add_empty_element(HashTable *ht, zend_ulong h) { zval dummy; diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index 3a501b7f37df1..335974e522d42 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -218,6 +218,7 @@ static zend_always_inline zval *zend_hash_find_ex(const HashTable *ht, zend_stri /* Find or add NULL, if doesn't exist */ ZEND_API zval* ZEND_FASTCALL zend_hash_lookup(HashTable *ht, zend_string *key); ZEND_API zval* ZEND_FASTCALL zend_hash_index_lookup(HashTable *ht, zend_ulong h); +ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_lookup(HashTable *ht, const char *str, size_t len); #define ZEND_HASH_INDEX_LOOKUP(_ht, _h, _ret) do { \ if (EXPECTED(HT_IS_PACKED(_ht))) { \ diff --git a/ext/standard/iptc.c b/ext/standard/iptc.c index 44dd33bab10ac..9c5beebfa41da 100644 --- a/ext/standard/iptc.c +++ b/ext/standard/iptc.c @@ -308,7 +308,6 @@ PHP_FUNCTION(iptcparse) unsigned char *buffer, recnum, dataset; char *str, key[16]; size_t str_len; - zval values, *element; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STRING(str, str_len) @@ -357,10 +356,9 @@ PHP_FUNCTION(iptcparse) array_init(return_value); } - if ((element = zend_hash_str_find(Z_ARRVAL_P(return_value), key, strlen(key))) == NULL) { - array_init(&values); - - element = zend_hash_str_update(Z_ARRVAL_P(return_value), key, strlen(key), &values); + zval *element = zend_hash_str_add_lookup(Z_ARRVAL_P(return_value), key, strlen(key)); + if (Z_ISNULL_P(element)) { + array_init(element); } add_next_index_stringl(element, (char *) buffer+inx, len); From e3a07e6a967a31ee2081e18ce2f6524a8c98fdee Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+ndossche@users.noreply.github.com> Date: Sat, 8 Nov 2025 12:45:11 +0100 Subject: [PATCH 2/2] review --- UPGRADING.INTERNALS | 1 + Zend/zend_hash.c | 2 +- Zend/zend_hash.h | 2 +- ext/standard/iptc.c | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 385ad0445cc99..f5d1456ecacc7 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -43,6 +43,7 @@ PHP 8.6 INTERNALS UPGRADE NOTES pointer. . The zend_get_call_trampoline_func() API now takes the __call or __callStatic zend_function* instead of a CE and a boolean argument. + . Added zend_hash_str_lookup(). ======================== 2. Build system changes diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index d0ce34dfcb7d9..c00397e9fe9e3 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -1062,7 +1062,7 @@ ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_new(HashTable *ht, const char *st return _zend_hash_str_add_or_update_i(ht, str, len, h, pData, HASH_ADD_NEW); } -ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_lookup(HashTable *ht, const char *str, size_t len) +ZEND_API zval* ZEND_FASTCALL zend_hash_str_lookup(HashTable *ht, const char *str, size_t len) { zend_ulong h = zend_hash_func(str, len); diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index 335974e522d42..70d9721cb7a17 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -218,7 +218,7 @@ static zend_always_inline zval *zend_hash_find_ex(const HashTable *ht, zend_stri /* Find or add NULL, if doesn't exist */ ZEND_API zval* ZEND_FASTCALL zend_hash_lookup(HashTable *ht, zend_string *key); ZEND_API zval* ZEND_FASTCALL zend_hash_index_lookup(HashTable *ht, zend_ulong h); -ZEND_API zval* ZEND_FASTCALL zend_hash_str_add_lookup(HashTable *ht, const char *str, size_t len); +ZEND_API zval* ZEND_FASTCALL zend_hash_str_lookup(HashTable *ht, const char *str, size_t len); #define ZEND_HASH_INDEX_LOOKUP(_ht, _h, _ret) do { \ if (EXPECTED(HT_IS_PACKED(_ht))) { \ diff --git a/ext/standard/iptc.c b/ext/standard/iptc.c index 9c5beebfa41da..5078c0813ccb8 100644 --- a/ext/standard/iptc.c +++ b/ext/standard/iptc.c @@ -356,7 +356,7 @@ PHP_FUNCTION(iptcparse) array_init(return_value); } - zval *element = zend_hash_str_add_lookup(Z_ARRVAL_P(return_value), key, strlen(key)); + zval *element = zend_hash_str_lookup(Z_ARRVAL_P(return_value), key, strlen(key)); if (Z_ISNULL_P(element)) { array_init(element); }