2015-05-25 29 views
4

我知道这是一种危险的行为,我只是想弄清楚发生了什么。如果我覆盖栈上的返回地址,会发生什么?

守则如下:

#include<stdio.h> 
#include<stdlib.h> 

static int count = 0; 

void hello(void){ 
    count ++; 
    fprintf(stderr,"hello! %d\n",count); 
} 

void foo(void){ 
    void *buf[10]; 
    static int i; 

    for(i = 0 ; i < 100 ; i++){ // put enough data to overwrite the return address on stack 
     buf[i] = hello; 
    } 
} 

int main(void){ 
    int buf[1000]; 
    foo(); 
    return 0; 
} 

而结果:

…… 
hello! 83 
hello! 84 
hello! 85 
hello! 86 
hello! 87 
hello! 88 
hello! 89 
Segmentation fault (core dumped) 

为什么你好FUNC被称为89时间? 当foo返回时,pc寄存器获取hello func的地址,不是吗? 所以你好,叫做,做里面的事情。那又怎么样?程序是不是回到主要功能? 89从哪里来?我必须误解一些事情,请指出。

+0

哪个编译器/操作系统您使用的?另外,你知道buf和buf中的buf没有任何关系,对吧? – Ashalynd

+0

@Ashalynd centos 7,gcc – MMMMMCCLXXVII

+0

哪个版本的gcc? – Ashalynd

回答

9

你写的功能hello的地址的堆栈foo超出您保留的空间数量的90倍,数量为buf。当foo试图返回,它加载(之一)的hello第一额外地址(ES)到程序计数器,弹出它和“返回”到它。我之所以说“其中之一”是因为在你保留的数组的末尾和返回地址的开始之间栈中可能有一些空间。

hello假定它是由foo调用。然而,它不叫,换句话说,在中foo剩余的地址没有被压入堆栈hello返回。所以,当hello返回时,它弹出的是堆栈中的下一个东西,它又是hello的地址。

这又看起来像但从hello的函数的调用,但它实际上不是一个电话,因为它是一个回归,所以hello不停地返回到自己和从堆栈每次弹出的hello一个地址,直到它用完这些地址。

那些后跑了出来,在堆栈中的下一个字节,当你作为一个指针处理还没有被覆盖,是在其他地方的记忆,大概是没有被分配到你的进程的内存映射的东西。 hello试图回到那个,那就是程序被遗漏的时候。

+0

这就是我想知道的,谢谢 – MMMMMCCLXXVII

5

嗯,这是不确定的行为。当你进入未分配的内存什么可能发生取决于目前有什么“垃圾”。

段错误基本上意味着你走出你的程序的受保护内存(在你的情况采取了“89倍”)。您的操作系统为您辩护,并告诉您,您尝试在为该程序分配的空间之外进行编写。

(这是不是在旧操作系统和这种错误的情况下可能会导致操作系统崩溃,如果你的程序溢出到系统空间。)

1

正如那鸿说,这是不确定的行为,但这并不意味着它不能解释:

100 - 89 = 11 

的这是,恰恰,你的本地堆栈的大小(无效* [10] + int)。

试试这个(不确定的行为,可能会删除你的硬盘或修复全球经济):

#include<stdio.h> 
#include<stdlib.h> 

static int count = 0; 

static void hello(void){ 
    count ++; 
    fprintf(stderr,"hello! %d\n",count); 
} 

static void foo(void){ 
    void *buf[1]; 
    static int i; 

    for(i = 0 ; i <= 100 + 2; i++){ // put enough data to overwrite the return address on stack 
     buf[i] = hello; 
    } 
} 

static void bye(void) { 
    printf("Bye, bye...\n"); 
    exit(EXIT_SUCCESS); 
} 

int main(void){ 
    void *buf[1000]; 
    int i; 

    for (i = 0; i < 1000; ++i) { 
     buf[i] = &bye; 
    } 
    foo(); 
    return 0; 
} 
相关问题