From e68bac5f7dc8807ba9e2e2537b426989ebeb6337 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Sun, 21 Jun 2026 08:13:20 -0400 Subject: [PATCH] Fix unsigned wrap in bzdecompress() output realloc at source_len UINT_MAX The input guard rejects only source_len > UINT_MAX, so source_len == UINT_MAX is permitted and assigned to bzs.avail_out (unsigned int). The per-iteration realloc then computed bzs.avail_out+1 in unsigned int arithmetic, which wraps to 0 at UINT_MAX, allocating no headroom while bz2 still believes avail_out bytes are available at next_out: the next decompress round writes past the buffer. Compute the term as (size_t)bzs.avail_out + 1 so the increment is done in size_t and cannot wrap, matching the (size_t) casts already used on the same call. --- ext/bz2/bz2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/bz2/bz2.c b/ext/bz2/bz2.c index 512632fe8a22..6af8286c5335 100644 --- a/ext/bz2/bz2.c +++ b/ext/bz2/bz2.c @@ -544,7 +544,7 @@ PHP_FUNCTION(bzdecompress) /* no reason to continue if we're going to drop it anyway */ break; } - dest = zend_string_safe_realloc(dest, 1, bzs.avail_out+1, (size_t) size, 0); + dest = zend_string_safe_realloc(dest, 1, (size_t) bzs.avail_out + 1, (size_t) size, 0); bzs.next_out = ZSTR_VAL(dest) + size; }