[php-src] PHP-8.5: Merge branch 'PHP-8.4' into PHP-8.5
Ilia Alshanetsky <[email protected]>
| Newsgroups | gmane.comp.php.cvs.general |
|---|---|
| Message-ID | <[email protected]> |
Author: Ilia Alshanetsky (iliaal)
Date: 2026-06-29T10:37:47-04:00
Commit: https://github.com/php/php-src/commit/6c1b05c429015abde24a5024965dde97a7df1cc7
Raw diff: https://github.com/php/php-src/commit/6c1b05c429015abde24a5024965dde97a7df1cc7.diff
Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4:
Fix GH-18173: ext/hash relies on implementation-defined malloc alignment
Changed paths:
M NEWS
M ext/hash/hash.c
M ext/hash/hash_adler32.c
M ext/hash/hash_crc32.c
M ext/hash/hash_fnv.c
M ext/hash/hash_gost.c
M ext/hash/hash_haval.c
M ext/hash/hash_joaat.c
M ext/hash/hash_md.c
M ext/hash/hash_murmur.c
M ext/hash/hash_ripemd.c
M ext/hash/hash_sha.c
M ext/hash/hash_sha3.c
M ext/hash/hash_snefru.c
M ext/hash/hash_tiger.c
M ext/hash/hash_whirlpool.c
M ext/hash/hash_xxhash.c
M ext/hash/php_hash.h
Diff:
diff --git a/NEWS b/NEWS
index 89f41d2bb2d3..dc37bcf555da 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,10 @@ PHP NEWS
. Fixed bug GH-22206 (missing return in global register detection).
(P3p111n0)
+- Hash:
+ . Fixed bug GH-18173 (ext/hash relies on implementation-defined malloc
+ alignment). (iliaal)
+
- Opcache:
. Fixed bug GH-22158 (Tracing JIT dispatches the observer begin handler
through the wrong run_time_cache slot on megamorphic calls). (ptondereau,
diff --git a/ext/hash/hash.c b/ext/hash/hash.c
index ec5391a62304..6e8bc49d34d1 100644
--- a/ext/hash/hash.c
+++ b/ext/hash/hash.c
@@ -388,7 +388,7 @@ static void php_hash_do_hash(
}
php_stream_close(stream);
if (n < 0) {
- efree(context);
+ php_hash_free_context(ops, context);
RETURN_FALSE;
}
} else {
@@ -397,7 +397,7 @@ static void php_hash_do_hash(
digest = zend_string_alloc(ops->digest_size, 0);
ops->hash_final((unsigned char *) ZSTR_VAL(digest), context);
- efree(context);
+ php_hash_free_context(ops, context);
if (raw_output) {
ZSTR_VAL(digest)[ops->digest_size] = 0;
@@ -536,7 +536,7 @@ static void php_hash_do_hash_hmac(
}
php_stream_close(stream);
if (n < 0) {
- efree(context);
+ php_hash_free_context(ops, context);
efree(K);
zend_string_efree(digest);
RETURN_FALSE;
@@ -554,7 +554,7 @@ static void php_hash_do_hash_hmac(
/* Zero the key */
ZEND_SECURE_ZERO(K, ops->block_size);
efree(K);
- efree(context);
+ php_hash_free_context(ops, context);
if (raw_output) {
ZSTR_VAL(digest)[ops->digest_size] = 0;
@@ -815,7 +815,7 @@ PHP_FUNCTION(hash_final)
ZSTR_VAL(digest)[digest_len] = 0;
/* Invalidate the object from further use */
- efree(hash->context);
+ php_hash_free_context(hash->ops, hash->context);
hash->context = NULL;
if (raw_output) {
@@ -973,7 +973,7 @@ PHP_FUNCTION(hash_hkdf)
ZEND_SECURE_ZERO(digest, ops->digest_size);
ZEND_SECURE_ZERO(prk, ops->digest_size);
efree(K);
- efree(context);
+ php_hash_free_context(ops, context);
efree(prk);
efree(digest);
ZSTR_VAL(returnval)[length] = 0;
@@ -1089,7 +1089,7 @@ PHP_FUNCTION(hash_pbkdf2)
efree(K1);
efree(K2);
efree(computed_salt);
- efree(context);
+ php_hash_free_context(ops, context);
efree(digest);
efree(temp);
@@ -1356,7 +1356,7 @@ PHP_FUNCTION(mhash_keygen_s2k)
RETVAL_STRINGL(key, bytes);
ZEND_SECURE_ZERO(key, bytes);
efree(digest);
- efree(context);
+ php_hash_free_context(ops, context);
efree(key);
}
}
@@ -1386,7 +1386,7 @@ static void php_hashcontext_dtor(zend_object *obj) {
php_hashcontext_object *hash = php_hashcontext_from_object(obj);
if (hash->context) {
- efree(hash->context);
+ php_hash_free_context(hash->ops, hash->context);
hash->context = NULL;
}
@@ -1422,7 +1422,7 @@ static zend_object *php_hashcontext_clone(zend_object *zobj) {
newobj->ops->hash_init(newobj->context, NULL);
if (SUCCESS != newobj->ops->hash_copy(newobj->ops, oldobj->context, newobj->context)) {
- efree(newobj->context);
+ php_hash_free_context(newobj->ops, newobj->context);
newobj->context = NULL;
return znew;
}
diff --git a/ext/hash/hash_adler32.c b/ext/hash/hash_adler32.c
index 3898ea60e877..e1fdd765b372 100644
--- a/ext/hash/hash_adler32.c
+++ b/ext/hash/hash_adler32.c
@@ -70,5 +70,6 @@ const php_hash_ops php_hash_adler32_ops = {
4, /* what to say here? */
4,
sizeof(PHP_ADLER32_CTX),
+ 0,
0
};
diff --git a/ext/hash/hash_crc32.c b/ext/hash/hash_crc32.c
index a770d0b55416..2e8de00b518d 100644
--- a/ext/hash/hash_crc32.c
+++ b/ext/hash/hash_crc32.c
@@ -102,6 +102,7 @@ const php_hash_ops php_hash_crc32_ops = {
4, /* what to say here? */
4,
sizeof(PHP_CRC32_CTX),
+ 0,
0
};
@@ -117,6 +118,7 @@ const php_hash_ops php_hash_crc32b_ops = {
4, /* what to say here? */
4,
sizeof(PHP_CRC32_CTX),
+ 0,
0
};
@@ -132,5 +134,6 @@ const php_hash_ops php_hash_crc32c_ops = {
4, /* what to say here? */
4,
sizeof(PHP_CRC32_CTX),
+ 0,
0
};
diff --git a/ext/hash/hash_fnv.c b/ext/hash/hash_fnv.c
index 92d4922bd810..c126de61cfd1 100644
--- a/ext/hash/hash_fnv.c
+++ b/ext/hash/hash_fnv.c
@@ -32,6 +32,7 @@ const php_hash_ops php_hash_fnv132_ops = {
4,
4,
sizeof(PHP_FNV132_CTX),
+ 0,
0
};
@@ -47,6 +48,7 @@ const php_hash_ops php_hash_fnv1a32_ops = {
4,
4,
sizeof(PHP_FNV132_CTX),
+ 0,
0
};
@@ -62,6 +64,7 @@ const php_hash_ops php_hash_fnv164_ops = {
8,
4,
sizeof(PHP_FNV164_CTX),
+ 0,
0
};
@@ -77,6 +80,7 @@ const php_hash_ops php_hash_fnv1a64_ops = {
8,
4,
sizeof(PHP_FNV164_CTX),
+ 0,
0
};
diff --git a/ext/hash/hash_gost.c b/ext/hash/hash_gost.c
index bba585a11f9f..c2dfa144dcd9 100644
--- a/ext/hash/hash_gost.c
+++ b/ext/hash/hash_gost.c
@@ -329,7 +329,8 @@ const php_hash_ops php_hash_gost_ops = {
32,
32,
sizeof(PHP_GOST_CTX),
- 1
+ 1,
+ 0
};
const php_hash_ops php_hash_gost_crypto_ops = {
@@ -344,5 +345,6 @@ const php_hash_ops php_hash_gost_crypto_ops = {
32,
32,
sizeof(PHP_GOST_CTX),
- 1
+ 1,
+ 0
};
diff --git a/ext/hash/hash_haval.c b/ext/hash/hash_haval.c
index 67bc2b2e4780..484b9a582915 100644
--- a/ext/hash/hash_haval.c
+++ b/ext/hash/hash_haval.c
@@ -252,7 +252,7 @@ const php_hash_ops php_hash_##p##haval##b##_ops = { \
php_hash_serialize, \
php_hash_unserialize, \
PHP_HAVAL_SPEC, \
- ((b) / 8), 128, sizeof(PHP_HAVAL_CTX), 1 }; \
+ ((b) / 8), 128, sizeof(PHP_HAVAL_CTX), 1, 0 }; \
PHP_HASH_API void PHP_##p##HAVAL##b##Init(PHP_HAVAL_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args) \
{ int i; context->count[0] = context->count[1] = 0; \
for(i = 0; i < 8; i++) context->state[i] = D0[i]; \
diff --git a/ext/hash/hash_joaat.c b/ext/hash/hash_joaat.c
index 328f9292c4ca..6a16ceeeda14 100644
--- a/ext/hash/hash_joaat.c
+++ b/ext/hash/hash_joaat.c
@@ -33,6 +33,7 @@ const php_hash_ops php_hash_joaat_ops = {
4,
4,
sizeof(PHP_JOAAT_CTX),
+ 0,
0
};
diff --git a/ext/hash/hash_md.c b/ext/hash/hash_md.c
index dd299e695891..4af74871fb03 100644
--- a/ext/hash/hash_md.c
+++ b/ext/hash/hash_md.c
@@ -29,7 +29,8 @@ const php_hash_ops php_hash_md5_ops = {
16,
64,
sizeof(PHP_MD5_CTX),
- 1
+ 1,
+ 0
};
const php_hash_ops php_hash_md4_ops = {
@@ -44,7 +45,8 @@ const php_hash_ops php_hash_md4_ops = {
16,
64,
sizeof(PHP_MD4_CTX),
- 1
+ 1,
+ 0
};
static hash_spec_result php_md2_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv);
@@ -61,7 +63,8 @@ const php_hash_ops php_hash_md2_ops = {
16,
16,
sizeof(PHP_MD2_CTX),
- 1
+ 1,
+ 0
};
/* MD common stuff */
diff --git a/ext/hash/hash_murmur.c b/ext/hash/hash_murmur.c
index 0117b2e57d36..d69c5c3bb688 100644
--- a/ext/hash/hash_murmur.c
+++ b/ext/hash/hash_murmur.c
@@ -33,6 +33,7 @@ const php_hash_ops php_hash_murmur3a_ops = {
4,
4,
sizeof(PHP_MURMUR3A_CTX),
+ 0,
0
};
@@ -95,6 +96,7 @@ const php_hash_ops php_hash_murmur3c_ops = {
16,
4,
sizeof(PHP_MURMUR3C_CTX),
+ 0,
0
};
@@ -174,6 +176,7 @@ const php_hash_ops php_hash_murmur3f_ops = {
16,
8,
sizeof(PHP_MURMUR3F_CTX),
+ 0,
0
};
diff --git a/ext/hash/hash_ripemd.c b/ext/hash/hash_ripemd.c
index 4802fdf9a1fc..188d0095cbc3 100644
--- a/ext/hash/hash_ripemd.c
+++ b/ext/hash/hash_ripemd.c
@@ -33,7 +33,8 @@ const php_hash_ops php_hash_ripemd128_ops = {
16,
64,
sizeof(PHP_RIPEMD128_CTX),
- 1
+ 1,
+ 0
};
const php_hash_ops php_hash_ripemd160_ops = {
@@ -48,7 +49,8 @@ const php_hash_ops php_hash_ripemd160_ops = {
20,
64,
sizeof(PHP_RIPEMD160_CTX),
- 1
+ 1,
+ 0
};
const php_hash_ops php_hash_ripemd256_ops = {
@@ -63,7 +65,8 @@ const php_hash_ops php_hash_ripemd256_ops = {
32,
64,
sizeof(PHP_RIPEMD256_CTX),
- 1
+ 1,
+ 0
};
const php_hash_ops php_hash_ripemd320_ops = {
@@ -78,7 +81,8 @@ const php_hash_ops php_hash_ripemd320_ops = {
40,
64,
sizeof(PHP_RIPEMD320_CTX),
- 1
+ 1,
+ 0
};
/* {{{ PHP_RIPEMD128Init
diff --git a/ext/hash/hash_sha.c b/ext/hash/hash_sha.c
index 3129446fcde4..c45947b8584f 100644
--- a/ext/hash/hash_sha.c
+++ b/ext/hash/hash_sha.c
@@ -75,7 +75,8 @@ const php_hash_ops php_hash_sha1_ops = {
20,
64,
sizeof(PHP_SHA1_CTX),
- 1
+ 1,
+ 0
};
/* sha224/sha256 */
@@ -92,7 +93,8 @@ const php_hash_ops php_hash_sha256_ops = {
32,
64,
sizeof(PHP_SHA256_CTX),
- 1
+ 1,
+ 0
};
const php_hash_ops php_hash_sha224_ops = {
@@ -107,7 +109,8 @@ const php_hash_ops php_hash_sha224_ops = {
28,
64,
sizeof(PHP_SHA224_CTX),
- 1
+ 1,
+ 0
};
#define ROTR32(b,x) ((x >> b) | (x << (32 - b)))
@@ -624,7 +627,8 @@ const php_hash_ops php_hash_sha384_ops = {
48,
128,
sizeof(PHP_SHA384_CTX),
- 1
+ 1,
+ 0
};
/* {{{ PHP_SHA512InitArgs
@@ -803,7 +807,8 @@ const php_hash_ops php_hash_sha512_ops = {
64,
128,
sizeof(PHP_SHA512_CTX),
- 1
+ 1,
+ 0
};
const php_hash_ops php_hash_sha512_256_ops = {
@@ -818,7 +823,8 @@ const php_hash_ops php_hash_sha512_256_ops = {
32,
128,
sizeof(PHP_SHA512_CTX),
- 1
+ 1,
+ 0
};
const php_hash_ops php_hash_sha512_224_ops = {
@@ -833,5 +839,6 @@ const php_hash_ops php_hash_sha512_224_ops = {
28,
128,
sizeof(PHP_SHA512_CTX),
- 1
+ 1,
+ 0
};
diff --git a/ext/hash/hash_sha3.c b/ext/hash/hash_sha3.c
index 8fa0a4b4e522..fea8998e55aa 100644
--- a/ext/hash/hash_sha3.c
+++ b/ext/hash/hash_sha3.c
@@ -251,7 +251,8 @@ const php_hash_ops php_hash_sha3_##bits##_ops = { \
bits >> 3, \
(1600 - (2 * bits)) >> 3, \
sizeof(PHP_SHA3_##bits##_CTX), \
- 1 \
+ 1, \
+ 0 \
}
#else
@@ -339,7 +340,8 @@ const php_hash_ops php_hash_sha3_##bits##_ops = { \
bits >> 3, \
(1600 - (2 * bits)) >> 3, \
sizeof(PHP_SHA3_CTX), \
- 1 \
+ 1, \
+ 0 \
}
#endif
diff --git a/ext/hash/hash_snefru.c b/ext/hash/hash_snefru.c
index b9b70f364208..7f167c38a8a5 100644
--- a/ext/hash/hash_snefru.c
+++ b/ext/hash/hash_snefru.c
@@ -214,5 +214,6 @@ const php_hash_ops php_hash_snefru_ops = {
32,
32,
sizeof(PHP_SNEFRU_CTX),
- 1
+ 1,
+ 0
};
diff --git a/ext/hash/hash_tiger.c b/ext/hash/hash_tiger.c
index 62d1b7347143..8dbcdde0afb3 100644
--- a/ext/hash/hash_tiger.c
+++ b/ext/hash/hash_tiger.c
@@ -265,7 +265,8 @@ static hash_spec_result php_tiger_unserialize(php_hashcontext_object *hash, zend
b/8, \
64, \
sizeof(PHP_TIGER_CTX), \
- 1 \
+ 1, \
+ 0 \
}
PHP_HASH_TIGER_OPS(3, 128);
diff --git a/ext/hash/hash_whirlpool.c b/ext/hash/hash_whirlpool.c
index fa3c216a64c4..b1ec068342c6 100644
--- a/ext/hash/hash_whirlpool.c
+++ b/ext/hash/hash_whirlpool.c
@@ -457,5 +457,6 @@ const php_hash_ops php_hash_whirlpool_ops = {
64,
64,
sizeof(PHP_WHIRLPOOL_CTX),
- 1
+ 1,
+ 0
};
diff --git a/ext/hash/hash_xxhash.c b/ext/hash/hash_xxhash.c
index add922e8e84f..690b5489c7ef 100644
--- a/ext/hash/hash_xxhash.c
+++ b/ext/hash/hash_xxhash.c
@@ -34,6 +34,7 @@ const php_hash_ops php_hash_xxh32_ops = {
4,
4,
sizeof(PHP_XXH32_CTX),
+ 0,
0
};
@@ -101,6 +102,7 @@ const php_hash_ops php_hash_xxh64_ops = {
8,
8,
sizeof(PHP_XXH64_CTX),
+ 0,
0
};
@@ -152,7 +154,8 @@ const php_hash_ops php_hash_xxh3_64_ops = {
8,
8,
sizeof(PHP_XXH3_64_CTX),
- 0
+ 0,
+ 64
};
typedef XXH_errorcode (*xxh3_reset_with_secret_func_t)(XXH3_state_t*, const void*, size_t);
@@ -257,7 +260,8 @@ const php_hash_ops php_hash_xxh3_128_ops = {
16,
8,
sizeof(PHP_XXH3_128_CTX),
- 0
+ 0,
+ 64
};
PHP_HASH_API void PHP_XXH3_128_Init(PHP_XXH3_128_CTX *ctx, HashTable *args)
diff --git a/ext/hash/php_hash.h b/ext/hash/php_hash.h
index f56605a33be6..34d44137028d 100644
--- a/ext/hash/php_hash.h
+++ b/ext/hash/php_hash.h
@@ -60,6 +60,7 @@ typedef struct _php_hash_ops {
size_t block_size;
size_t context_size;
unsigned is_crypto: 1;
+ size_t context_align;
} php_hash_ops;
struct _php_hashcontext_object {
@@ -163,9 +164,26 @@ PHP_HASH_API hash_spec_result php_hash_unserialize_spec(php_hashcontext_object *
static inline void *php_hash_alloc_context(const php_hash_ops *ops) {
/* Zero out context memory so serialization doesn't expose internals */
+ if (ops->context_align > 0) {
+ size_t align = ops->context_align;
+ char *base = ecalloc(1, ops->context_size + align);
+ size_t offset = align - ((uintptr_t)base & (align - 1));
+ char *ptr = base + offset;
+ ptr[-1] = (char)offset;
+ return ptr;
+ }
return ecalloc(1, ops->context_size);
}
+static inline void php_hash_free_context(const php_hash_ops *ops, void *ctx) {
+ if (ops->context_align > 0) {
+ unsigned char offset = ((unsigned char *)ctx)[-1];
+ efree((char *)ctx - offset);
+ return;
+ }
+ efree(ctx);
+}
+
static inline void php_hash_bin2hex(char *out, const unsigned char *in, size_t in_len)
{
static const char hexits[17] = "0123456789abcdef";