Fix __builtin_ctz related bug
The previous commit introduces an issue related to __builtin_ctz().
The GCC doc:
Returns the number of trailing 0-bits in x, starting at the least
significant bit position. If x is 0, the result is undefined.
The behavier of __builtin_ctz() differs on x86-64 and arm, where the
x86-64 toolchain returns 32 for __builtin_ctz(0), while arm toolchain
returns -1 in such case.
So the issue could not be found by the unit test running on x86-64
system, but is caught when it's running on the real BMC which is ARM.
Tested: Verify the IPv6 netmask settings are correctly parsed on BMC.
Signed-off-by: Lei YU <yulei.sh@bytedance.com>
Change-Id: I1e803c94fe1adc9c37d4ce3e41108756963d100a
diff --git a/test/test_util.cpp b/test/test_util.cpp
index 98d1c42..4673e51 100644
--- a/test/test_util.cpp
+++ b/test/test_util.cpp
@@ -176,6 +176,10 @@
prefix = toCidr(AF_INET6, mask);
EXPECT_EQ(prefix, 126);
+ mask = "ffff:ffff:ffff:ffff::";
+ prefix = toCidr(AF_INET6, mask);
+ EXPECT_EQ(prefix, 64);
+
// Invalid Masks
mask = "ffff:0fff::";
prefix = toCidr(AF_INET6, mask);
diff --git a/util.cpp b/util.cpp
index eb3bf5f..25d2838 100644
--- a/util.cpp
+++ b/util.cpp
@@ -59,7 +59,21 @@
entry("SUBNETMASK=%s", subnetMask.c_str()));
return 0;
}
- trailingZeroes = __builtin_ctz(subnet.s6_addr32[lv]);
+
+ // The __builtin_ctz function returns -1 when the value is 0 on arm.
+ // GCC's doc specifies that:
+ // If x is 0, the result is undefined.
+ // https://gcc.gnu.org/onlinedocs/gcc-10.2.0/gcc/Other-Builtins.html
+ // So we could not rely on the undefined behavior.
+ // Handling the 0 case specifically fixes the issue.
+ if (subnet.s6_addr32[lv] == 0)
+ {
+ trailingZeroes = 32;
+ }
+ else
+ {
+ trailingZeroes = __builtin_ctz(subnet.s6_addr32[lv]);
+ }
zeroesFound |= trailingZeroes;
if (bitsSet + trailingZeroes != 32)