From 6a217a06d9e08f79b6f71ab1cb3f1b432374fe01 Mon Sep 17 00:00:00 2001 From: Timothy Arceri Date: Tue, 29 Jul 2025 10:24:04 +1000 Subject: [PATCH] util: remove recursion from bitset helpers Recursion can cause a stack overflow when the range is very large. Fixes: cb558b2b88c2 ("glsl: add mark_array_elements_referenced() fast path") Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/13617 Reviewed-by: Gert Wollny Reviewed-by: Caio Oliveira Part-of: --- src/util/bitset.h | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/src/util/bitset.h b/src/util/bitset.h index cf9e59a01cf..594f8cc56db 100644 --- a/src/util/bitset.h +++ b/src/util/bitset.h @@ -226,17 +226,17 @@ __bitset_shl(BITSET_WORD *x, unsigned amount, unsigned n) static inline bool __bitset_test_range(const BITSET_WORD *r, unsigned start, unsigned end) { - const unsigned size = end - start + 1; - const unsigned start_mod = start % BITSET_WORDBITS; + while (start <= end) { + unsigned start_mod = start % BITSET_WORDBITS; + unsigned size = MIN2(BITSET_WORDBITS - start_mod, end - start + 1); - if (start_mod + size <= BITSET_WORDBITS) { - return !BITSET_TEST_RANGE_INSIDE_WORD(r, start, end, 0); - } else { - const unsigned first_size = BITSET_WORDBITS - start_mod; + if (!BITSET_TEST_RANGE_INSIDE_WORD(r, start, start + size - 1, 0)) + return true; - return __bitset_test_range(r, start, start + first_size - 1) || - __bitset_test_range(r, start + first_size, end); + start += size; } + + return false; } #define BITSET_TEST_RANGE(x, b, e) \ @@ -245,16 +245,12 @@ __bitset_test_range(const BITSET_WORD *r, unsigned start, unsigned end) static inline void __bitset_set_range(BITSET_WORD *r, unsigned start, unsigned end) { - const unsigned size = end - start + 1; - const unsigned start_mod = start % BITSET_WORDBITS; + while (start <= end) { + unsigned start_mod = start % BITSET_WORDBITS; + unsigned size = MIN2(BITSET_WORDBITS - start_mod, end - start + 1); - if (start_mod + size <= BITSET_WORDBITS) { - BITSET_SET_RANGE_INSIDE_WORD(r, start, end); - } else { - const unsigned first_size = BITSET_WORDBITS - start_mod; - - __bitset_set_range(r, start, start + first_size - 1); - __bitset_set_range(r, start + first_size, end); + BITSET_SET_RANGE_INSIDE_WORD(r, start, start + size - 1); + start += size; } } @@ -264,16 +260,12 @@ __bitset_set_range(BITSET_WORD *r, unsigned start, unsigned end) static inline void __bitclear_clear_range(BITSET_WORD *r, unsigned start, unsigned end) { - const unsigned size = end - start + 1; - const unsigned start_mod = start % BITSET_WORDBITS; + while (start <= end) { + unsigned start_mod = start % BITSET_WORDBITS; + unsigned size = MIN2(BITSET_WORDBITS - start_mod, end - start + 1); - if (start_mod + size <= BITSET_WORDBITS) { - BITSET_CLEAR_RANGE_INSIDE_WORD(r, start, end); - } else { - const unsigned first_size = BITSET_WORDBITS - start_mod; - - __bitclear_clear_range(r, start, start + first_size - 1); - __bitclear_clear_range(r, start + first_size, end); + BITSET_CLEAR_RANGE_INSIDE_WORD(r, start, start + size - 1); + start += size; } }