淺析C語言編程中的數組越界問題
因為C語言不檢查數組越界,而數組又是我們經常用的數據結構之一,所以程序中經常會遇到數組越界的情況,并且后果輕者讀寫數據不對,重者程序crash。下面我們來分析一下數組越界的情況:
1) 堆中的數組越界
因為堆是我們自己分配的,如果越界,那么會把堆中其他空間的數據給寫掉,或讀取了其他空間的數據,這樣就會導致其他變量的數據變得不對,如果是一個指針的話,那么有可能會引起crash
2) 棧中的數組越界
因為棧是向下增長的,在進入一個函數之前,會先把參數和下一步要執(zhí)行的指令地址(通過call實現(xiàn))壓棧,在函數的入口會把ebp壓棧,并把esp賦值給ebp,在函數返回的時候,將ebp值賦給esp,pop先前棧內的上級函數棧的基地址給ebp,恢復原棧基址,然后把調用函數之前的壓入棧的指令地址pop出來(通過ret實現(xiàn))。
棧是由高往低增長的,而數組的存儲是由低位往高位存的 ,如果越界的話,會把當前函數的ebp和下一跳的指令地址覆蓋掉,如果覆蓋了當前函數的ebp,那么在恢復的時候esp就不能指向正確的地方,從而導致未可知的情況,如果下一跳的地址也被覆蓋掉,那么肯定會導致crash。
-------------------------
壓入的參數和函數指針
-------------------------
aa[4]
aa[3]
合法的數組空間 aa[2]
aa[1]
aa[0]
-------------------------
###sta.c###
#include <stdio.h> void f(int ai) { int aa[5]={1,2,3}; int i = 1; for (i=0;i<10;i++) aa[i]=i; printf("f()/n"); } void main() { f(3); printf("ok/n"); } ###sta.s### .file "sta.c" ;說明匯編的源程序 .section .rodata ;說明以下是只讀數據區(qū) .LC0: .string "f()" ;"f()" 的類型是string,地址為LC0 .text ;代碼段開始 .globl f ;f為全局可訪問 .type f, @function ; f是函數 f: pushl %ebp movl %esp, %ebp subl $40, %esp movl $0, -24(%ebp) movl $0, -20(%ebp) movl $0, -16(%ebp) movl $0, -12(%ebp) movl $0, -8(%ebp) movl $1, -24(%ebp) movl $2, -20(%ebp) movl $3, -16(%ebp) movl $1, -4(%ebp) movl $0, -4(%ebp) jmp .L2 .L3: movl -4(%ebp), %edx movl -4(%ebp), %eax movl %eax, -24(%ebp,%edx,4) addl $1, -4(%ebp) .L2: cmpl $9, -4(%ebp) jle .L3 movl $.LC0, (%esp) call puts leave ret .size f, .-f ;用以計算函數f的大小 .section .rodata .LC1: .string "ok" .text .globl main .type main, @function main: leal 4(%esp), %ecx andl $-16, %esp pushl -4(%ecx) pushl %ebp movl %esp, %ebp pushl %ecx subl $4, %esp movl $3, (%esp) call f movl $.LC1, (%esp) call puts addl $4, %esp popl %ecx popl %ebp leal -4(%ecx), %esp ret .size main, .-main .ident "GCC: (GNU) 4.1.2 20070115 (SUSE Linux)" ;說明是用什么工具編譯的 .section .note.GNU-stack,"",@progbits
從main函數開始壓入f函數的參數開始,堆棧的調用情況如下
圖1 壓入參數
圖二 通過call 命令壓入下一跳地址 IP
圖三 函數f 通過pushl %ebp 把 ebp保存起來
圖四 函數 f 通過movl %esp, %ebp讓ebp指向esp,這樣esp就可以進行修改,在函數返回的時候用ebp的值對esp進行恢復
圖五 函數 f 通過subl $40, %esp 給函數的局部變量預留空間
圖六 int數組 aa[5]占用了20個字節(jié)的空間,然后 int i占用了4個字節(jié)的空間(緊鄰著之前壓入棧的%ebp)
故,如果aa[5]進行賦值,則會把 i 的值覆蓋掉,
如果對aa[6]進行賦值,則會把 棧中的 %ebp 覆蓋掉,那么在函數 f 返回的時候則不能對ebp進行恢復,即main函數的ebp變成了我們覆蓋掉的值,程序不知道會發(fā)生什么事情,但因為我們的程序接下來沒有調用棧中的內容,故還是可以運行的。
如果對aa[7]進行賦值,則會把棧中的 %IP 覆蓋掉,在函數 f 返回的時候就不能正確地找到下一跳的地址,會crash;
您可能感興趣的文章
- 01-10深入Main函數中的參數argc,argv的使用詳解
- 01-10如何尋找數組中的第二大數
- 01-10C++大數模板(推薦)
- 01-10淺談C/C++中的static與extern關鍵字的使用詳解
- 01-10深入C/C++浮點數在內存中的存儲方式詳解
- 01-10深入探討C語言中局部變量與全局變量在內存中的存放位置
- 01-10深入解析C中的數值與
- 01-10探討:程序在內存中的分配(常量,局部變量,全局變量,程序代碼)問
- 01-10基于linux下C開發(fā)中的幾點技術經驗總結
- 01-10淺析Linux下精確控制時間的函數


閱讀排行
本欄相關
- 04-02c語言函數調用后清空內存 c語言調用
- 04-02func函數+在C語言 func函數在c語言中
- 04-02c語言的正則匹配函數 c語言正則表達
- 04-02c語言用函數寫分段 用c語言表示分段
- 04-02c語言中對數函數的表達式 c語言中對
- 04-02c語言編寫函數冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數 round c語言
- 04-02c語言分段函數怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數 c語言中怎
- 04-02c語言調用函數求fibo C語言調用函數求
隨機閱讀
- 08-05dedecms(織夢)副欄目數量限制代碼修改
- 04-02jquery與jsp,用jquery
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10delphi制作wav文件的方法
- 01-10C#中split用法實例總結
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-10SublimeText編譯C開發(fā)環(huán)境設置
- 01-11ajax實現(xiàn)頁面的局部加載
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 08-05DEDE織夢data目錄下的sessions文件夾有什