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/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)