[cfe-dev] Clarification on undefined behaviour and/or how to get warned for these

David Blaikie via cfe-dev cfe-dev at lists.llvm.org
Wed Oct 7 08:41:43 PDT 2015


On Wed, Oct 7, 2015 at 3:24 AM, Eloy Durán <eloy.de.enige at gmail.com> wrote:

> Ok, interesting, I had to use
> `-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error`, so I guess
> this is just an issue with the clang being included not having the current
> UBSan yet.
>

Perhaps you don't have compiler-rt? I think the trap behavior is an
alternative when there's no runtime support (that provides the pretty
diagnostics, etc).


>
> Thanks!
>
>
> On 06 Oct 2015, at 20:20, David Blaikie <dblaikie at gmail.com> wrote:
>
> UBSan catches this
>
> $ clang++-tot undef.cpp -fsanitize=undefined
> $ ./a.out
> undef.cpp:14:8: runtime error: value inf is outside the range of
> representable values of type 'long'
>
> On Tue, Oct 6, 2015 at 5:07 AM, Eloy Durán <cfe-dev at lists.llvm.org> wrote:
>
>> Hi,
>>
>> 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.
>>
>> 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
>> https://github.com/artsy/eigen/issues/838#issuecomment-145600551, but I
>> have reduced it to the following example for ease of understanding.
>>
>> ——
>>
>> ~/tmp » cat huge-vail.c
>> // This could use the HUGE_VAL macro instead of __builtin_huge_val, but
>> I’m
>> // using the built-in one here, because that’s what the macro would use
>> under
>> // the hood.
>>
>> #include <math.h>
>> #include <assert.h>
>>
>> void succeed(double value) { assert(value > 43); }
>> void fail(long value)      { assert(value > 43); }
>>
>> int main(void)
>> {
>>   asm volatile ("movq $42, %%rdi" :);
>>
>>   // When passing to a function with the correct parameter type, this
>> works as expected.
>>   succeed(__builtin_huge_val());
>>   // When passing to a function that changes the type, the value in the
>> $rdi register is passed as-is.
>>   fail(__builtin_huge_val());
>>
>>   return 0;
>> }
>>
>> ——
>>
>> ~/tmp » clang -v
>> Apple LLVM version 7.0.0 (clang-700.0.72)
>> Target: x86_64-apple-darwin14.5.0
>> Thread model: posix
>> ~/tmp » clang huge-vail.c -o huge-vail
>> ~/tmp » ./huge-vail
>> Assertion failed: (value > 43), function fail, file huge-vail.c, line 9.
>> fish: Job 1, './huge-vail ' terminated by signal SIGABRT (Abort)
>>
>> 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’:
>>
>> define i32 @main() #0 {
>>   %1 = alloca i32, align 4
>>   store i32 0, i32* %1
>>   call void asm sideeffect "movq $$42, %rdi",
>> "~{dirflag},~{fpsr},~{flags}"() #3, !srcloc !1
>>   call void @succeed(double 0x7FF0000000000000)
>>   call void @fail(i64 undef)
>>   ret i32 0
>> }
>>
>> ——
>>
>> With an older clang this works as I would (naively) expect and how it has
>> been working for the past 3 years:
>>
>> ~/tmp »
>> /Applications/Xcode-6.4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang
>> -v
>> Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
>> Target: x86_64-apple-darwin14.5.0
>> Thread model: posix
>> ~/tmp »
>> /Applications/Xcode-6.4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang
>> huge-vail.c -o huge-vail
>> ~/tmp » ./huge-vail
>> ~/tmp » echo $status
>> 0
>>
>> The LLVM IR for that is:
>>
>> define i32 @main() #0 {
>>   %1 = alloca i32, align 4
>>   store i32 0, i32* %1
>>   call void asm sideeffect "movq $$42, %rdi",
>> "~{dirflag},~{fpsr},~{flags}"() #4, !srcloc !1
>>   call void @succeed(double 0x7FF0000000000000)
>>   call void @fail(i64 9223372036854775807)
>>   ret i32 0
>> }
>>
>> ——
>>
>> 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:
>> * What the reason is to mark it as undefined now vs the large value used
>> previously?
>> * 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:
>> http://clang.llvm.org/docs/UsersManual.html#controlling-code-generation
>>
>> Simply pointing me to a doc that explains this case is perfectly fine too!
>>
>> Kind regards,
>> Eloy Durán
>>
>>
>> _______________________________________________
>> cfe-dev mailing list
>> cfe-dev at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20151007/17a05e33/attachment.html>


More information about the cfe-dev mailing list