为什么printf()会阻止发生崩溃?

Mat*_*gan 2 debugging visual-c++

我一直在互联网上寻找这个问题的答案(见帖子主题).我被问过两次这个确切的问题.一旦接受公司的采访,一次接受朋友的采访,我找不到生活中的答案.

在没有调试器的情况下调试时,我实际上经历过多次错误,并且只使用print语句来隔离错误.我不记得任何确切的情况,虽然我很肯定我经历过它.如果任何人都可以提供链接或引用或指向printf()源中的某些内容,这可能会导致在使用print语句调试代码时停止发生错误,我将非常感谢良好的阅读.

谢谢Matthew Hoggan

我目前正在阅读所提供的链接,但为了进一步对话,我发布了一些我调查的弱尝试:

好吧,所以我已经开始玩自己尝试回答我自己的问题,但事情仍然不是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
Run Code Online (Sandbox Code Playgroud)

等价的C++代码:

#include <stdio.h>

int main ( int argc, char** argv ) {

    int x = 0;

    printf ("Hello World"); 

    return x;
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*urr 8

添加一个printf()可以改变bug行为的原因有几个.一些比较常见的可能是:

  • 改变执行的时间(特别是对于线程错误)
  • 更改内存使用模式(编译器可能会更改堆栈的使用方式)
  • 改变寄存器的使用方式

例如,可以将未初始化的局部变量分配给寄存器.在添加之前printf()使用未初始化的变量并获得寄存器中的垃圾值(可能是之前调用的结果rand(),因此它确实是不确定的).添加printf()导致寄存器被使用printf()并且printf()总是碰巧将该寄存器设置为0(或者其他).现在你的越野车程序仍然很忙,但行为不同.也许这种行为恰好是良性的.

  • 另一件事是“printf”是编译器一无所知的函数调用。因此编译器假设它可能会修改其地址可能已知的任何变量。这意味着寄存器副本在调用“printf”之前被刷新,并在调用之后重新加载。这可能会导致多线程代码中出现显着的行为差异。(它的作用就像一个记忆屏障。) (2认同)