]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: panic on nearest_power() overflow with the offending value
authorAki Tuomi <aki.tuomi@open-xchange.com>
Wed, 20 May 2026 12:21:01 +0000 (15:21 +0300)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Fri, 22 May 2026 10:23:03 +0000 (13:23 +0300)
Replace the i_assert() with an i_panic() that reports the input
value, making overflow failures easier to diagnose. Add unit tests
for the boundary input and a fatal test for the overflow case.

Co-Authored-By: uwezkhan06 <uwezkhan053@gmail.com>
src/lib/bits.c
src/lib/test-bits.c
src/lib/test-lib.inc

index a76a815996990bdface255ec5dbdbb9d658d1905..56ac38f4dd3c796b6b2a6ee1f7acf55cf5dccc11 100644 (file)
@@ -14,7 +14,8 @@
 
 size_t nearest_power(size_t num)
 {
-       i_assert(num <= ((size_t)1 << (CHAR_BIT*sizeof(size_t) - 1)));
+       if (unlikely(num > ((size_t)1 << (CHAR_BIT*sizeof(size_t) - 1))))
+               i_panic("nearest_power(%zu): calculation would overflow", num);
 
        if (num == 0)
                return 1;
index d091dc5bc7a770657954daeb44ae9f5ec59830d8..9657c07d0953b97813f19f278698d8d4ec5ef07f 100644 (file)
@@ -60,6 +60,7 @@ static void test_nearest_power(void)
        unsigned int b;
        size_t num;
        test_begin("nearest_power()");
+       test_assert(nearest_power(0)==1);
        test_assert(nearest_power(1)==1);
        test_assert(nearest_power(2)==2);
        for (b = 2; b < CHAR_BIT*sizeof(size_t) - 1; ++b) {
@@ -74,6 +75,9 @@ static void test_nearest_power(void)
        test_assert_idx(nearest_power(num-1) == num,    b);
        test_assert_idx(nearest_power(num  ) == num,    b);
        /* i_assert()s: test_assert_idx(nearest_power(num+1) == num<<1, b); */
+       /* Test edge case: nearest_power should never return a value smaller than input */
+       num = ((size_t)1 << (CHAR_BIT * sizeof(size_t) - 1));
+       test_assert(nearest_power(num) >= num);
        test_end();
 }
 
@@ -279,3 +283,20 @@ void test_bits(void)
        test_sum_overflows();
        test_bit_tests();
 }
+
+enum fatal_test_state fatal_bits(unsigned int stage)
+{
+       /* Needs volatile to avoid compiler optimization */
+       volatile size_t num = ((size_t)1 << (CHAR_BIT * sizeof(size_t) - 1));
+       switch (stage) {
+       case 0:
+               test_begin("nearest_power() overflow");
+               test_expect_fatal_string("calculation would overflow");
+               num = nearest_power(num + 1);
+               return FATAL_TEST_FAILURE;
+       default:
+               break;
+       }
+       test_end();
+       return FATAL_TEST_FINISHED;
+}
index 91c6a971247fe6b1a936d877dd4db8ef2be80a4c..a4a0b037be07626b29f9d727bd2e9a1548c9dbdd 100644 (file)
@@ -9,6 +9,7 @@ TEST(test_backtrace)
 TEST(test_base32)
 TEST(test_base64)
 TEST(test_bits)
+FATAL(fatal_bits)
 TEST(test_bsearch_insert_pos)
 TEST(test_buffer)
 TEST(test_buffer_append_full)