Created attachment 43915 [details] example .c file - check for invalid index optimized out of foo() only The following code, when compiled with gcc-6.4 or gcc-7.2 and -fsanitize=object-size and -O2 or higher creates unnecessary code to ensure a valid index. I'm configured for aarch64, but also see this with armv7. When indexing a 256-element array with either a uint8_t variable or an integer variable shifted right by 24 or more, gcc inserts code to ensure a valid index. That code DOES get optimized out when using an integer variable with a smaller or variable shift count and an explicit mask with 0xff. With the index clearly being an unsigned 8-bit value, the check for > 256 should not be needed. Even explicitly and'ing with 0xff does not cause the check to get optimized out when using an 8-bit datatype. lut[(*pi >> 23) & 0xff]); // good lut[(*pi >> 24) & 0xff]); // extra check lut[(*pi >> 25) & 0xff]); // extra check lut[(*pi >> 24) & 0x1]); // extra check lut[*pb] // extra check lut[*pb & 0xff]; // extra check lut[*pb >> 7]; // extra check lut[*pb >> 8]; // good - loads first element /bonus/scratch/gcc64/poky/proj/tmp/work/aarch64-poky-linux/graph/*/recipe-sysroot-native/usr/bin/aarch64-poky-linux/aarch64-poky-linux-gcc -mcpu=cortex-a53 --sysroot=/bonus/scratch/gcc64/poky/proj/tmp/work/aarch64-poky-linux/graph/*/recipe-sysroot -S -O4 -fsanitize=object-size -fno-sanitize-recover -fsanitize-undefined-trap-on-error -Wall -Wextra ~/sanitize.c gcc-7.2 assembly output follows: .arch armv8-a+crc .file "sanitize.c" .text .align 2 .p2align 4,,15 .global foo .type foo, %function foo: ldrb w1, [x0, 1] adrp x0, lut add x0, x0, :lo12:lut ldr w0, [x0, x1, lsl 2] ret .size foo, .-foo .align 2 .p2align 4,,15 .global bar .type bar, %function bar: ldrb w2, [x0, 3] adrp x1, lut add x0, x1, :lo12:lut add x3, x0, x2, lsl 2 sub x0, x3, x0 add x0, x0, 4 cmp x0, 1024 bhi .L6 .L4: add x1, x1, :lo12:lut ldr w0, [x1, x2, lsl 2] ret .L6: add x0, x3, x0 cmp x3, x0 bhi .L4 brk #1000 .size bar, .-bar .align 2 .p2align 4,,15 .global baz .type baz, %function baz: ldrb w2, [x0] adrp x1, lut add x0, x1, :lo12:lut add x3, x0, x2, uxtb 2 sub x0, x3, x0 add x0, x0, 4 cmp x0, 1024 bhi .L10 .L8: add x1, x1, :lo12:lut ldr w0, [x1, x2, lsl 2] ret .L10: add x0, x3, x0 cmp x3, x0 bhi .L8 brk #1000 .size baz, .-baz .ident "GCC: (GNU) 7.2.0" .section .note.GNU-stack,"",@progbits
This is intentional. For sanitization we don't want to heavily rely on value range propagation, because value range propagation is relying on no undefined behavior occuring in the program and the sanitizer's purpose is exactly catch undefined behavior in the program. We don't have 2 sets of value ranges where one would be extra conservative and another another one what we have right now where we could use the extra conservative for sanitization. And by using the normal value range we would just not detect many undefined behaviors.
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83356#c9 for more details. *** This bug has been marked as a duplicate of bug 83356 ***