https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82076
Bug ID: 82076 Summary: inconsistencies between sanitizer and -Wstringop-overflow Product: gcc Version: 8.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: sanitizer Assignee: unassigned at gcc dot gnu.org Reporter: msebor at gcc dot gnu.org CC: dodji at gcc dot gnu.org, dvyukov at gcc dot gnu.org, jakub at gcc dot gnu.org, kcc at gcc dot gnu.org, marxin at gcc dot gnu.org Target Milestone: --- The two options, -fsanitize=undefined, and -Wstringop-overflow, detect disjoint subsets of undefined accesses. The inconsistency is due to GCC folding some calls to functions like memset but not others. For memcpy, the folder only folds calls with constant sizes that are powers of 2. This defeats the -Wstringop-overflow warning which only considers calls to functions that weren't folded. The folded copy expressions (MEM_REFs) are then instrumented and invalid access are detected. Calls that aren't folded (i.e., those with non-constant sizes or with constant sizes that aren't a power of 2), on the other hand, are examined by -Wstringop-overflow, but they are not subject to instrumentation. This makes each option considerably less useful than it could be. The sanitizer would be improved by also instrumenting calls to the known memory and string functions. -Wstringop-overflow would benefit from delayed folding (e.g., the folding could be deferred until after the tree-ssa-strlen pass has run; that would have the nice effect of exposing optimization opportunities in the strlen pass such as those discussed in bug 81703). The example below shows the problem. The first invocation of the compiler issues a warning but the instrumented program runs to completion without detecting the out-of-bounds access. The second GCC invocation doesn't detect the read past the end but the instrumented program does. It would be an improvement if all invocations (i.e., that of the compiler and the sanitized program) detected the problem. (It's understood that -Wstringop-overflow can only detect invalid accesses when the size is either constant or in some range; similarly, the sanitizer can only detect accesses that actually take place at runtime, so neither solution can detect 100% of invalid accesses in every program.) $ cat t.c && set -x && for N in 3 4; do gcc -DN=$N -O2 -Wall -fsanitize=undefined t.c && ./a.out ; done int main (void) { char a[4]; const char *s = "1"; __builtin_memcpy (a, s, N); __builtin_printf ("%s\n", a); } + for N in 3 4 + gcc -DN=3 -O2 -Wall -fsanitize=undefined t.c t.c: In function ‘main’: t.c:5:5: warning: ‘__builtin_memcpy’ reading 3 bytes from a region of size 2 [-Wstringop-overflow=] __builtin_memcpy (a, s, N); ^~~~~~~~~~~~~~~~~~~~~~~~~~ + ./a.out 1 + for N in 3 4 + gcc -DN=4 -O2 -Wall -fsanitize=undefined t.c + ./a.out t.c:5:5: runtime error: load of address 0x000000400724 with insufficient space for an object of type 'char' 0x000000400724: note: pointer points here 01 00 02 00 31 00 74 2e 63 00 00 00 01 1b 03 3b 30 00 00 00 05 00 00 00 34 fe ff ff 7c 00 00 00 ^ 1 ++ printf '\033]0;%s on %s %s:%s\007' 'fc-25 (Twenty' x86_64 tor /opt/notnfs/msebor/build/tmp