Visual Studio在特定汇编行设置断点时触发未处理异常问题
问题复现代码
LEA ECX, Perm[3000] START: MOV EAX, N MOV EBX, EAX MOV Perm[3000 + EBX * 4], EBX FACT : DEC EBX MOV Perm[3000 + EBX * 4], EBX TEST EBX, EBX JZ FACTEND MUL EBX JMP FACT FACTEND : MOV Num, EAX
问题原因
这个问题是x86平台软件断点的实现机制和调试器的指令地址处理缺陷共同导致的,具体逻辑如下:
- x86调试器的软件断点默认通过
INT 3中断实现:调试器会把目标代码行对应指令的首字节替换为0xCC(也就是INT 3的操作码),CPU执行到这个字节时会触发调试中断,调试器收到中断后需要先把该位置的原指令字节恢复,再把程序计数器(EIP)回退到当前指令的首地址,才能让程序继续正常执行。 - 不同断点位置的表现差异:
- 断点打在第一个
MOV Perm[3000 + EBX * 4], EBX行时,调试器可以正常完成指令恢复、EIP回退操作,后续指令流没有被破坏,所以执行无异常。 - 断点打在第二个写Perm指令或者
TEST EBX, EBX行时,大概率是调试器处理中断时没有正确把EIP回退到当前指令的首地址:x86是变长指令集,这两条指令的长度都大于1字节,一旦EIP偏移错误,后续CPU会从当前指令的中间字节开始解析执行,直接触发非法指令、非法内存访问等错误。
- 断点打在第一个
还有一个低概率的触发原因:MUL EBX是32位无符号乘法指令,运算结果的低32位存在EAX、高32位存在EDX,会隐式修改EDX的值,如果调试器处理断点的过程中没有正确备份恢复EDX寄存器,也会导致后续运算结果出错。
内容的提问来源于stack exchange,提问作者JustJohn
相关产品推荐
相关产品推荐

