[php-src] master: Merge branch '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:55-04:00

Commit: https://github.com/php/php-src/commit/81f09e8cf06c72cf5de809a8085fda76357ab556
Raw diff: https://github.com/php/php-src/commit/81f09e8cf06c72cf5de809a8085fda76357ab556.diff

Merge branch 'PHP-8.5'

* PHP-8.5:
  Fix GH-18173: ext/hash relies on implementation-defined malloc alignment

Changed paths:
  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/ext/hash/hash.c b/ext/hash/hash.c
index 3ba42c8ff85d..e2af98c81ddf 100644
--- a/ext/hash/hash.c
+++ b/ext/hash/hash.c
@@ -386,7 +386,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 {
@@ -395,7 +395,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;
@@ -534,7 +534,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;
@@ -552,7 +552,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;
@@ -813,7 +813,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) {
@@ -967,7 +967,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;
@@ -1083,7 +1083,7 @@ PHP_FUNCTION(hash_pbkdf2)
 	efree(K1);
 	efree(K2);
 	efree(computed_salt);
-	efree(context);
+	php_hash_free_context(ops, context);
 	efree(digest);
 	efree(temp);
 
@@ -1348,7 +1348,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);
 			}
 		}
@@ -1378,7 +1378,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;
 	}
 
@@ -1414,7 +1414,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 2a40b3318cd5..1f5ae3756a0a 100644
--- a/ext/hash/hash_adler32.c
+++ b/ext/hash/hash_adler32.c
@@ -68,5 +68,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 795cfcdf05b2..407150a1cdd3 100644
--- a/ext/hash/hash_crc32.c
+++ b/ext/hash/hash_crc32.c
@@ -100,6 +100,7 @@ const php_hash_ops php_hash_crc32_ops = {
 	4, /* what to say here? */
 	4,
 	sizeof(PHP_CRC32_CTX),
+	0,
 	0
 };
 
@@ -115,6 +116,7 @@ const php_hash_ops php_hash_crc32b_ops = {
 	4, /* what to say here? */
 	4,
 	sizeof(PHP_CRC32_CTX),
+	0,
 	0
 };
 
@@ -130,5 +132,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 58101c4f2e6c..7859e5908870 100644
--- a/ext/hash/hash_fnv.c
+++ b/ext/hash/hash_fnv.c
@@ -30,6 +30,7 @@ const php_hash_ops php_hash_fnv132_ops = {
 	4,
 	4,
 	sizeof(PHP_FNV132_CTX),
+	0,
 	0
 };
 
@@ -45,6 +46,7 @@ const php_hash_ops php_hash_fnv1a32_ops = {
 	4,
 	4,
 	sizeof(PHP_FNV132_CTX),
+	0,
 	0
 };
 
@@ -60,6 +62,7 @@ const php_hash_ops php_hash_fnv164_ops = {
 	8,
 	4,
 	sizeof(PHP_FNV164_CTX),
+	0,
 	0
 };
 
@@ -75,6 +78,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 ad87754970b9..91edbd50834f 100644
--- a/ext/hash/hash_gost.c
+++ b/ext/hash/hash_gost.c
@@ -327,7 +327,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 = {
@@ -342,5 +343,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 2adafdb189e2..b326142cc7ef 100644
--- a/ext/hash/hash_haval.c
+++ b/ext/hash/hash_haval.c
@@ -250,7 +250,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 0d7b64092f47..0550af18dce7 100644
--- a/ext/hash/hash_joaat.c
+++ b/ext/hash/hash_joaat.c
@@ -31,6 +31,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 0bd48a9c823c..44d43e16777f 100644
--- a/ext/hash/hash_md.c
+++ b/ext/hash/hash_md.c
@@ -27,7 +27,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 = {
@@ -42,7 +43,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);
@@ -59,7 +61,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 cd5d5f4be520..1e63262c20ed 100644
--- a/ext/hash/hash_murmur.c
+++ b/ext/hash/hash_murmur.c
@@ -31,6 +31,7 @@ const php_hash_ops php_hash_murmur3a_ops = {
 	4,
 	4,
 	sizeof(PHP_MURMUR3A_CTX),
+	0,
 	0
 };
 
@@ -93,6 +94,7 @@ const php_hash_ops php_hash_murmur3c_ops = {
 	16,
 	4,
 	sizeof(PHP_MURMUR3C_CTX),
+	0,
 	0
 };
 
@@ -172,6 +174,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 1b76f58ff098..c6396ba2a60a 100644
--- a/ext/hash/hash_ripemd.c
+++ b/ext/hash/hash_ripemd.c
@@ -31,7 +31,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 = {
@@ -46,7 +47,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 = {
@@ -61,7 +63,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 = {
@@ -76,7 +79,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 fd4d8ce5a36a..3a7729e31fc0 100644
--- a/ext/hash/hash_sha.c
+++ b/ext/hash/hash_sha.c
@@ -73,7 +73,8 @@ const php_hash_ops php_hash_sha1_ops = {
 	20,
 	64,
 	sizeof(PHP_SHA1_CTX),
-	1
+	1,
+	0
 };
 
 /* sha224/sha256 */
@@ -90,7 +91,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 = {
@@ -105,7 +107,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)))
@@ -622,7 +625,8 @@ const php_hash_ops php_hash_sha384_ops = {
 	48,
 	128,
 	sizeof(PHP_SHA384_CTX),
-	1
+	1,
+	0
 };
 
 /* {{{ PHP_SHA512InitArgs
@@ -801,7 +805,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 = {
@@ -816,7 +821,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 = {
@@ -831,5 +837,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 d82840e81de6..3f5d966820cd 100644
--- a/ext/hash/hash_sha3.c
+++ b/ext/hash/hash_sha3.c
@@ -249,7 +249,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
@@ -337,7 +338,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 5f08eb088229..3fe16b4398a3 100644
--- a/ext/hash/hash_snefru.c
+++ b/ext/hash/hash_snefru.c
@@ -212,5 +212,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 1153711d85d4..f9b4dc737581 100644
--- a/ext/hash/hash_tiger.c
+++ b/ext/hash/hash_tiger.c
@@ -263,7 +263,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 2a5b220d3a18..9d895efa06e7 100644
--- a/ext/hash/hash_whirlpool.c
+++ b/ext/hash/hash_whirlpool.c
@@ -455,5 +455,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 b6177905e691..e0f400fc517e 100644
--- a/ext/hash/hash_xxhash.c
+++ b/ext/hash/hash_xxhash.c
@@ -32,6 +32,7 @@ const php_hash_ops php_hash_xxh32_ops = {
 	4,
 	4,
 	sizeof(PHP_XXH32_CTX),
+	0,
 	0
 };
 
@@ -99,6 +100,7 @@ const php_hash_ops php_hash_xxh64_ops = {
 	8,
 	8,
 	sizeof(PHP_XXH64_CTX),
+	0,
 	0
 };
 
@@ -150,7 +152,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);
@@ -255,7 +258,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 9eac5da78c8d..f89bee8ab010 100644
--- a/ext/hash/php_hash.h
+++ b/ext/hash/php_hash.h
@@ -58,6 +58,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 {
@@ -161,9 +162,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";
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.