From: Eric Blake Date: Fri, 15 Jul 2011 20:26:43 +0000 (-0600) Subject: ffs: avoid undefined behavior X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d767af3634fa49b048bf073327092be19c7c7fd1;p=pspp ffs: avoid undefined behavior * lib/ffs.c (ffs): Provide fallback for non-32-bit int. * tests/test-ffs.c (naive, main): Avoid signed shifts. Reported by Bruno Haible. Signed-off-by: Eric Blake --- diff --git a/ChangeLog b/ChangeLog index 465e8d0ac4..2a67a7e731 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2011-07-15 Eric Blake + + ffs: avoid undefined behavior + * lib/ffs.c (ffs): Provide fallback for non-32-bit int. + * tests/test-ffs.c (naive, main): Avoid signed shifts. + Reported by Bruno Haible. + 2011-07-12 Bruno Haible pthread_sigmask: Rely on module 'threadlib'. diff --git a/lib/ffs.c b/lib/ffs.c index b23210be13..b037d47a10 100644 --- a/lib/ffs.c +++ b/lib/ffs.c @@ -18,6 +18,8 @@ #include +#include + int ffs (int i) { @@ -26,13 +28,26 @@ ffs (int i) #else /* http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup gives this deBruijn constant for a branch-less computation, although - that table counted trailing zeros rather than bit position. */ - static unsigned int table[] = { - 1, 2, 29, 3, 30, 15, 25, 4, 31, 23, 21, 16, 26, 18, 5, 9, - 32, 28, 14, 24, 22, 20, 17, 8, 27, 13, 19, 7, 12, 6, 11, 10 - }; - unsigned int u = i; - unsigned int bit = u & -u; - return table[(bit * 0x077cb531U) >> 27] - !i; + that table counted trailing zeros rather than bit position. This + requires 32-bit int, we fall back to a naive algorithm on the rare + platforms where that assumption is not true. */ + if (CHAR_BIT * sizeof i == 32) + { + static unsigned int table[] = { + 1, 2, 29, 3, 30, 15, 25, 4, 31, 23, 21, 16, 26, 18, 5, 9, + 32, 28, 14, 24, 22, 20, 17, 8, 27, 13, 19, 7, 12, 6, 11, 10 + }; + unsigned int u = i; + unsigned int bit = u & -u; + return table[(bit * 0x077cb531U) >> 27] - !i; + } + else + { + unsigned int j; + for (j = 0; j < CHAR_BIT * sizeof i; j++) + if (i & (1U << j)) + return j + 1; + return 0; + } #endif } diff --git a/tests/test-ffs.c b/tests/test-ffs.c index a7c615e1cf..cfc4d0ec53 100644 --- a/tests/test-ffs.c +++ b/tests/test-ffs.c @@ -29,9 +29,9 @@ SIGNATURE_CHECK (ffs, int, (int)); static int naive (int i) { - int j; + unsigned int j; for (j = 0; j < CHAR_BIT * sizeof i; j++) - if (i & (1 << j)) + if (i & (1U << j)) return j + 1; return 0; } @@ -45,8 +45,8 @@ main (int argc, char *argv[]) ASSERT (ffs (i) == naive (i)); for (i = 0; i < CHAR_BIT * sizeof i; i++) { - ASSERT (ffs (1 << i) == naive (1 << i)); - ASSERT (ffs (1 << i) == i + 1); + ASSERT (ffs (1U << i) == naive (1U << i)); + ASSERT (ffs (1U << i) == i + 1); } return 0; }