From f2e5e858246629ff8a2715d359700b1c45cdd253 Mon Sep 17 00:00:00 2001 From: Adrien Mazarguil Date: Fri, 13 Apr 2018 20:42:58 +0200 Subject: [PATCH] eal: fix undefined behavior in fbarray According to GCC documentation [1], the __builtin_clz() family of functions yield undefined behavior when fed a zero value. There is one instance in the fbarray code where this can occur. Clang (at least version 3.8.0-2ubuntu4) seems much more sensitive to this than GCC and yields random results when compiling optimized code, as shown below: #include int main(void) { volatile unsigned long long moo; int x; moo = 0; x = __builtin_clzll(moo); printf("%d\n", x); return 0; } $ gcc -O3 -o test test.c && ./test 63 $ clang -O3 -o test test.c && ./test 1742715559 $ clang -O0 -o test test.c && ./test 63 Even 63 can be considered an unexpected result given the number of leading zeroes should be the full width of the underlying type, i.e. 64. In practice it causes find_next_n() to sometimes return negative values interpreted as errors by caller functions, which prevents DPDK applications from starting due to inability to find free memory segments: # testpmd [...] EAL: Detected 32 lcore(s) EAL: Detected 2 NUMA nodes EAL: No free hugepages reported in hugepages-1048576kB EAL: Multi-process socket /var/run/.rte_unix EAL: eal_memalloc_alloc_seg_bulk(): couldn't find suitable memseg_list EAL: FATAL: Cannot init memory EAL: Cannot init memory PANIC in main(): Cannot init EAL 4: [./build/app/testpmd(_start+0x29) [0x462289]] 3: [/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0) [0x7f19d54fc830]] 2: [./build/app/testpmd(main+0x8a3) [0x466193]] 1: [./build/app/testpmd(__rte_panic+0xd6) [0x4efaa6]] Aborted This problem appears with commit 66cc45e293ed ("mem: replace memseg with memseg lists") however the root cause is introduced by a prior patch. [1] https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html Fixes: c44d09811b40 ("eal: add shared indexed file-backed array") Signed-off-by: Adrien Mazarguil Acked-by: Anatoly Burakov --- lib/librte_eal/common/eal_common_fbarray.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/librte_eal/common/eal_common_fbarray.c b/lib/librte_eal/common/eal_common_fbarray.c index f65875dd9e..11aa3f22a1 100644 --- a/lib/librte_eal/common/eal_common_fbarray.c +++ b/lib/librte_eal/common/eal_common_fbarray.c @@ -173,7 +173,10 @@ find_next_n(const struct rte_fbarray *arr, int start, int n, bool used) */ /* count leading zeroes on inverted mask */ - clz = __builtin_clzll(~cur_msk); + if (~cur_msk == 0) + clz = sizeof(cur_msk) * 8; + else + clz = __builtin_clzll(~cur_msk); /* if there aren't any runs at the end either, just continue */ if (clz == 0) -- 2.20.1