UD2 Undefined Instruction generated by Clang/LLVM

From Wikistix
Jump to navigation Jump to search

Maybe I'm just slow, but I only recently learned of the UD family of x86-64 (amd64) instructions (UD0, UD1 & UD2). These are reserved undefined instructions that generate an invalid opcode exception when executed, resulting in a SIGILL (illegal instruction signal) on Unix-like operating systems.

These can be generated by Clang/LLVM (and gcc) when compiling with flags like -fsanitize=undefined -fsanitize-trap=all.

For example, a range check is introduced when doing casts that might result in undefined behavior:

#include <cstdint>

int64_t fubar(double d) {
        return static_cast<int64_t>(d);

Results in the following sequence:

        .quad   -4332462841530417151    # double -9.2233720368547778E+18
        .quad   4890909195324358656     # double 9.2233720368547758E+18
        .globl  _Z5fubard
        .p2align        4, 0x90
        .type   _Z5fubard,@function
_Z5fubard:                              # @_Z5fubard
        .long   846595819               # 0x327606eb
        .long   .L__unnamed_1-_Z5fubard
# %bb.0:
        ucomisd .LCPI0_0(%rip), %xmm0
        jbe     .LBB0_2
# %bb.1:
        movsd   .LCPI0_1(%rip), %xmm1   # xmm1 = mem[0],zero
        ucomisd %xmm0, %xmm1
        jbe     .LBB0_2
# %bb.3:
        cvttsd2si       %xmm0, %rax

The UD2 instruction is invoked if the double is outside of the bounds of a signed int64.

See Also[edit]

Misinformation found herein copyright Paul Ripke (aka “stix”) stixpjr@gmail.com.