<div dir="ltr"><div class="gmail_extra"><br><div class="gmail_quote">2017-03-21 13:46 GMT+01:00 Manuel Rigger <span dir="ltr"><<a href="mailto:rigger.manuel@gmail.com" target="_blank">rigger.manuel@gmail.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div>Hi everyone,</div><div><br></div><div>I found that Clang -O0 performs optimizations that undermine dynamic bug-finding tools.</div><div><br></div><div>First, most bug finding tools such as ASan, Valgrind, Dr. Memory, Mudflap, Purify and Safe Sulong (on which I am working) rely on detecting errors during the execution of the program. They either insert additional checks during compile-time or during run-time which are executed when the program is running. To find errors with these tools, it is necessary that these errors stay in the program and are not optimized away.</div><div> </div><div>I think it is widely known that bugs are sometimes optimized away when compiling with optimizations turned on (-O1, -O2, -O3), and that there is a consensus that this is legit. However, I found that also bugs are optimized away while compiling with -O0. For example, I recently opened a bug report on the LLVM sanitizers Github space [1] to describe a case where ASan did not find an out-of-bounds access (see below).</div><div><br></div><div>int count[7] = {0, 0, 0, 0, 0, 0, 0};</div><div><br></div><div>int main(int argc, char** args) {</div><div>    return count[7];</div><div>}</div></div></blockquote><div><br></div><div>The LLVM IR produced by Clang still contains code for the undefined access:</div><div><br></div><div><div>@count = global [7 x i32] zeroinitializer, align 16</div><div><br></div><div>define i32 @main(i32 %argc, i8** %args) {</div><div>  ; ...</div><div>  %4 = load i32, i32* getelementptr inbounds ([7 x i32], [7 x i32]* @count, i64 1, i64 0), align 4</div><div>  ret i32 %4</div><div>}</div></div><div><br></div><div>Probably, the access is removed in the back end. Would it be reasonable to not optimize the access away when compiling with -O0?</div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div><br></div><div>Note, that Clang printed a warning and then optimized the invalid access away (which is legit since it is UB). However, note that that cases exist where no warning is printed. For example, consider the following program:</div><div><br></div><div>#include <ctype.h></div><div><br></div><div>int main() { </div><div>    isalnum(1000000);</div><div>    isalpha(1000000);</div><div>    iscntrl(1000000);</div><div>    isdigit(1000000);</div><div>    isgraph(1000000);</div><div>    islower(1000000);</div><div>    isprint(1000000);</div><div>    ispunct(1000000);</div><div>    isspace(1000000);</div><div>    isupper(1000000);</div><div>    isxdigit(1000000);</div><div>}</div><div><br></div><div>The glibc (on my system) implements the macros by calling __ctype_b_loc() which returns a lookup array that can be indexed by values between -128 and 255. Thus, I expected that, when compiling with -O0, the calls above would result in out-of-bounds accesses that (at least in theory) could be detected by bug finding tools. However, Clang optimizes the calls away, so bug finding tools have no chance to find the out-of-bounds accesses. Note, that in this example no warning is printed.</div><div><br></div><div>I think the calls are removed since __ctype_b_loc() has an __attribute__ ((__const__)). When the attribute is used, Clang -O0 also removes calls in other instances, for example in the function below. Using pure instead of const as an attribute has the same effect.</div><div><br></div><div>#include <stdio.h></div><div><br></div><div>int arr[10];</div><div><br></div><div>void test() __attribute__ ((__const__));</div><div><br></div><div>void test(int index) {</div><div>    printf("%d\n", arr[index]);</div><div>}</div><div><br></div><div>int main() {</div><div>    test(10000);</div><div>}</div><div><br></div><div>I have not yet found further cases but I feel unsettled to know that even when compiling with -O0 Clang optimizes bugs away that then cannot be found any longer by dynamic bug finding tools. The cases that I presented exhibit undefined behavior. However, according to the "Principle of least astonishment", I think that the errors should be compiled in a way so that bug finding tools can still detect them.</div><div><br></div><div>Following, I have the following questions/suggestions:</div><div>- Is it known that Clang performs optimizations that hide program bugs, even when compiling with -O0?</div><div>- Are there command line options to specify that no optimizations should be performed? Until recently, I thought that -O0 had this effect.</div><div>- In each case, I would propose to not perform optimizations at -O0 to allow dynamic bug finding tools to find such bugs, or at least offer a flag to turn off optimizations altogether.</div><div><br></div><div><br></div><div>[1] <a href="https://github.com/google/sanitizers/issues/773" target="_blank">https://github.com/google/<wbr>sanitizers/issues/773</a></div><div>[2] <a href="https://refspecs.linuxfoundation.org/LSB_2.0.1/LSB-Core/LSB-Core/baselib---ctype-b-loc.html" target="_blank">https://refspecs.<wbr>linuxfoundation.org/LSB_2.0.1/<wbr>LSB-Core/LSB-Core/baselib---<wbr>ctype-b-loc.html</a></div></div>
</blockquote></div><br></div></div>