Hash functions rely heavily on unsigned integer overflow behavior, but
the sanitizer complains about them. Instead of disabling the sanitizer
(which might prevent us from getting warnings from real errors), silence
it by explicitly upcasting values to 64-bit integers before applying
operations, then explicitly downcasting to 32-bit again. The compiler
will optimize this out.
/* Subnet lookup cache */
/* Subnet lookup cache */
+static uint32_t wrapping_add32(uint32_t a, uint32_t b) {
+ return (uint32_t)((uint64_t)a + b);
+}
+
+static uint32_t wrapping_mul32(uint32_t a, uint32_t b) {
+ return (uint32_t)((uint64_t)a * b);
+}
+
static uint32_t hash_function_ipv4_t(const ipv4_t *p) {
/*
This basic hash works because
static uint32_t hash_function_ipv4_t(const ipv4_t *p) {
/*
This basic hash works because
#if __BYTE_ORDER == __LITTLE_ENDIAN
// 10.0.x.x/16 part
#if __BYTE_ORDER == __LITTLE_ENDIAN
// 10.0.x.x/16 part
- hash += halfwidth[1] * 0x9e370001UL;
+ hash = wrapping_add32(hash, wrapping_mul32(halfwidth[1], 0x9e370001U));
// x.x.0.[0-255] part
#if SUBNET_HASH_SIZE >= 0x10000
// x.x.0.[0-255] part
#if SUBNET_HASH_SIZE >= 0x10000
#endif // _____LP64_____
#else
// 10.0.x.x/16 part
#endif // _____LP64_____
#else
// 10.0.x.x/16 part
- hash += halfwidth[0] * 0x9e370001UL;
+ hash = wrapping_add32(hash, wrapping_mul32(halfwidth[0], 0x9e370001U));
// x.x.0.[0-255] part (ntohs is nop on big endian)
return hash ^ halfwidth[1];
// x.x.0.[0-255] part (ntohs is nop on big endian)
return hash ^ halfwidth[1];
for(int i = 0; i < 4; i++) {
hash += fullwidth[i];
for(int i = 0; i < 4; i++) {
hash += fullwidth[i];
+ hash = wrapping_mul32(hash, 0x9e370001U);
for(int i = 0; i < 3; i++) {
hash += halfwidth[i];
for(int i = 0; i < 3; i++) {
hash += halfwidth[i];
+ hash = wrapping_mul32(hash, 0x9e370001U);