我一直在互联网上寻找这个问题的答案(见帖子主题)。我被问过两次这个确切的问题。一次是公司面试,一次是 friend 面试,我一辈子都找不到答案。
在没有调试器的情况下调试时,我实际上曾多次遇到此错误,并且仅使用打印语句来隔离错误。我不记得任何确切的情况,尽管我很肯定我经历过。如果有人可以提供链接或引用,或将我指向 printf() 源代码中的某些内容,这些内容可能会导致在使用 print 语句调试代码时停止发生错误,我将不胜感激。
谢谢你, 马修·霍根
我目前正在阅读提供的链接,但为了进一步对话,我发布了一些我试图调查的弱点:
好的,所以我开始尝试自己尝试回答我自己的问题,但事情对我来说仍然不是 100% 清楚。下面是 g++ 编译器使用 -S 选项输出程序集而不是可执行文件的输出。等效的 C++ 代码也在下面发布。我的目标是尝试重新创建一个简单的场景,然后根据指令尝试检测处理器级别可能发生的情况。所以让我们说在“调用 printf”汇编代码之后,我假设它是从存储在/usr/lib 或另一个 lib 目录中的库文件链接的,我试图访问一个 NULL 指针(不在代码中),或者其他一些传统上会使程序崩溃的操作形式。我假设我必须找出 printf 在指令方面做了什么才能更深入地了解这一点?
.file "assembly_test_printf.cpp"
.section .rodata
.LC0:
.string "Hello World"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
.cfi_personality 0x0,__gxx_personality_v0
pushl %ebp
.cfi_def_cfa_offset 8
movl %esp, %ebp
.cfi_offset 5, -8
.cfi_def_cfa_register 5
andl $-16, %esp
subl $32, %esp
movl $0, 28(%esp)
movl $.LC0, (%esp)
call printf
movl 28(%esp), %eax
leave
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5"
.section .note.GNU-stack,"",@progbits
等效的 C++ 代码:
#include <stdio.h>
int main ( int argc, char** argv ) {
int x = 0;
printf ("Hello World");
return x;
}
最佳答案
添加 printf()
可以改变错误行为的原因有很多。一些更常见的可能是:
- 更改执行时间(尤其是线程错误)
- 改变内存使用模式(编译器可能会改变堆栈的使用方式)
- 改变寄存器的使用方式
例如,一个未初始化的局部变量可能被分配给一个寄存器。在添加 printf()
之前,未初始化的变量被使用并得到寄存器中的垃圾值(可能是先前调用 rand()
的结果,所以它真的是不确定的)。添加 printf()
会导致在 printf()
中使用寄存器,并且 printf()
总是碰巧将该寄存器设置为 0
(或其他)。现在,您的错误程序仍然存在错误,但行为不同。也许这种行为恰好是良性的。
关于debugging - 为什么 printf() 会阻止崩溃的发生?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6079865/