From 198b3a187bc11b94370429b170b5863c32706523 Mon Sep 17 00:00:00 2001 From: 94xhn <87560781+94xhn@users.noreply.github.com> Date: Sat, 18 Jul 2026 02:04:32 +0800 Subject: [PATCH] map: guard against uint32 overflow when init cap is huge sc_map_alloc_##name() rounds the requested capacity up to the next power of two. When cap is large enough (roughly > 2^31), the round-up wraps uint32_t back to 0 instead of failing. The existing overflow guard 'if (*cap > SC_MAP_MAX / factor)' cannot catch this on the sc_map_init_*() path because factor is 1 there, so the check degenerates to 'cap > UINT32_MAX', which is never true for a uint32_t value. The result: sc_map_init_*() returns true with m->cap silently set to 0 (while still allocating a 1-item buffer). Any later sc_map_get_*()/sc_map_del_*() call then computes 'mod = m->cap - 1', which underflows to UINT32_MAX, and indexes m->mem[pos] with pos derived from a full 32-bit hash - an out-of-bounds access far past the tiny actual allocation. Reproduced with: struct sc_map_str map; sc_map_init_str(&map, 2147483649U, 0); // returns true, map.cap == 0 sc_map_get_str(&map, "somekey"); // segfaults Fix: check for the wrap directly after computing the rounded-up value, regardless of which factor produced it. --- map/sc_map.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/map/sc_map.c b/map/sc_map.c index c81b124..7c22e7e 100644 --- a/map/sc_map.c +++ b/map/sc_map.c @@ -106,6 +106,9 @@ v |= v >> i; \ } \ v++; \ + if (v == 0) { \ + return NULL; \ + } \ \ *cap = v; \ t = sc_map_calloc(v + 1, sizeof(*t)); \