diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index cddc8122526..e8a5a4ca783 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -29,6 +29,10 @@ PHP 8.5 INTERNALS UPGRADE NOTES be heap-allocated and stored in the pointer as a minimal change to keep compatibility. +- Hash + . Hash functions now use proper hash_spec_result enum for return values + instead of using SUCCESS and FAILURE. + - Zend . Added zend_safe_assign_to_variable_noref() function to safely assign a value to a non-reference zval. diff --git a/ext/hash/hash.c b/ext/hash/hash.c index 26435fd5c1a..75e2e241bec 100644 --- a/ext/hash/hash.c +++ b/ext/hash/hash.c @@ -229,20 +229,20 @@ static void one_to_buffer(size_t sz, unsigned char *buf, uint64_t val) { significant bits first. This allows 32-bit and 64-bit architectures to interchange serialized HashContexts. */ -PHP_HASH_API zend_result php_hash_serialize_spec(const php_hashcontext_object *hash, zval *zv, const char *spec) /* {{{ */ +PHP_HASH_API hash_spec_result php_hash_serialize_spec(const php_hashcontext_object *hash, zval *zv, const char *spec) /* {{{ */ { size_t pos = 0, max_alignment = 1; unsigned char *buf = (unsigned char *) hash->context; zval tmp; if (buf == NULL) { - return FAILURE; + return HASH_SPEC_FAILURE; } array_init(zv); while (*spec != '\0' && *spec != '.') { char spec_ch = *spec; size_t sz, count = parse_serialize_spec(&spec, &pos, &sz, &max_alignment); if (pos + count * sz > hash->ops->context_size) { - return FAILURE; + return HASH_SPEC_FAILURE; } if (isupper((unsigned char) spec_ch)) { pos += count * sz; @@ -265,38 +265,33 @@ PHP_HASH_API zend_result php_hash_serialize_spec(const php_hashcontext_object *h } } if (*spec == '.' && align_to(pos, max_alignment) != hash->ops->context_size) { - return FAILURE; + return HASH_SPEC_FAILURE; } - return SUCCESS; + return HASH_SPEC_SUCCESS; } /* }}} */ -/* Unserialize a hash context serialized by `php_hash_serialize_spec` with `spec`. - Returns SUCCESS on success and a negative error code on failure. - Codes: FAILURE (-1) == generic failure - -999 == spec wrong size for context - -1000 - POS == problem at byte offset POS */ - -PHP_HASH_API int php_hash_unserialize_spec(php_hashcontext_object *hash, const zval *zv, const char *spec) /* {{{ */ +/* Unserialize a hash context serialized by `php_hash_serialize_spec` with `spec`. */ +PHP_HASH_API hash_spec_result php_hash_unserialize_spec(php_hashcontext_object *hash, const zval *zv, const char *spec) /* {{{ */ { size_t pos = 0, max_alignment = 1, j = 0; unsigned char *buf = (unsigned char *) hash->context; zval *elt; if (Z_TYPE_P(zv) != IS_ARRAY) { - return FAILURE; + return HASH_SPEC_FAILURE; } while (*spec != '\0' && *spec != '.') { char spec_ch = *spec; size_t sz, count = parse_serialize_spec(&spec, &pos, &sz, &max_alignment); if (pos + count * sz > hash->ops->context_size) { - return -999; + return WRONG_CONTEXT_SIZE; } if (isupper((unsigned char) spec_ch)) { pos += count * sz; } else if (sz == 1 && count > 1) { elt = zend_hash_index_find(Z_ARRVAL_P(zv), j); if (!elt || Z_TYPE_P(elt) != IS_STRING || Z_STRLEN_P(elt) != count) { - return -1000 - pos; + return BYTE_OFFSET_POS_ERROR - pos; } ++j; memcpy(buf + pos, Z_STRVAL_P(elt), count); @@ -306,14 +301,14 @@ PHP_HASH_API int php_hash_unserialize_spec(php_hashcontext_object *hash, const z uint64_t val; elt = zend_hash_index_find(Z_ARRVAL_P(zv), j); if (!elt || Z_TYPE_P(elt) != IS_LONG) { - return -1000 - pos; + return BYTE_OFFSET_POS_ERROR - pos; } ++j; val = (uint32_t) Z_LVAL_P(elt); if (sz == 8) { elt = zend_hash_index_find(Z_ARRVAL_P(zv), j); if (!elt || Z_TYPE_P(elt) != IS_LONG) { - return -1000 - pos; + return BYTE_OFFSET_POS_ERROR - pos; } ++j; val += ((uint64_t) Z_LVAL_P(elt)) << 32; @@ -325,31 +320,32 @@ PHP_HASH_API int php_hash_unserialize_spec(php_hashcontext_object *hash, const z } } if (*spec == '.' && align_to(pos, max_alignment) != hash->ops->context_size) { - return -999; + return WRONG_CONTEXT_SIZE; } - return SUCCESS; + + return HASH_SPEC_SUCCESS; } /* }}} */ -PHP_HASH_API zend_result php_hash_serialize(const php_hashcontext_object *hash, zend_long *magic, zval *zv) /* {{{ */ +PHP_HASH_API hash_spec_result php_hash_serialize(const php_hashcontext_object *hash, zend_long *magic, zval *zv) /* {{{ */ { - if (hash->ops->serialize_spec) { - *magic = PHP_HASH_SERIALIZE_MAGIC_SPEC; - return php_hash_serialize_spec(hash, zv, hash->ops->serialize_spec); - } else { - return FAILURE; - } + if (!hash->ops->serialize_spec) { + return HASH_SPEC_FAILURE; + } + + *magic = PHP_HASH_SERIALIZE_MAGIC_SPEC; + return php_hash_serialize_spec(hash, zv, hash->ops->serialize_spec); } /* }}} */ -PHP_HASH_API int php_hash_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv) /* {{{ */ +PHP_HASH_API hash_spec_result php_hash_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv) /* {{{ */ { if (hash->ops->serialize_spec && magic == PHP_HASH_SERIALIZE_MAGIC_SPEC) { return php_hash_unserialize_spec(hash, zv, hash->ops->serialize_spec); - } else { - return FAILURE; } + + return HASH_SPEC_FAILURE; } /* }}} */ @@ -1475,7 +1471,7 @@ PHP_METHOD(HashContext, __serialize) ZVAL_LONG(&tmp, hash->options); zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp); - if (hash->ops->hash_serialize(hash, &magic, &tmp) != SUCCESS) { + if (hash->ops->hash_serialize(hash, &magic, &tmp) != HASH_SPEC_SUCCESS) { goto serialize_failure; } zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp); @@ -1504,7 +1500,7 @@ PHP_METHOD(HashContext, __unserialize) HashTable *data; zval *algo_zv, *magic_zv, *options_zv, *hash_zv, *members_zv; zend_long magic, options; - int unserialize_result; + hash_spec_result unserialize_result; const php_hash_ops *ops; if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &data) == FAILURE) { @@ -1553,7 +1549,7 @@ PHP_METHOD(HashContext, __unserialize) ops->hash_init(hash->context, NULL); unserialize_result = ops->hash_unserialize(hash, magic, hash_zv); - if (unserialize_result != SUCCESS) { + if (unserialize_result != HASH_SPEC_SUCCESS) { zend_throw_exception_ex(NULL, 0, "Incomplete or ill-formed serialization data (\"%s\" code %d)", ops->algo, unserialize_result); /* free context */ php_hashcontext_dtor(Z_OBJ_P(object)); diff --git a/ext/hash/hash_gost.c b/ext/hash/hash_gost.c index 2ad6948a9a6..bba585a11f9 100644 --- a/ext/hash/hash_gost.c +++ b/ext/hash/hash_gost.c @@ -304,17 +304,17 @@ PHP_HASH_API void PHP_GOSTFinal(unsigned char digest[32], PHP_GOST_CTX *context) ZEND_SECURE_ZERO(context, sizeof(*context)); } -static int php_gost_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv) +static hash_spec_result php_gost_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv) { PHP_GOST_CTX *ctx = (PHP_GOST_CTX *) hash->context; - int r = FAILURE; + hash_spec_result r = HASH_SPEC_FAILURE; if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC - && (r = php_hash_unserialize_spec(hash, zv, PHP_GOST_SPEC)) == SUCCESS + && (r = php_hash_unserialize_spec(hash, zv, PHP_GOST_SPEC)) == HASH_SPEC_SUCCESS && ctx->length < sizeof(ctx->buffer)) { - return SUCCESS; - } else { - return r != SUCCESS ? r : -2000; + return HASH_SPEC_SUCCESS; } + + return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE; } const php_hash_ops php_hash_gost_ops = { diff --git a/ext/hash/hash_md.c b/ext/hash/hash_md.c index 96da7fce82a..dd299e69589 100644 --- a/ext/hash/hash_md.c +++ b/ext/hash/hash_md.c @@ -47,7 +47,7 @@ const php_hash_ops php_hash_md4_ops = { 1 }; -static int php_md2_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv); +static hash_spec_result php_md2_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv); const php_hash_ops php_hash_md2_ops = { "md2", @@ -356,15 +356,15 @@ PHP_HASH_API void PHP_MD2Final(unsigned char output[16], PHP_MD2_CTX *context) memcpy(output, context->state, 16); } -static int php_md2_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv) +static hash_spec_result php_md2_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv) { PHP_MD2_CTX *ctx = (PHP_MD2_CTX *) hash->context; - int r = FAILURE; + hash_spec_result r = HASH_SPEC_FAILURE; if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC - && (r = php_hash_unserialize_spec(hash, zv, PHP_MD2_SPEC)) == SUCCESS + && (r = php_hash_unserialize_spec(hash, zv, PHP_MD2_SPEC)) == HASH_SPEC_SUCCESS && (unsigned char) ctx->in_buffer < sizeof(ctx->buffer)) { - return SUCCESS; - } else { - return r != SUCCESS ? r : -2000; + return HASH_SPEC_SUCCESS; } + + return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE; } diff --git a/ext/hash/hash_sha3.c b/ext/hash/hash_sha3.c index 07da2cfd2d0..8fa0a4b4e52 100644 --- a/ext/hash/hash_sha3.c +++ b/ext/hash/hash_sha3.c @@ -200,20 +200,20 @@ static void PHP_SHA3_Final(unsigned char* digest, ZEND_SECURE_ZERO(ctx, sizeof(PHP_SHA3_CTX)); } -static int php_sha3_unserialize(php_hashcontext_object *hash, +static hash_spec_result php_sha3_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv, size_t block_size) { PHP_SHA3_CTX *ctx = (PHP_SHA3_CTX *) hash->context; - int r = FAILURE; + hash_spec_result r = HASH_SPEC_FAILURE; if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC - && (r = php_hash_unserialize_spec(hash, zv, PHP_SHA3_SPEC)) == SUCCESS + && (r = php_hash_unserialize_spec(hash, zv, PHP_SHA3_SPEC)) == HASH_SPEC_SUCCESS && ctx->pos < block_size) { - return SUCCESS; - } else { - return r != SUCCESS ? r : -2000; + return HASH_SPEC_SUCCESS; } + + return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE; } // ========================================================================== @@ -292,23 +292,23 @@ const php_hash_ops php_hash_sha3_##bits##_ops = { \ #endif #define PHP_KECCAK_SPEC "b200IiIIB" -static zend_result php_keccak_serialize(const php_hashcontext_object *hash, zend_long *magic, zval *zv) +static hash_spec_result php_keccak_serialize(const php_hashcontext_object *hash, zend_long *magic, zval *zv) { *magic = PHP_HASH_SERIALIZE_MAGIC_KECCAK; return php_hash_serialize_spec(hash, zv, PHP_KECCAK_SPEC); } -static int php_keccak_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv) +static hash_spec_result php_keccak_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv) { Keccak_HashInstance *ctx = (Keccak_HashInstance *) hash->context; - int r = FAILURE; + hash_spec_result r = HASH_SPEC_FAILURE; if (magic == PHP_HASH_SERIALIZE_MAGIC_KECCAK - && (r = php_hash_unserialize_spec(hash, zv, PHP_KECCAK_SPEC)) == SUCCESS + && (r = php_hash_unserialize_spec(hash, zv, PHP_KECCAK_SPEC)) == HASH_SPEC_SUCCESS && ctx->sponge.byteIOIndex < ctx->sponge.rate / 8) { - return SUCCESS; - } else { - return r != SUCCESS ? r : -2000; + return HASH_SPEC_SUCCESS; } + + return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE; } // ========================================================================== diff --git a/ext/hash/hash_snefru.c b/ext/hash/hash_snefru.c index c1dbc3ae57a..b9b70f36420 100644 --- a/ext/hash/hash_snefru.c +++ b/ext/hash/hash_snefru.c @@ -189,17 +189,17 @@ PHP_HASH_API void PHP_SNEFRUFinal(unsigned char digest[32], PHP_SNEFRU_CTX *cont ZEND_SECURE_ZERO(context, sizeof(*context)); } -static int php_snefru_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv) +static hash_spec_result php_snefru_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv) { PHP_SNEFRU_CTX *ctx = (PHP_SNEFRU_CTX *) hash->context; - int r = FAILURE; + hash_spec_result r = HASH_SPEC_FAILURE; if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC - && (r = php_hash_unserialize_spec(hash, zv, PHP_SNEFRU_SPEC)) == SUCCESS + && (r = php_hash_unserialize_spec(hash, zv, PHP_SNEFRU_SPEC)) == HASH_SPEC_SUCCESS && ctx->length < sizeof(ctx->buffer)) { - return SUCCESS; - } else { - return r != SUCCESS ? r : -2000; + return HASH_SPEC_SUCCESS; } + + return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE; } const php_hash_ops php_hash_snefru_ops = { diff --git a/ext/hash/hash_tiger.c b/ext/hash/hash_tiger.c index 841693a67dd..62d1b734714 100644 --- a/ext/hash/hash_tiger.c +++ b/ext/hash/hash_tiger.c @@ -239,17 +239,17 @@ PHP_HASH_API void PHP_TIGER192Final(unsigned char digest[24], PHP_TIGER_CTX *con ZEND_SECURE_ZERO(context, sizeof(*context)); } -static int php_tiger_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv) +static hash_spec_result php_tiger_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv) { PHP_TIGER_CTX *ctx = (PHP_TIGER_CTX *) hash->context; - int r = FAILURE; + hash_spec_result r = HASH_SPEC_FAILURE; if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC - && (r = php_hash_unserialize_spec(hash, zv, PHP_TIGER_SPEC)) == SUCCESS + && (r = php_hash_unserialize_spec(hash, zv, PHP_TIGER_SPEC)) == HASH_SPEC_SUCCESS && ctx->length < sizeof(ctx->buffer)) { - return SUCCESS; - } else { - return r != SUCCESS ? r : -2000; + return HASH_SPEC_SUCCESS; } + + return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE; } #define PHP_HASH_TIGER_OPS(p, b) \ diff --git a/ext/hash/hash_whirlpool.c b/ext/hash/hash_whirlpool.c index db5a0da1236..fa3c216a64c 100644 --- a/ext/hash/hash_whirlpool.c +++ b/ext/hash/hash_whirlpool.c @@ -429,20 +429,20 @@ PHP_HASH_API void PHP_WHIRLPOOLFinal(unsigned char digest[64], PHP_WHIRLPOOL_CTX ZEND_SECURE_ZERO(context, sizeof(*context)); } -static int php_whirlpool_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv) +static hash_spec_result php_whirlpool_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv) { PHP_WHIRLPOOL_CTX *ctx = (PHP_WHIRLPOOL_CTX *) hash->context; - int r = FAILURE; + hash_spec_result r = HASH_SPEC_FAILURE; if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC - && (r = php_hash_unserialize_spec(hash, zv, PHP_WHIRLPOOL_SPEC)) == SUCCESS + && (r = php_hash_unserialize_spec(hash, zv, PHP_WHIRLPOOL_SPEC)) == HASH_SPEC_SUCCESS && ctx->buffer.pos >= 0 && ctx->buffer.pos < (int) sizeof(ctx->buffer.data) && ctx->buffer.bits >= ctx->buffer.pos * 8 && ctx->buffer.bits < ctx->buffer.pos * 8 + 8) { - return SUCCESS; - } else { - return r != SUCCESS ? r : -2000; + return HASH_SPEC_SUCCESS; } + + return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE; } const php_hash_ops php_hash_whirlpool_ops = { diff --git a/ext/hash/hash_xxhash.c b/ext/hash/hash_xxhash.c index 1c1315afd4b..add922e8e84 100644 --- a/ext/hash/hash_xxhash.c +++ b/ext/hash/hash_xxhash.c @@ -17,9 +17,9 @@ #include "php_hash.h" #include "php_hash_xxhash.h" -static int php_hash_xxh32_unserialize( +static hash_spec_result php_hash_xxh32_unserialize( php_hashcontext_object *hash, zend_long magic, const zval *zv); -static int php_hash_xxh64_unserialize( +static hash_spec_result php_hash_xxh64_unserialize( php_hashcontext_object *hash, zend_long magic, const zval *zv); const php_hash_ops php_hash_xxh32_ops = { @@ -75,18 +75,18 @@ PHP_HASH_API zend_result PHP_XXH32Copy(const php_hash_ops *ops, const PHP_XXH32_ return SUCCESS; } -static int php_hash_xxh32_unserialize( +static hash_spec_result php_hash_xxh32_unserialize( php_hashcontext_object *hash, zend_long magic, const zval *zv) { PHP_XXH32_CTX *ctx = (PHP_XXH32_CTX *) hash->context; - int r = FAILURE; + hash_spec_result r = HASH_SPEC_FAILURE; if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC - && (r = php_hash_unserialize_spec(hash, zv, PHP_XXH32_SPEC)) == SUCCESS + && (r = php_hash_unserialize_spec(hash, zv, PHP_XXH32_SPEC)) == HASH_SPEC_SUCCESS && ctx->s.memsize < 16) { - return SUCCESS; - } else { - return r != SUCCESS ? r : -2000; + return HASH_SPEC_SUCCESS; } + + return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE; } const php_hash_ops php_hash_xxh64_ops = { @@ -231,18 +231,18 @@ PHP_HASH_API zend_result PHP_XXH3_64_Copy(const php_hash_ops *ops, const PHP_XXH return SUCCESS; } -static int php_hash_xxh64_unserialize( +static hash_spec_result php_hash_xxh64_unserialize( php_hashcontext_object *hash, zend_long magic, const zval *zv) { PHP_XXH64_CTX *ctx = (PHP_XXH64_CTX *) hash->context; - int r = FAILURE; + hash_spec_result r = HASH_SPEC_FAILURE; if (magic == PHP_HASH_SERIALIZE_MAGIC_SPEC - && (r = php_hash_unserialize_spec(hash, zv, PHP_XXH64_SPEC)) == SUCCESS + && (r = php_hash_unserialize_spec(hash, zv, PHP_XXH64_SPEC)) == HASH_SPEC_SUCCESS && ctx->s.memsize < 32) { - return SUCCESS; - } else { - return r != SUCCESS ? r : -2000; + return HASH_SPEC_SUCCESS; } + + return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE; } const php_hash_ops php_hash_xxh3_128_ops = { diff --git a/ext/hash/php_hash.h b/ext/hash/php_hash.h index 3b058ef48bd..f56605a33be 100644 --- a/ext/hash/php_hash.h +++ b/ext/hash/php_hash.h @@ -29,14 +29,22 @@ #define L64 INT64_C +typedef enum { + HASH_SPEC_SUCCESS = 0, + HASH_SPEC_FAILURE = -1, + WRONG_CONTEXT_SIZE = -999, + BYTE_OFFSET_POS_ERROR = -1000, + CONTEXT_VALIDATION_FAILURE = -2000, +} hash_spec_result; + typedef struct _php_hashcontext_object php_hashcontext_object; typedef void (*php_hash_init_func_t)(void *context, HashTable *args); typedef void (*php_hash_update_func_t)(void *context, const unsigned char *buf, size_t count); typedef void (*php_hash_final_func_t)(unsigned char *digest, void *context); typedef zend_result (*php_hash_copy_func_t)(const void *ops, const void *orig_context, void *dest_context); -typedef zend_result (*php_hash_serialize_func_t)(const php_hashcontext_object *hash, zend_long *magic, zval *zv); -typedef int (*php_hash_unserialize_func_t)(php_hashcontext_object *hash, zend_long magic, const zval *zv); +typedef hash_spec_result (*php_hash_serialize_func_t)(const php_hashcontext_object *hash, zend_long *magic, zval *zv); +typedef hash_spec_result (*php_hash_unserialize_func_t)(php_hashcontext_object *hash, zend_long magic, const zval *zv); typedef struct _php_hash_ops { const char *algo; @@ -148,10 +156,10 @@ extern PHP_HASH_API zend_class_entry *php_hashcontext_ce; PHP_HASH_API const php_hash_ops *php_hash_fetch_ops(zend_string *algo); PHP_HASH_API void php_hash_register_algo(const char *algo, const php_hash_ops *ops); PHP_HASH_API zend_result php_hash_copy(const void *ops, const void *orig_context, void *dest_context); -PHP_HASH_API zend_result php_hash_serialize(const php_hashcontext_object *context, zend_long *magic, zval *zv); -PHP_HASH_API int php_hash_unserialize(php_hashcontext_object *context, zend_long magic, const zval *zv); -PHP_HASH_API zend_result php_hash_serialize_spec(const php_hashcontext_object *context, zval *zv, const char *spec); -PHP_HASH_API int php_hash_unserialize_spec(php_hashcontext_object *hash, const zval *zv, const char *spec); +PHP_HASH_API hash_spec_result php_hash_serialize(const php_hashcontext_object *context, zend_long *magic, zval *zv); +PHP_HASH_API hash_spec_result php_hash_unserialize(php_hashcontext_object *context, zend_long magic, const zval *zv); +PHP_HASH_API hash_spec_result php_hash_serialize_spec(const php_hashcontext_object *context, zval *zv, const char *spec); +PHP_HASH_API hash_spec_result php_hash_unserialize_spec(php_hashcontext_object *hash, const zval *zv, const char *spec); static inline void *php_hash_alloc_context(const php_hash_ops *ops) { /* Zero out context memory so serialization doesn't expose internals */