为啥Linux不崩溃而是输出随机字符串?

Posted

技术标签:

【中文标题】为啥Linux不崩溃而是输出随机字符串?【英文标题】:Why Linux does not crash but output an random string?为什么Linux不崩溃而是输出随机字符串? 【发布时间】:2014-12-14 14:26:25 【问题描述】:
char* getChar()

    //char* pStr = "TEST!!!";
    char str[10] = "TEST!!!";
    return str;

int main(int argc, char *argv[])

    double *XX[2];

    printf("STR is %s.\n", getChar());
    return (0);

我知道堆栈中的临时变量不应该被返回。

其实它会输出一个未确定的字符串。

除了 NULL-Pointer-Reference,Linux 什么时候崩溃?

【问题讨论】:

我不喜欢getChar 这个名字,太像标准的getchar @BasileStarynkevitch:那是你不喜欢这段代码的地方?!? 不仅,因为我也回答了! 我知道堆栈中的临时变量不应该被返回。看来你已经知道答案了。 Linux 没有崩溃,只是你的进程被终止了。 【参考方案1】:

你有一些undefined behavior。另请阅读 this answer 以了解这可能意味着什么。

如果您希望获得解释,则需要深入了解具体实施细节。 就这样吧……

这个carp.c 文件(与你的非常相似,我将getChar 重命名为carp 并包含<stdio.h>

 #include <stdio.h>
 char *carp() 
   char str[10] = "TEST!!!";
   return str;
 
 int main(int argc, char**argv)
 
   printf("STR is %s.\n", carp());
   return 0;
     

gcc -O -fverbose-asm -S carp.c编译成很好的警告

carp.c: In function 'carp':
carp.c:4:8: warning: function returns address of local variable [-Wreturn-local-addr]
      return str;
      ^

进入这个汇编代码(Debian/Sid/x86-64 上的 GCC 4.9.1)

    .text
.Ltext0:
        .globl  carp
        .type   carp, @function
carp:
.LFB11:
        .file 1 "carp.c"
        .loc 1 2 0
        .cfi_startproc
        .loc 1 5 0
        leaq    -16(%rsp), %rax #, tmp85
        ret
        .cfi_endproc
.LFE11:
        .size   carp, .-carp
        .section        .rodata.str1.1,"aMS",@progbits,1
.LC0:
        .string "STR is %s.\n"
        .text
        .globl  main
        .type   main, @function
main:
.LFB12:
        .loc 1 7 0
        .cfi_startproc
.LVL0:
        subq    $24, %rsp       #,
        .cfi_def_cfa_offset 32
        .loc 1 8 0
        movq    %rsp, %rsi      #,
.LVL1:
        movl    $.LC0, %edi     #,
.LVL2:
        movl    $0, %eax        #,
        call    printf  #
.LVL3:
        .loc 1 10 0
        movl    $0, %eax        #,
        addq    $24, %rsp       #,
        .cfi_def_cfa_offset 8
        ret
        .cfi_endproc
.LFE12:
        .size   main, .-main

如您所见,错误的 carp 函数返回的堆栈指针减去 16 个字节。 main 会打印那里发生的事情。在那个位置发生的事情可能取决于很多因素(您的环境environ(7)、用于堆栈的ASLR 等等......)。如果您有兴趣了解进入main 时的内存(和地址空间)究竟是什么,请深入了解execve(2)、ld.so(8)、编译器的crt0、内核源代码、动态链接器源代码、你的 libc 源代码、x86-64 ABI 等等……我的生命太短了,无法花很多时间来解释这一切。

顺便说一句,请注意本地 str"TEST!!!" 的初始化已经正确 optimized 被我的编译器淘汰了。

另请阅读signal(7):您的进程在许多情况下都可以终止(我不会像您那样称其为“Linux 崩溃”),例如当在virtual memory(另见this)中从其address space 中取消引用指针时,执行错误的机器代码等...

【讨论】:

你的解释太棒了。 ------- 一般Linux除了NULL-Pointer-Reference什么时候崩溃?【参考方案2】:

它没有崩溃,因为你很幸运;因为你无法知道打印出来的字符串有多长,所以你不知道它会进入内存的哪些部分。

【讨论】:

以上是关于为啥Linux不崩溃而是输出随机字符串?的主要内容,如果未能解决你的问题,请参考以下文章

编译代码后它崩溃(不明白为啥)

当我溢出分配的字符数组时,为啥我的 C 程序不会崩溃?

System.out.println(String.format("%%",0.85)); 为啥输出的不是百分数呢?而是%?

为啥持有 PARTIAL_WAKE_LOCK 会导致随机系统崩溃?

施放 pParam 后,为啥我会得到随机字符?

为啥http post响应在响应末尾添加随机字符