Use proper hash_spec_result enum for return values in ext/hash (#19386)

This commit is contained in:
Alexandre Daubois 2025-08-09 12:56:40 +02:00 committed by GitHub
parent d65025b53d
commit 74c006fbab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 104 additions and 96 deletions

View file

@ -29,6 +29,10 @@ PHP 8.5 INTERNALS UPGRADE NOTES
be heap-allocated and stored in the pointer as a minimal change to keep be heap-allocated and stored in the pointer as a minimal change to keep
compatibility. compatibility.
- Hash
. Hash functions now use proper hash_spec_result enum for return values
instead of using SUCCESS and FAILURE.
- Zend - Zend
. Added zend_safe_assign_to_variable_noref() function to safely assign . Added zend_safe_assign_to_variable_noref() function to safely assign
a value to a non-reference zval. a value to a non-reference zval.

View file

@ -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 significant bits first. This allows 32-bit and 64-bit architectures to
interchange serialized HashContexts. */ 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; size_t pos = 0, max_alignment = 1;
unsigned char *buf = (unsigned char *) hash->context; unsigned char *buf = (unsigned char *) hash->context;
zval tmp; zval tmp;
if (buf == NULL) { if (buf == NULL) {
return FAILURE; return HASH_SPEC_FAILURE;
} }
array_init(zv); array_init(zv);
while (*spec != '\0' && *spec != '.') { while (*spec != '\0' && *spec != '.') {
char spec_ch = *spec; char spec_ch = *spec;
size_t sz, count = parse_serialize_spec(&spec, &pos, &sz, &max_alignment); size_t sz, count = parse_serialize_spec(&spec, &pos, &sz, &max_alignment);
if (pos + count * sz > hash->ops->context_size) { if (pos + count * sz > hash->ops->context_size) {
return FAILURE; return HASH_SPEC_FAILURE;
} }
if (isupper((unsigned char) spec_ch)) { if (isupper((unsigned char) spec_ch)) {
pos += count * sz; 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) { 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`. /* Unserialize a hash context serialized by `php_hash_serialize_spec` with `spec`. */
Returns SUCCESS on success and a negative error code on failure. PHP_HASH_API hash_spec_result php_hash_unserialize_spec(php_hashcontext_object *hash, const zval *zv, const char *spec) /* {{{ */
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) /* {{{ */
{ {
size_t pos = 0, max_alignment = 1, j = 0; size_t pos = 0, max_alignment = 1, j = 0;
unsigned char *buf = (unsigned char *) hash->context; unsigned char *buf = (unsigned char *) hash->context;
zval *elt; zval *elt;
if (Z_TYPE_P(zv) != IS_ARRAY) { if (Z_TYPE_P(zv) != IS_ARRAY) {
return FAILURE; return HASH_SPEC_FAILURE;
} }
while (*spec != '\0' && *spec != '.') { while (*spec != '\0' && *spec != '.') {
char spec_ch = *spec; char spec_ch = *spec;
size_t sz, count = parse_serialize_spec(&spec, &pos, &sz, &max_alignment); size_t sz, count = parse_serialize_spec(&spec, &pos, &sz, &max_alignment);
if (pos + count * sz > hash->ops->context_size) { if (pos + count * sz > hash->ops->context_size) {
return -999; return WRONG_CONTEXT_SIZE;
} }
if (isupper((unsigned char) spec_ch)) { if (isupper((unsigned char) spec_ch)) {
pos += count * sz; pos += count * sz;
} else if (sz == 1 && count > 1) { } else if (sz == 1 && count > 1) {
elt = zend_hash_index_find(Z_ARRVAL_P(zv), j); elt = zend_hash_index_find(Z_ARRVAL_P(zv), j);
if (!elt || Z_TYPE_P(elt) != IS_STRING || Z_STRLEN_P(elt) != count) { if (!elt || Z_TYPE_P(elt) != IS_STRING || Z_STRLEN_P(elt) != count) {
return -1000 - pos; return BYTE_OFFSET_POS_ERROR - pos;
} }
++j; ++j;
memcpy(buf + pos, Z_STRVAL_P(elt), count); 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; uint64_t val;
elt = zend_hash_index_find(Z_ARRVAL_P(zv), j); elt = zend_hash_index_find(Z_ARRVAL_P(zv), j);
if (!elt || Z_TYPE_P(elt) != IS_LONG) { if (!elt || Z_TYPE_P(elt) != IS_LONG) {
return -1000 - pos; return BYTE_OFFSET_POS_ERROR - pos;
} }
++j; ++j;
val = (uint32_t) Z_LVAL_P(elt); val = (uint32_t) Z_LVAL_P(elt);
if (sz == 8) { if (sz == 8) {
elt = zend_hash_index_find(Z_ARRVAL_P(zv), j); elt = zend_hash_index_find(Z_ARRVAL_P(zv), j);
if (!elt || Z_TYPE_P(elt) != IS_LONG) { if (!elt || Z_TYPE_P(elt) != IS_LONG) {
return -1000 - pos; return BYTE_OFFSET_POS_ERROR - pos;
} }
++j; ++j;
val += ((uint64_t) Z_LVAL_P(elt)) << 32; 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) { 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) { if (!hash->ops->serialize_spec) {
*magic = PHP_HASH_SERIALIZE_MAGIC_SPEC; return HASH_SPEC_FAILURE;
return php_hash_serialize_spec(hash, zv, hash->ops->serialize_spec); }
} else {
return 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 if (hash->ops->serialize_spec
&& magic == PHP_HASH_SERIALIZE_MAGIC_SPEC) { && magic == PHP_HASH_SERIALIZE_MAGIC_SPEC) {
return php_hash_unserialize_spec(hash, zv, hash->ops->serialize_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); ZVAL_LONG(&tmp, hash->options);
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp); 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; goto serialize_failure;
} }
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp); zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp);
@ -1504,7 +1500,7 @@ PHP_METHOD(HashContext, __unserialize)
HashTable *data; HashTable *data;
zval *algo_zv, *magic_zv, *options_zv, *hash_zv, *members_zv; zval *algo_zv, *magic_zv, *options_zv, *hash_zv, *members_zv;
zend_long magic, options; zend_long magic, options;
int unserialize_result; hash_spec_result unserialize_result;
const php_hash_ops *ops; const php_hash_ops *ops;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &data) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &data) == FAILURE) {
@ -1553,7 +1549,7 @@ PHP_METHOD(HashContext, __unserialize)
ops->hash_init(hash->context, NULL); ops->hash_init(hash->context, NULL);
unserialize_result = ops->hash_unserialize(hash, magic, hash_zv); 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); zend_throw_exception_ex(NULL, 0, "Incomplete or ill-formed serialization data (\"%s\" code %d)", ops->algo, unserialize_result);
/* free context */ /* free context */
php_hashcontext_dtor(Z_OBJ_P(object)); php_hashcontext_dtor(Z_OBJ_P(object));

View file

@ -304,17 +304,17 @@ PHP_HASH_API void PHP_GOSTFinal(unsigned char digest[32], PHP_GOST_CTX *context)
ZEND_SECURE_ZERO(context, sizeof(*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; 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 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)) { && ctx->length < sizeof(ctx->buffer)) {
return SUCCESS; return HASH_SPEC_SUCCESS;
} else {
return r != SUCCESS ? r : -2000;
} }
return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE;
} }
const php_hash_ops php_hash_gost_ops = { const php_hash_ops php_hash_gost_ops = {

View file

@ -47,7 +47,7 @@ const php_hash_ops php_hash_md4_ops = {
1 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 = { const php_hash_ops php_hash_md2_ops = {
"md2", "md2",
@ -356,15 +356,15 @@ PHP_HASH_API void PHP_MD2Final(unsigned char output[16], PHP_MD2_CTX *context)
memcpy(output, context->state, 16); 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; 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 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)) { && (unsigned char) ctx->in_buffer < sizeof(ctx->buffer)) {
return SUCCESS; return HASH_SPEC_SUCCESS;
} else {
return r != SUCCESS ? r : -2000;
} }
return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE;
} }

View file

@ -200,20 +200,20 @@ static void PHP_SHA3_Final(unsigned char* digest,
ZEND_SECURE_ZERO(ctx, sizeof(PHP_SHA3_CTX)); 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, zend_long magic,
const zval *zv, const zval *zv,
size_t block_size) size_t block_size)
{ {
PHP_SHA3_CTX *ctx = (PHP_SHA3_CTX *) hash->context; 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 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) { && ctx->pos < block_size) {
return SUCCESS; return HASH_SPEC_SUCCESS;
} else {
return r != SUCCESS ? r : -2000;
} }
return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE;
} }
// ========================================================================== // ==========================================================================
@ -292,23 +292,23 @@ const php_hash_ops php_hash_sha3_##bits##_ops = { \
#endif #endif
#define PHP_KECCAK_SPEC "b200IiIIB" #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; *magic = PHP_HASH_SERIALIZE_MAGIC_KECCAK;
return php_hash_serialize_spec(hash, zv, PHP_KECCAK_SPEC); 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; Keccak_HashInstance *ctx = (Keccak_HashInstance *) hash->context;
int r = FAILURE; hash_spec_result r = HASH_SPEC_FAILURE;
if (magic == PHP_HASH_SERIALIZE_MAGIC_KECCAK 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) { && ctx->sponge.byteIOIndex < ctx->sponge.rate / 8) {
return SUCCESS; return HASH_SPEC_SUCCESS;
} else {
return r != SUCCESS ? r : -2000;
} }
return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE;
} }
// ========================================================================== // ==========================================================================

View file

@ -189,17 +189,17 @@ PHP_HASH_API void PHP_SNEFRUFinal(unsigned char digest[32], PHP_SNEFRU_CTX *cont
ZEND_SECURE_ZERO(context, sizeof(*context)); 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; 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 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)) { && ctx->length < sizeof(ctx->buffer)) {
return SUCCESS; return HASH_SPEC_SUCCESS;
} else {
return r != SUCCESS ? r : -2000;
} }
return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE;
} }
const php_hash_ops php_hash_snefru_ops = { const php_hash_ops php_hash_snefru_ops = {

View file

@ -239,17 +239,17 @@ PHP_HASH_API void PHP_TIGER192Final(unsigned char digest[24], PHP_TIGER_CTX *con
ZEND_SECURE_ZERO(context, sizeof(*context)); 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; 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 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)) { && ctx->length < sizeof(ctx->buffer)) {
return SUCCESS; return HASH_SPEC_SUCCESS;
} else {
return r != SUCCESS ? r : -2000;
} }
return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE;
} }
#define PHP_HASH_TIGER_OPS(p, b) \ #define PHP_HASH_TIGER_OPS(p, b) \

View file

@ -429,20 +429,20 @@ PHP_HASH_API void PHP_WHIRLPOOLFinal(unsigned char digest[64], PHP_WHIRLPOOL_CTX
ZEND_SECURE_ZERO(context, sizeof(*context)); 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; 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 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 >= 0
&& ctx->buffer.pos < (int) sizeof(ctx->buffer.data) && ctx->buffer.pos < (int) sizeof(ctx->buffer.data)
&& ctx->buffer.bits >= ctx->buffer.pos * 8 && ctx->buffer.bits >= ctx->buffer.pos * 8
&& ctx->buffer.bits < ctx->buffer.pos * 8 + 8) { && ctx->buffer.bits < ctx->buffer.pos * 8 + 8) {
return SUCCESS; return HASH_SPEC_SUCCESS;
} else {
return r != SUCCESS ? r : -2000;
} }
return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE;
} }
const php_hash_ops php_hash_whirlpool_ops = { const php_hash_ops php_hash_whirlpool_ops = {

View file

@ -17,9 +17,9 @@
#include "php_hash.h" #include "php_hash.h"
#include "php_hash_xxhash.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); 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); php_hashcontext_object *hash, zend_long magic, const zval *zv);
const php_hash_ops php_hash_xxh32_ops = { 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; 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_hashcontext_object *hash, zend_long magic, const zval *zv)
{ {
PHP_XXH32_CTX *ctx = (PHP_XXH32_CTX *) hash->context; 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 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) { && ctx->s.memsize < 16) {
return SUCCESS; return HASH_SPEC_SUCCESS;
} else {
return r != SUCCESS ? r : -2000;
} }
return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE;
} }
const php_hash_ops php_hash_xxh64_ops = { 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; 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_hashcontext_object *hash, zend_long magic, const zval *zv)
{ {
PHP_XXH64_CTX *ctx = (PHP_XXH64_CTX *) hash->context; 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 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) { && ctx->s.memsize < 32) {
return SUCCESS; return HASH_SPEC_SUCCESS;
} else {
return r != SUCCESS ? r : -2000;
} }
return r != HASH_SPEC_SUCCESS ? r : CONTEXT_VALIDATION_FAILURE;
} }
const php_hash_ops php_hash_xxh3_128_ops = { const php_hash_ops php_hash_xxh3_128_ops = {

View file

@ -29,14 +29,22 @@
#define L64 INT64_C #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 struct _php_hashcontext_object php_hashcontext_object;
typedef void (*php_hash_init_func_t)(void *context, HashTable *args); 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_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 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_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 hash_spec_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_unserialize_func_t)(php_hashcontext_object *hash, zend_long magic, const zval *zv);
typedef struct _php_hash_ops { typedef struct _php_hash_ops {
const char *algo; 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 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 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_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 hash_spec_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 hash_spec_result 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 hash_spec_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_unserialize_spec(php_hashcontext_object *hash, const zval *zv, const char *spec);
static inline void *php_hash_alloc_context(const php_hash_ops *ops) { static inline void *php_hash_alloc_context(const php_hash_ops *ops) {
/* Zero out context memory so serialization doesn't expose internals */ /* Zero out context memory so serialization doesn't expose internals */