clang -O2 -E generates bad code for this code: #include <stdio.h> #include <string.h> int main(int argc, char *argv[]) { if (argc > 3) { if (strcmp(argv[1], "-4") == 0) { printf("wat\n"); } } return 0; } It seems to believe sizeof("-4") is 4 rather than 3. Might be a duplicate of 11536, not sure. Steps to reproduce: clang -O2 -E bug.c | clang -Werror -x c - Expected result: bug.o generated Actual result: dummy.c:6:2109: error: array index 3 is past the end of the array (which contains 3 elements) [-Werror,-Warray-bounds] ...> 2 && __result == 0) __result = (__s1[3] - ((__const unsigned char *) (__const char *) ("-4"))[3]); } } __result; }))) : __... ^ ~ 1 error generated. Version info: clang version 3.5.0 (http://llvm.org/git/clang.git db5f8b25707a23dd5852a35539775f7e8cf8896e) (http://llvm.org/git/llvm.git 0263debd04a3a827ac0e11968082d1c6fe0a9902) Target: x86_64-unknown-linux-gnu Thread model: posix Found candidate GCC installation: /opt/rh/devtoolset-2/root/usr/lib/gcc/x86_64-redhat-linux/4.8.2 Selected GCC installation: /opt/rh/devtoolset-2/root/usr/lib/gcc/x86_64-redhat-linux/4.8.2 Candidate multilib: .;@m64 Candidate multilib: 32;@m32 Selected multilib: .;@m64 on CentOS. Also tested with 3.4 release.
Can you please post the preprocessed code? I think this is caused by the following macro in glibc's /usr/include/bits/string2.h header: # define __strcmp_gc(s1, s2, l2) \ (__extension__ ({ __const unsigned char *__s1 = \ (__const unsigned char *) (__const char *) (s1); \ register int __result = \ __s1[0] - ((__const unsigned char *) \ (__const char *) (s2))[0]; \ if (l2 > 0 && __result == 0) \ { \ __result = (__s1[1] \ - ((__const unsigned char *) \ (__const char *) (s2))[1]); \ if (l2 > 1 && __result == 0) \ { \ __result = \ (__s1[2] - ((__const unsigned char *) \ (__const char *) (s2))[2]); \ if (l2 > 2 && __result == 0) \ __result = \ (__s1[3] \ - ((__const unsigned char *) \ (__const char *) (s2))[3]); \ } \ } \ __result; })) #endif Normally, warnings such as you are seeing are suppressed for macros, so that unused paths like the one that accesses __s1[3] are not warned about. But if you preprocess manually, and feed the result to another instance of clang, it will warn about all the possible forks of this particular if statement.
Created attachment 12713 [details] Pre-processed source.
> Can you please post the preprocessed code? I think this is caused by the > following macro in glibc's /usr/include/bits/string2.h header: Okay, that seems like the likely culprit then. I'm quite happy with this explanation. > Normally, warnings such as you are seeing are suppressed for macros, so that > unused paths like the one that accesses __s1[3] are not warned about. But > if you preprocess manually, and feed the result to another instance of > clang, it will warn about all the possible forks of this particular if > statement. Ok. For context, we ran into this trying to build our code with ccache 3.1.x, so I guess that setup isn't really compatible then, unless maybe we use CCACHE_CPP2=1
(In reply to comment #3) > > Can you please post the preprocessed code? I think this is caused by the > > following macro in glibc's /usr/include/bits/string2.h header: > > Okay, that seems like the likely culprit then. I'm quite happy with this > explanation. > > > Normally, warnings such as you are seeing are suppressed for macros, so that > > unused paths like the one that accesses __s1[3] are not warned about. But > > if you preprocess manually, and feed the result to another instance of > > clang, it will warn about all the possible forks of this particular if > > statement. > > Ok. For context, we ran into this trying to build our code with ccache > 3.1.x, so I guess that setup isn't really compatible then, unless maybe we > use CCACHE_CPP2=1 I'm not sure how to get ccache to do this, but the trick will be to run the preprocessing step with -frewrite-includes. That preserves enough information that we should still be able to suppress the diagnostic.
(In reply to comment #4) > I'm not sure how to get ccache to do this, but the trick will be to run the > preprocessing step with -frewrite-includes. That preserves enough > information that we should still be able to suppress the diagnostic. Thanks for the tip, though in practice I haven't gotten it to work yet. While adding -frewrite-includes fixes it on the original example, if we change the example to also use say 'strcasestr', the preprocessed code won't compile unless we pass -D_GNU_SOURCE on the /compile step/ $ ccache clang -frewrite-includes -D_GNU_CACHE -O2 -c dummy.c In file included from /home/eddy/.ccache/tmp/dummy.tmp.dev214.15827.i:1: In file included from <built-in>:1: dummy.c:7:8: warning: implicit declaration of function 'strcasestr' is invalid in C99 [-Wimplicit-function-declaration] if (strcasestr(argv[1], "apa")) ^ 1 warning generated. I assume this is roughly what happens in ccache: clang -O1 -D_GNU_SOURCE -E -frewrite-includes dummy.c > cache-file.i (calculate hash for cache-file.i) clang cache-file.i and here cache-file.i doesn't compile because the define was essentially lost? This however works: $ clang -O1 -E -frewrite-includes dummy.c | clang -D_GNU_SOURCE -x c -
(In reply to comment #5) > (In reply to comment #4) > > I'm not sure how to get ccache to do this, but the trick will be to run the > > preprocessing step with -frewrite-includes. That preserves enough > > information that we should still be able to suppress the diagnostic. > > Thanks for the tip, though in practice I haven't gotten it to work yet. > > While adding -frewrite-includes fixes it on the original example, if we > change the example to also use say 'strcasestr', the preprocessed code won't > compile unless we pass -D_GNU_SOURCE on the /compile step/ Yes, because -frewrite-includes doesn't expand macros, you'll need to pass the same -D flags to both the "preprocess" and the compile steps. Perhaps we should translate command-line -D flags into #define directives in the output when we're in -frewrite-includes mode. (Patches welcome...)
*** Bug 21614 has been marked as a duplicate of this bug. ***
Re-titling.
*** Bug 24025 has been marked as a duplicate of this bug. ***
Created attachment 14710 [details] minimal repro Attached is a minimal repro case. Compiling with ``clang main.c -c -O2 -Wall -Werror`` fails. Also, I noted a similar problem with a (crazy) call to tolower: map[tolower(start++)] = 1; x.c:199:46: error: expression with side effects has no effect in an unevaluated context [-Werror,-Wunevaluated-expression] map[(__extension__ ({ int __res; if (sizeof (start++) > 1) { if (__builtin_constant_p (start++)) { int __c = (start++); __res = __c < -128 || __c > 255 ? __c : (*__ctype_tolower_loc ())[__c]; } else __res = tolower (start++); } else __res = (*__ctype_tolower_loc ())[(int) (start++)]; __res; }))] = 1; This looks to be symptomatic of a general problem with macro expansion happening at the preprocessor leaving the compilation stage ignorant of where the macros came from. I'm getting a lot of spurious -Wparentheses-equality warnings from macros in the following form: #define M(X, Y) ((X) == (Y)) if (M(a, b)) // boom!
(In reply to comment #10) > Compiling with ``clang main.c -c -O2 -Wall -Werror`` fails. It works fine for me. As noted earlier in the bug, if you're using -E and feeding the result back into clang (maybe your 'clang' is a symlink to ccache and it's doing this for you?), you need to also use -frewrite-includes to prevent macro expansion from being performed in the "preprocessing" step.
*** Bug 15979 has been marked as a duplicate of this bug. ***
This is 100 % reproducible with: glibc-2.22-10.fc23.x86_64 clang-3.7.0-4.fc23.x86_64 It is no longer reproducible with: glibc-2.23.1-5.fc24.x86_64 clang-3.8.0-0.3.fc24.x86_64 I do not why, if a change happened in Glibc or Clang.
The macro definitions haven't fundamentally changed: https://sourceware.org/git/?p=glibc.git;a=blob;f=string/bits/string2.h;h=8200ef173da116589e2ff2e321984e80b1bb40e1;hb=HEAD#l797 However, maybe the "#if __GNUC_PREREQ (3, 2)" part is now chosen? In that case it would use __builtin_strcmp() and avoid all the nastiness with comparing characters directly.
*** Bug 28583 has been marked as a duplicate of this bug. ***