Following Jeffrey Walton's example, I built and tested a gnulib testdir with CC="gcc -fsanitize=undefined". Here are the findings.
Of course, since this is based on runtime tests, not gcc warnings, it does not produce findings for modules without unit tests. lib/bitrotate.h:98:14: runtime error: left shift of 43981 by 16 places cannot be represented in type 'int' lib/bitrotate.h:109:25: runtime error: left shift of 43981 by 16 places cannot be represented in type 'int' lib/bitset/table.c:784:54: runtime error: shift exponent 87 is too large for 64-bit type 'long unsigned int' lib/des.c:552:3: runtime error: left shift of 255 by 24 places cannot be represented in type 'int' lib/des.c:437:3: runtime error: left shift of 242 by 24 places cannot be represented in type 'int' lib/des.c:625:3: runtime error: left shift of 254 by 24 places cannot be represented in type 'int' lib/xmemdup0.c:41:3: runtime error: null pointer passed as argument 2, which is declared to never be null tests/test-c-stack.c:66:13: runtime error: load of null pointer of type 'char' tests/test-canonicalize.c:74:15: runtime error: null pointer passed as argument 1, which is declared to never be null tests/test-count-leading-zeros.c:56:3: runtime error: left shift of 1804289383 by 31 places cannot be represented in type 'int' tests/test-count-leading-zeros.c:56:3: runtime error: left shift of negative value -2147483648 tests/test-count-one-bits.c:55:3: runtime error: left shift of 1804289383 by 31 places cannot be represented in type 'int' tests/test-count-one-bits.c:55:3: runtime error: left shift of negative value -2147483648 tests/test-count-trailing-zeros.c:56:3: runtime error: left shift of 1804289383 by 31 places cannot be represented in type 'int' tests/test-count-trailing-zeros.c:56:3: runtime error: left shift of negative value -2147483648 tests/test-memmem.c:84:26: runtime error: null pointer passed as argument 3, which is declared to never be null Let me fix some of them here. 2019-03-09 Bruno Haible <br...@clisp.org> Fix undefined behaviour. * lib/bitrotate.h (rotl16, rotr16, rotl8, rotr8): Case x to 'unsigned int', to avoid shift operations on 'int'. * lib/xmemdup0.c (xmemdup0): Don't invoke memcpy with a zero size. * tests/test-count-leading-zeros.c (main): Use a random number that has as many bits as TYPE, not only 2*15 or 2*31 bits. * tests/test-count-trailing-zeros.c (main): Likewise. * tests/test-count-one-bits.c (main): Likewise. * tests/test-memmem.c: Don't include "null-ptr.h". (main): Use zerosize_ptr() instead of null_ptr(). * modules/memmem-tests (Files): Remove tests/null-ptr.h. diff --git a/lib/bitrotate.h b/lib/bitrotate.h index 862331e..04b9083 100644 --- a/lib/bitrotate.h +++ b/lib/bitrotate.h @@ -95,7 +95,8 @@ rotr_sz (size_t x, int n) BITROTATE_INLINE uint16_t rotl16 (uint16_t x, int n) { - return ((x << n) | (x >> (16 - n))) & UINT16_MAX; + return (((unsigned int) x << n) | ((unsigned int) x >> (16 - n))) + & UINT16_MAX; } /* Given an unsigned 16-bit argument X, return the value corresponding @@ -106,7 +107,8 @@ rotl16 (uint16_t x, int n) BITROTATE_INLINE uint16_t rotr16 (uint16_t x, int n) { - return ((x >> n) | (x << (16 - n))) & UINT16_MAX; + return (((unsigned int) x >> n) | ((unsigned int) x << (16 - n))) + & UINT16_MAX; } /* Given an unsigned 8-bit argument X, return the value corresponding @@ -117,7 +119,7 @@ rotr16 (uint16_t x, int n) BITROTATE_INLINE uint8_t rotl8 (uint8_t x, int n) { - return ((x << n) | (x >> (8 - n))) & UINT8_MAX; + return (((unsigned int) x << n) | ((unsigned int) x >> (8 - n))) & UINT8_MAX; } /* Given an unsigned 8-bit argument X, return the value corresponding @@ -128,7 +130,7 @@ rotl8 (uint8_t x, int n) BITROTATE_INLINE uint8_t rotr8 (uint8_t x, int n) { - return ((x >> n) | (x << (8 - n))) & UINT8_MAX; + return (((unsigned int) x >> n) | ((unsigned int) x << (8 - n))) & UINT8_MAX; } _GL_INLINE_HEADER_END diff --git a/lib/xmemdup0.c b/lib/xmemdup0.c index 4f491be..57c1b59 100644 --- a/lib/xmemdup0.c +++ b/lib/xmemdup0.c @@ -38,7 +38,8 @@ char * xmemdup0 (void const *p, size_t s) { char *result = xcharalloc (s + 1); - memcpy (result, p, s); + if (s > 0) + memcpy (result, p, s); result[s] = 0; return result; } diff --git a/tests/test-count-leading-zeros.c b/tests/test-count-leading-zeros.c index 3caae7f..e94e37e 100644 --- a/tests/test-count-leading-zeros.c +++ b/tests/test-count-leading-zeros.c @@ -34,23 +34,34 @@ main (int argc, char *argv[]) { int i, j; -#define TEST_COUNT_LEADING_ZEROS(FUNC, TYPE, BITS, MAX, ONE) \ - ASSERT (FUNC (0) == BITS); \ - for (i = 0; i < BITS; i++) \ - { \ - ASSERT (FUNC (ONE << i) == BITS - i - 1); \ - for (j = 0; j < i; j++) \ - ASSERT (FUNC ((ONE << i) | (ONE << j)) == BITS - i - 1);\ - } \ - for (i = 0; i < 1000; i++) \ - { \ - TYPE value = rand () ^ (rand () << 31 << 1); \ - int count = 0; \ - for (j = 0; j < BITS; j++) \ - if (value & (ONE << j)) \ - count = BITS - j - 1; \ - ASSERT (count == FUNC (value)); \ - } \ +#define TEST_COUNT_LEADING_ZEROS(FUNC, TYPE, BITS, MAX, ONE) \ + ASSERT (FUNC (0) == BITS); \ + for (i = 0; i < BITS; i++) \ + { \ + ASSERT (FUNC (ONE << i) == BITS - i - 1); \ + for (j = 0; j < i; j++) \ + ASSERT (FUNC ((ONE << i) | (ONE << j)) == BITS - i - 1); \ + } \ + for (i = 0; i < 1000; i++) \ + { \ + /* RAND_MAX is most often 0x7fff or 0x7fffffff. */ \ + TYPE value = \ + (RAND_MAX <= 0xffff \ + ? ((TYPE) rand () >> 3) \ + ^ (((TYPE) rand () >> 3) << 12) \ + ^ (((TYPE) rand () >> 3) << 24) \ + ^ (((TYPE) rand () >> 3) << 30 << 6) \ + ^ (((TYPE) rand () >> 3) << 30 << 18) \ + ^ (((TYPE) rand () >> 3) << 30 << 30) \ + : ((TYPE) rand () >> 3) \ + ^ (((TYPE) rand () >> 3) << 22) \ + ^ (((TYPE) rand () >> 3) << 22 << 22)); \ + int count = 0; \ + for (j = 0; j < BITS; j++) \ + if (value & (ONE << j)) \ + count = BITS - j - 1; \ + ASSERT (count == FUNC (value)); \ + } \ ASSERT (FUNC (MAX) == 0); TEST_COUNT_LEADING_ZEROS (count_leading_zeros, unsigned int, diff --git a/tests/test-count-one-bits.c b/tests/test-count-one-bits.c index 109f3ee..852e1d6 100644 --- a/tests/test-count-one-bits.c +++ b/tests/test-count-one-bits.c @@ -34,22 +34,33 @@ main (int argc, char *argv[]) { int i, j; -#define TEST_COUNT_ONE_BITS(FUNC, TYPE, BITS, MAX, ONE) \ - ASSERT (FUNC (0) == 0); \ - for (i = 0; i < BITS; i++) \ - { \ - ASSERT (FUNC (ONE << i) == 1); \ - for (j = i + 1; j < BITS; j++) \ - ASSERT (FUNC ((ONE << i) | (ONE << j)) == 2); \ - } \ - for (i = 0; i < 1000; i++) \ - { \ - TYPE value = rand () ^ (rand () << 31 << 1); \ - int count = 0; \ - for (j = 0; j < BITS; j++) \ - count += (value & (ONE << j)) != 0; \ - ASSERT (count == FUNC (value)); \ - } \ +#define TEST_COUNT_ONE_BITS(FUNC, TYPE, BITS, MAX, ONE) \ + ASSERT (FUNC (0) == 0); \ + for (i = 0; i < BITS; i++) \ + { \ + ASSERT (FUNC (ONE << i) == 1); \ + for (j = i + 1; j < BITS; j++) \ + ASSERT (FUNC ((ONE << i) | (ONE << j)) == 2); \ + } \ + for (i = 0; i < 1000; i++) \ + { \ + /* RAND_MAX is most often 0x7fff or 0x7fffffff. */ \ + TYPE value = \ + (RAND_MAX <= 0xffff \ + ? ((TYPE) rand () >> 3) \ + ^ (((TYPE) rand () >> 3) << 12) \ + ^ (((TYPE) rand () >> 3) << 24) \ + ^ (((TYPE) rand () >> 3) << 30 << 6) \ + ^ (((TYPE) rand () >> 3) << 30 << 18) \ + ^ (((TYPE) rand () >> 3) << 30 << 30) \ + : ((TYPE) rand () >> 3) \ + ^ (((TYPE) rand () >> 3) << 22) \ + ^ (((TYPE) rand () >> 3) << 22 << 22)); \ + int count = 0; \ + for (j = 0; j < BITS; j++) \ + count += (value & (ONE << j)) != 0; \ + ASSERT (count == FUNC (value)); \ + } \ ASSERT (FUNC (MAX) == BITS); TEST_COUNT_ONE_BITS (count_one_bits, unsigned int, UINT_BIT, UINT_MAX, 1U); diff --git a/tests/test-count-trailing-zeros.c b/tests/test-count-trailing-zeros.c index 5a18599..04d9ddc 100644 --- a/tests/test-count-trailing-zeros.c +++ b/tests/test-count-trailing-zeros.c @@ -34,23 +34,34 @@ main (int argc, char *argv[]) { int i, j; -#define TEST_COUNT_TRAILING_ZEROS(FUNC, TYPE, BITS, MAX, ONE) \ - ASSERT (FUNC (0) == BITS); \ - for (i = 0; i < BITS; i++) \ - { \ - ASSERT (FUNC (ONE << i) == i); \ - for (j = 0; j < i; j++) \ - ASSERT (FUNC ((ONE << i) | (ONE << j)) == j); \ - } \ - for (i = 0; i < 1000; i++) \ - { \ - TYPE value = rand () ^ (rand () << 31 << 1); \ - int count = 0; \ - for (j = BITS - 1; 0 <= j; j--) \ - if (value & (ONE << j)) \ - count = j; \ - ASSERT (count == FUNC (value)); \ - } \ +#define TEST_COUNT_TRAILING_ZEROS(FUNC, TYPE, BITS, MAX, ONE) \ + ASSERT (FUNC (0) == BITS); \ + for (i = 0; i < BITS; i++) \ + { \ + ASSERT (FUNC (ONE << i) == i); \ + for (j = 0; j < i; j++) \ + ASSERT (FUNC ((ONE << i) | (ONE << j)) == j); \ + } \ + for (i = 0; i < 1000; i++) \ + { \ + /* RAND_MAX is most often 0x7fff or 0x7fffffff. */ \ + TYPE value = \ + (RAND_MAX <= 0xffff \ + ? ((TYPE) rand () >> 3) \ + ^ (((TYPE) rand () >> 3) << 12) \ + ^ (((TYPE) rand () >> 3) << 24) \ + ^ (((TYPE) rand () >> 3) << 30 << 6) \ + ^ (((TYPE) rand () >> 3) << 30 << 18) \ + ^ (((TYPE) rand () >> 3) << 30 << 30) \ + : ((TYPE) rand () >> 3) \ + ^ (((TYPE) rand () >> 3) << 22) \ + ^ (((TYPE) rand () >> 3) << 22 << 22)); \ + int count = 0; \ + for (j = BITS - 1; 0 <= j; j--) \ + if (value & (ONE << j)) \ + count = j; \ + ASSERT (count == FUNC (value)); \ + } \ ASSERT (FUNC (MAX) == 0); TEST_COUNT_TRAILING_ZEROS (count_trailing_zeros, unsigned int, diff --git a/tests/test-memmem.c b/tests/test-memmem.c index ed327e6..17e2e41 100644 --- a/tests/test-memmem.c +++ b/tests/test-memmem.c @@ -26,7 +26,6 @@ SIGNATURE_CHECK (memmem, void *, (void const *, size_t, void const *, size_t)); #include <stdlib.h> #include <unistd.h> -#include "null-ptr.h" #include "zerosize-ptr.h" #include "macros.h" @@ -81,7 +80,7 @@ main (int argc, char *argv[]) { const char input[] = "foo"; - const char *result = memmem (input, strlen (input), null_ptr (), 0); + const char *result = memmem (input, strlen (input), zerosize_ptr (), 0); ASSERT (result == input); } diff --git a/modules/memmem-tests b/modules/memmem-tests index 28c0091..250ccbf 100644 --- a/modules/memmem-tests +++ b/modules/memmem-tests @@ -1,7 +1,6 @@ Files: tests/test-memmem.c tests/signature.h -tests/null-ptr.h tests/zerosize-ptr.h tests/macros.h m4/mmap-anon.m4