]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: bits_rotXYY() - Replace signed expression with UNSIGNED_MINUS() macro for unsign...
authorMarco Bettini <marco.bettini@open-xchange.com>
Mon, 29 Nov 2021 14:05:29 +0000 (15:05 +0100)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Tue, 30 Nov 2021 10:03:03 +0000 (10:03 +0000)
Found by code analysis tool

src/lib/bits.h
src/lib/test-bits.c

index 3b761f11b65d8705539f79f5db2b5ab1532a3e32..2e84755be07ad7eb8b844bb0c22f6c60a0cb4304 100644 (file)
 /* ((val & bits) == bits) is uncommon */
 #define HAS_ALL_BITS(val,bits) ((~(val) & (bits)) == 0)
 
+/* negation implemented without using the subtraction operator
+   ~(x - 1) = 1 + ~x these are equivalent by -(-x) == ~(~(x)) == x */
+#define UNSIGNED_MINUS(x) (1 + ~(x))
+
 /* Returns x, such that x is the smallest power of 2 >= num. */
 size_t nearest_power(size_t num) ATTR_CONST;
 
@@ -84,7 +88,7 @@ bits_rotl64(uint64_t num, unsigned int count)
 {
        const unsigned int mask = CHAR_BIT*sizeof(num) - 1;
        count &= mask;
-       return (num << count) | (num >> (-count & mask));
+       return (num << count) | (num >> (UNSIGNED_MINUS(count) & mask));
 }
 
 static inline uint32_t ATTR_NO_SANITIZE_INTEGER
@@ -93,7 +97,7 @@ bits_rotl32(uint32_t num, unsigned int count)
 {
         const unsigned int mask = CHAR_BIT*sizeof(num) - 1;
         count &= mask;
-        return (num << count) | (num >> (-count & mask));
+        return (num << count) | (num >> (UNSIGNED_MINUS(count) & mask));
 }
 
 static inline uint64_t ATTR_NO_SANITIZE_INTEGER
@@ -102,7 +106,7 @@ bits_rotr64(uint64_t num, unsigned int count)
 {
        const unsigned int mask = CHAR_BIT*sizeof(num) - 1;
        count &= mask;
-       return (num >> count) | (num << (-count & mask));
+       return (num >> count) | (num << (UNSIGNED_MINUS(count) & mask));
 }
 
 static inline uint32_t ATTR_NO_SANITIZE_INTEGER
@@ -111,7 +115,7 @@ bits_rotr32(uint32_t num, unsigned int count)
 {
        const unsigned int mask = CHAR_BIT*sizeof(num) - 1;
        count &= mask;
-       return (num >> count) | (num << (-count & mask));
+       return (num >> count) | (num << (UNSIGNED_MINUS(count) & mask));
 }
 
 /* These functions look too big to be inline, but in almost all expected
index c43209aa6b07a9b519ff26c5612c265bda732be7..d091dc5bc7a770657954daeb44ae9f5ec59830d8 100644 (file)
@@ -6,6 +6,44 @@
 
 #include <stdio.h>
 
+static void test_bits_unsigned_minus(void)
+{
+       test_begin("bits_unsigned_minus()");
+
+       // 32 bit
+       test_assert(UNSIGNED_MINUS(0x00000000U) == 0x00000000U);
+
+       test_assert(UNSIGNED_MINUS(0x00000001U) == 0xffffffffU);
+       test_assert(UNSIGNED_MINUS(0x00000002U) == 0xfffffffeU);
+       test_assert(UNSIGNED_MINUS(0x00000003U) == 0xfffffffdU);
+       //..
+       test_assert(UNSIGNED_MINUS(0x7fffffffU) == 0x80000001U);
+       test_assert(UNSIGNED_MINUS(0x80000000U) == 0x80000000U);
+       test_assert(UNSIGNED_MINUS(0x80000001U) == 0x7fffffffU);
+       //..
+       test_assert(UNSIGNED_MINUS(0xffffffffU) == 0x00000001U);
+       test_assert(UNSIGNED_MINUS(0xfffffffeU) == 0x00000002U);
+       test_assert(UNSIGNED_MINUS(0xfffffffdU) == 0x00000003U);
+
+       // 64 bit
+       test_assert(UNSIGNED_MINUS(0x0000000000000000ULL) == 0x0000000000000000ULL);
+
+       test_assert(UNSIGNED_MINUS(0x0000000000000001ULL) == 0xffffffffffffffffULL);
+       test_assert(UNSIGNED_MINUS(0x0000000000000002ULL) == 0xfffffffffffffffeULL);
+       test_assert(UNSIGNED_MINUS(0x0000000000000003ULL) == 0xfffffffffffffffdULL);
+       //..
+       test_assert(UNSIGNED_MINUS(0x7fffffffffffffffULL) == 0x8000000000000001ULL);
+       test_assert(UNSIGNED_MINUS(0x8000000000000000ULL) == 0x8000000000000000ULL);
+       test_assert(UNSIGNED_MINUS(0x8000000000000001ULL) == 0x7fffffffffffffffULL);
+       //..
+       test_assert(UNSIGNED_MINUS(0xffffffffffffffffULL) == 0x0000000000000001ULL);
+       test_assert(UNSIGNED_MINUS(0xfffffffffffffffeULL) == 0x0000000000000002ULL);
+       test_assert(UNSIGNED_MINUS(0xfffffffffffffffdULL) == 0x0000000000000003ULL);
+
+       test_end();
+}
+
+
 /* nearest_power(0) = error      bits_requiredXX(0) = 0
    nearest_power(1) = 1 = 1<<0   bits_requiredXX(1) = 1
    nearest_power(2) = 2 = 1<<1   bits_requiredXX(2) = 2
@@ -156,6 +194,7 @@ static void test_bits_rotl32(void)
        test_assert(bits_rotl32(0x1c00000eU, 3) == 0xe0000070U);
        test_assert(bits_rotl32(0xe0000070U, 5) == 0x00000e1cU);
        test_assert(bits_rotl32(0x00000e1cU, 0) == 0x00000e1cU);
+       test_assert(bits_rotl32(0x1c00000eU, 3 + 32) == 0xe0000070U);
 
        test_end();
 }
@@ -167,6 +206,7 @@ static void test_bits_rotl64(void)
         test_assert(bits_rotl64(0x1c0000000000000eUL, 3) == 0xe000000000000070UL);
         test_assert(bits_rotl64(0xe000000000000070UL, 5) == 0x0000000000000e1cUL);
         test_assert(bits_rotl64(0x0000000000000e1cUL, 0) == 0x0000000000000e1cUL);
+        test_assert(bits_rotl64(0x1c0000000000000eUL, 3 + 64) == 0xe000000000000070UL);
 
        test_end();
 }
@@ -178,6 +218,7 @@ static void test_bits_rotr32(void)
        test_assert(bits_rotr32(0x1c00000eU, 3) == 0xc3800001U);
        test_assert(bits_rotr32(0xc3800001U, 5) == 0x0e1c0000U);
        test_assert(bits_rotr32(0x00000e1cU, 0) == 0x00000e1cU);
+       test_assert(bits_rotr32(0x1c00000eU, 3 + 32) == 0xc3800001U);
 
        test_end();
 }
@@ -189,6 +230,7 @@ static void test_bits_rotr64(void)
        test_assert(bits_rotr64(0x1c0000000000000eUL, 3) == 0xc380000000000001UL);
        test_assert(bits_rotr64(0xc380000000000001UL, 5) == 0x0e1c000000000000UL);
        test_assert(bits_rotr64(0x0000000000000e1cUL, 0) == 0x0000000000000e1cUL);
+       test_assert(bits_rotr64(0x1c0000000000000eUL, 3 + 64) == 0xc380000000000001UL);
 
        test_end();
 }
@@ -224,6 +266,7 @@ static void test_bit_tests(void)
 
 void test_bits(void)
 {
+       test_bits_unsigned_minus();
        test_nearest_power();
        test_bits_is_power_of_two();
        test_bits_requiredXX();