看一下这段代码
int main()
{
int i = 1U << 31; // assume this yields INT_MIN
volatile int x;
x = -1;
x = i / x; //dividing INT_MIN by -1 is UB
return 0;
}
它在典型平台上调用未定义的行为,但“行为”与我的期望完全不同 - 它就好像它是一个无限循环。我能想到它咬人的场景。
当然undefined是未定义的,但我检查了输出程序集,它使用的是普通idiv
- 为什么它没有陷阱?为了便于比较,除以零会导致立即中止。
使用Windows 7 64位和MingW64
任何人都可以向我解释这个吗?
修改
我尝试了几个选项,结果总是一样的。
这是集会:
.file "a.c"
.def __main; .scl 2; .type 32; .endef
.section .text.startup,"x"
.p2align 4,,15
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
subq $56, %rsp
.seh_stackalloc 56
.seh_endprologue
call __main
movl $-1, 44(%rsp)
movl $-2147483648, %eax
movl 44(%rsp), %ecx
cltd
idivl %ecx
movl %eax, 44(%rsp)
xorl %eax, %eax
addq $56, %rsp
ret
.seh_endproc
.ident "GCC: (x86_64-posix-sjlj, built by strawberryperl.com project) 4.8.2"
答案 0 :(得分:4)
你观察到的无限循环可能是MinGW-w64中的一个错误。
MinGW-w64部分支持SEH,如果在调试器中运行代码,您将看到异常处理程序(名为&#34; _gnu_exception_handler&#34;的函数)由于无效的idiv而被调用。 (例如在gdb中运行程序并在_gnu_exception_handler上设置断点)
简单地说,这个异常处理程序在整数溢出的情况下所做的只是解除异常并在发生异常的位置继续执行(idiv)。然后再次执行idiv操作,导致相同的溢出触发相同的错误处理程序,并且您的CPU在idiv和异常处理程序之间来回切换。 (这是MinGW-w64的行为可以被视为错误的地方。)
如果你想深入了,你可以直接在源here中看到它。
值&#34; EXCEPTION_CONTINUE_EXECUTION&#34;由_gnu_exception_handler处理EXCEPTION_INT_OVERFLOW(整数溢出)时返回的是导致此行为的原因(当系统看到处理程序返回EXCEPTION_CONTINUE_EXECUTION时,它会跳回到生成异常的指令并尝试再次执行它。)
如果您对更多详细信息感兴趣,here是了解SEH如何在Windows上运行的良好资源。