全局數組變量和局部數組變量的訪問越界問題

有 1 小段程序如下:
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
 
int a[50];
 
int main(void)
{
        int i;
        for (i = 0; i < 300; i++)
                a[i]=i;
 
        return 0;
}

上面程序中聲明瞭 1 個全局數組變量,且有 50 個元素。但在 main() 中,故意使它訪問越界,而且越出不少,但在程序運行時並沒有出錯。然而當我們將 for 裏的 i 循環次數增大到 700 時,會產生段錯誤。

這是因爲每個進程都有自己的頁表,一般情況下每個頁爲 4K,操作系統分配頁表時,每次至少分配一個頁。像上面程序中,爲什麼在小範圍內對數組越界訪問並不會造成錯誤,這正是由於沒有越過頁邊界。但是當增大越界的範圍時,終會導致缺頁,從而發生段錯誤,因爲再往下的線性地址沒有進行映射。

再看一下局部數組變量越界的情況:
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
 
 
int main(void)
{
        int a[50];
        int i;
        for (i = 0; i < 52; i++)
                a[i]=i;
 
        return 0;
}

上面程序運行起來也沒有出錯,但是如果將 for 裏的 i 的範圍改爲 53 時,就會看到段錯誤。這是因爲,數組 a 和整數 i 都是局部變量,它們在運行時所進行的讀寫操作均在棧中。觀察反彙編代碼:

  08048394 <main>:
8048394:       55                      push   %ebp
8048395:       89 e5                   mov    %esp,%ebp
8048397:       81 ec d0 00 00 00       sub    $0xd0,%esp
804839d:       c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%ebp)
80483a4:       eb 11                   jmp    80483b7 <main+0x23>
80483a6:       8b 45 fc                mov    -0x4(%ebp),%eax
80483a9:       8b 55 fc                mov    -0x4(%ebp),%edx
80483ac:       89 94 85 34 ff ff ff    mov    %edx,-0xcc(%ebp,%eax,4)
80483b3:       83 45 fc 01             addl   $0x1,-0x4(%ebp)
80483b7:       83 7d fc 33             cmpl   $0x33,-0x4(%ebp)
80483bb:       7e e9                   jle    80483a6 <main+0x12>

x86 的棧指針類型爲滿遞減,上面的 0xd0 分配了 52x4 個字節棧空間。當我們寫超出數組 1 個元素空間大小(4 個字節)時,那麼將覆蓋的是 i 變量,這種情況可以修改上面程序證明:
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
int main(void)
{
        int a[50];
        int i;
        for ( i = 0; i < 51; i++)
                a[i] = (i+5);
 
        printf ("%d\n", i);
 
        return 0;
}

上面程序輸出 i 的值爲 56,可見 i 確實被覆蓋了。

當我們寫超出數組 2 個元素空間大小(8 個字節)時,保存在棧中的 EBP 寄存器也被覆蓋了;

當我們寫超出數組 3 個元素空間大小(3 個字節)時,main() 函數的返回地址被沖掉了,此時造成了緩衝區溢出。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章