<div dir="ltr"><div>UBSan catches this<br><br>$ clang++-tot undef.cpp -fsanitize=undefined</div><div>$ ./a.out</div><div>undef.cpp:14:8: runtime error: value inf is outside the range of representable values of type 'long'</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Oct 6, 2015 at 5:07 AM, Eloy Durán <span dir="ltr"><<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word">Hi,<div><br></div><div>I’m fairly new to the world of C compiler edge cases and their undefined behaviour or what the C standards say about this particular one, but as it’s behaviour changed ‘recently’ I’d like to ask for some clarification nonetheless.</div><div><br></div><div>Since moving the build process of our iOS app to Xcode 7, an animation that was expected to run for a long time suddenly ran for a very short period. The issue turned out to be a change in how `HUGE_VAL` as an argument was converted to a `long`, which is the parameter type the function expected. The full case in question can be found here <a href="https://github.com/artsy/eigen/issues/838#issuecomment-145600551" target="_blank">https://github.com/artsy/eigen/issues/838#issuecomment-145600551</a>, but I have reduced it to the following example for ease of understanding.</div><div><br></div><div>——</div><div><br></div><div>~/tmp » cat huge-vail.c<br>// This could use the HUGE_VAL macro instead of __builtin_huge_val, but I’m<br>// using the built-in one here, because that’s what the macro would use under<br>// the hood.<br><br>#include <math.h><br>#include <assert.h><br><br>void succeed(double value) { assert(value > 43); }<br>void fail(long value) { assert(value > 43); }<br><br>int main(void)<br>{<br> asm volatile ("movq $42, %%rdi" :);<br><br> // When passing to a function with the correct parameter type, this works as expected.<br> succeed(__builtin_huge_val());<br> // When passing to a function that changes the type, the value in the $rdi register is passed as-is.<br> fail(__builtin_huge_val());<br><br> return 0;<br>}</div><div><br></div><div>——</div><div><br></div><div><div>~/tmp » clang -v</div><div>Apple LLVM version 7.0.0 (clang-700.0.72)</div><div>Target: x86_64-apple-darwin14.5.0</div><div>Thread model: posix</div><div>~/tmp » clang huge-vail.c -o huge-vail</div><div>~/tmp » ./huge-vail </div><div>Assertion failed: (value > 43), function fail, file huge-vail.c, line 9.</div><div>fish: Job 1, './huge-vail ' terminated by signal SIGABRT (Abort)</div></div><div><br></div><div>When looking at the LLVM IR generated for this file, there’s a clear difference in what gets passed to the function. Specifically the undef part, which is considered a ‘undefined variable’:</div><div><br></div><div><div>define i32 @main() #0 {</div><div> %1 = alloca i32, align 4</div><div> store i32 0, i32* %1</div><div> call void asm sideeffect "movq $$42, %rdi", "~{dirflag},~{fpsr},~{flags}"() #3, !srcloc !1</div><div> call void @succeed(double 0x7FF0000000000000)</div><div> call void @fail(i64 undef)</div><div> ret i32 0</div><div>}</div></div><div><br></div><div>——</div><div><br></div><div>With an older clang this works as I would (naively) expect and how it has been working for the past 3 years:<br><br><div>~/tmp » /Applications/Xcode-6.4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -v</div><div>Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)</div><div>Target: x86_64-apple-darwin14.5.0</div><div>Thread model: posix</div><div>~/tmp » /Applications/Xcode-6.4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang huge-vail.c -o huge-vail</div><div>~/tmp » ./huge-vail </div><div>~/tmp » echo $status</div><div>0</div><br>The LLVM IR for that is:<br><br><div>define i32 @main() #0 {</div><div> %1 = alloca i32, align 4</div><div> store i32 0, i32* %1</div><div> call void asm sideeffect "movq $$42, %rdi", "~{dirflag},~{fpsr},~{flags}"() #4, !srcloc !1</div><div> call void @succeed(double 0x7FF0000000000000)</div><div> call void @fail(i64 9223372036854775807)</div><div> ret i32 0</div><div>}</div></div><div><br></div><div>——</div><div><br></div><div>I understand that `HUGE_VAL` is actually a `double` and so the `double` to `long` conversion is probably where this behaviour comes from, but I wonder:</div><div>* What the reason is to mark it as undefined now vs the large value used previously?</div><div>* If there is a compiler flag that would have turned on checks for this undefined behaviour? I’ve tried the flags listed here in the manual, but none of those triggered a warning for me: <a href="http://clang.llvm.org/docs/UsersManual.html#controlling-code-generation" target="_blank">http://clang.llvm.org/docs/UsersManual.html#controlling-code-generation</a></div><div><br></div><div>Simply pointing me to a doc that explains this case is perfectly fine too!</div><div><br></div><div>Kind regards,</div><div>Eloy Durán</div><div><br></div></div><br>_______________________________________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@lists.llvm.org">cfe-dev@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br>
<br></blockquote></div><br></div>