Bug 82076 - inconsistencies between sanitizer and -Wstringop-overflow
Summary: inconsistencies between sanitizer and -Wstringop-overflow
Alias: None
Product: gcc
Classification: Unclassified
Component: sanitizer (show other bugs)
Version: 8.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
Keywords: diagnostic
Depends on:
Reported: 2017-09-01 17:32 UTC by Martin Sebor
Modified: 2018-11-06 16:32 UTC (History)
7 users (show)

See Also:
Known to work:
Known to fail:
Last reconfirmed:


Note You need to log in before you can comment on or make changes to this bug.
Description Martin Sebor 2017-09-01 17:32:01 UTC
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
+ 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
++ printf '\033]0;%s on %s %s:%s\007' 'fc-25 (Twenty' x86_64 tor /opt/notnfs/msebor/build/tmp
Comment 1 Richard Biener 2017-09-04 08:45:17 UTC
Warning / instrumenting on optimized IL is always going to run into these issues.  And no, delaying optimization is not an option because earlier passes are relying on those optimizations.
Comment 2 Jeffrey A. Law 2017-12-05 00:48:48 UTC
Yea, I think it's inevitable that sanitizer-instrumented code is likely to run afoul of various warnings.  Using the sanitizers disables certain optimizations.  Optimizations that often we rely on to get accurate warnings.

I think we should ultimately consider this NOTABUG.
Comment 3 Martin Sebor 2018-08-21 23:19:06 UTC
I think the problem in this case is that a) the sanitizers don't instrument calls to built-in functions like memcpy (the reason for the missing runtime error in the case of -DN=3), and b) -Wstringop-overflow doesn't handle MEM_REF (which is what memcpy with a small power-of-2 size is transformed into).  Both should be solvable.