程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 淺析C說話編程中的數組越界成績

淺析C說話編程中的數組越界成績

編輯:關於C++

淺析C說話編程中的數組越界成績。本站提示廣大學習愛好者:(淺析C說話編程中的數組越界成績)文章只能為提供參考,不一定能成為您想要的結果。以下是淺析C說話編程中的數組越界成績正文


由於C說話不檢討數組越界,而數組又是我們常常用的數據構造之一,所以法式中常常會碰到數組越界的情形,而且效果輕者讀寫數據纰謬,重者法式crash。上面我們來剖析一下數組越界的情形:
1) 堆中的數組越界

由於堆是我們本身分派的,假如越界,那末會把堆中其他空間的數據給寫失落,或讀取了其他空間的數據,如許就會招致其他變量的數據變得纰謬,假如是一個指針的話,那末有能夠會惹起crash

2) 棧中的數組越界

由於棧是向下增加的,在進入一個函數之前,會先把參數和下一步要履行的指令地址(經由過程call完成)壓棧,在函數的進口會把ebp壓棧,並把esp賦值給ebp,在函數前往的時刻,將ebp值賦給esp,pop先前棧內的下級函數棧的基地址給ebp,恢回復復興棧基址,然後把挪用函數之前的壓入棧的指令地址pop出來(經由過程ret完成)。

棧是由高往低增加的,而數組的存儲是由低位往高位存的 ,假如越界的話,會把以後函數的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           ;解釋以下是只讀數據區
.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個字節的空間,然後 int i占用了4個字節的空間(緊鄰著之前壓入棧的%ebp)

故,假如aa[5]停止賦值,則會把 i 的值籠罩失落,

假如對aa[6]停止賦值,則會把 棧中的 %ebp 籠罩失落,那末在函數 f 前往的時刻則不克不及對ebp停止恢復,即main函數的ebp釀成了我們籠罩失落的值,法式不曉得會產生甚麼工作,但由於我們的法式接上去沒有挪用棧中的內容,故照樣可以運轉的。

假如對aa[7]停止賦值,則會把棧中的 %IP 籠罩失落,在函數 f 前往的時刻就不克不及准確地找到下一跳的地址,會crash;

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved