From 2c8c36be454daf4c6aa2ec3864361f88485e588e Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Thu, 8 Oct 2026 14:41:26 +0200 Subject: [PATCH] struct: fix infinite loop in grow_buffer() for small sizes The growth step in grow_buffer() was `n += ((n >> 1) + 7u) & ~7u` which adds 0 when new_size is small (<= 15), since (n>>1)+7 lands in [3,14] and rounding down to an 8-byte boundary yields 0. The loop then spins forever. This is hit when a buffer is first grown with a zero-length size (which allocates a chunk but leaves capacity at 0), and then a subsequent put() needs to grow from that 0 capacity. e.g.: b = struct.buffer() b.put("*", "") # grow to 0 -> data != NULL, capacity stays 0 b.put("*", "x") # grow from 0 -> infinite loop Use +8u (not +7u) so the growth step is always >= 8 bytes and the loop always makes progress. Fixes `ucode -lstruct -p 'b=struct.buffer(); b.put("*",""); b.put("*","x")'` hanging. Signed-off-by: Jo-Philipp Wich --- lib/struct.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/struct.c b/lib/struct.c index f18cb8ca..dc4882dc 100644 --- a/lib/struct.c +++ b/lib/struct.c @@ -2541,7 +2541,12 @@ grow_buffer(uc_vm_t *vm, void **buf, size_t *bufsz, size_t length) return false; } - new_size += ((new_size >> 1) + 7u) & ~7u; + /* Use +8u (not +7u) so the growth step is always >= 8 bytes: + * with +7u the expression ((new_size >> 1) + 7u) & ~7u + * evaluates to 0 for new_size <= 15, stalling the loop + * forever when *bufsz is 0 (e.g. a buffer that was + * allocated with a zero-byte grow). */ + new_size += ((new_size >> 1) + 8u) & ~7u; } }