Using gnulib and building it with UBSAN sanitizer
I have found a bug in quotearg.c. Passing as char value,
which modulus of 32 will be 31, const integer value will overflow.
Here is PoC which causes this error:
#include "config.h"
#include "quotearg.h"
int main(void)
{
struct quoting_options *o;
unsigned char c = 31;
int i = 1, r;
r = set_char_quoting(o, c, i);
return 0;
}
Here is the stacktrace:
UBSAN_OPTIONS=print_stacktrace=1,halt_on_error=0 ./test
quotearg.c:151:23: runtime error: left shift of 1 by 31 places
cannot be represented in type 'int'
#0 in set_char_quoting /home/as/gnulib/build/gllib/quotearg.c:151:23
#1 in main /home/as/gnulib/build/test.c:10:9
#2 in __libc_start_call_main
csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#3 in __libc_start_main csu/../csu/libc-start.c:360:3
#4 in _start (/home/as/gnulib/build/test+0x355c0)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior quotearg.c:151:23
Solution - set const value 1 to unsigned const value:
diff --git a/lib/quotearg.c b/lib/quotearg.c
index a31ea3d100..358f836f77 100644
--- a/lib/quotearg.c
+++ b/lib/quotearg.c
@@ -148,7 +148,7 @@ set_char_quoting (struct quoting_options *o, char c,
int i)
(o ? o : &default_quoting_options)->quote_these_too + uc / INT_BITS;
int shift = uc % INT_BITS;
int r = (*p >> shift) & 1;
- *p ^= ((i & 1) ^ r) << shift;
+ *p ^= ((i & 1U) ^ r) << shift;
return r;
}
To reproduce this error, we need to build gnulib static with UBSAN,
then, build PoC like this:
clang -fsanitize=undefined -g -O0 -I./gllib/ test.c -o test ./gllib/libgnu.a
set UBSAN_OPTIONS=print_stacktrace=1 and run this PoC