浅析C语言编程中的数组越界问题

来源:本站
导读:目前正在解读《浅析C语言编程中的数组越界问题》的相关信息,《浅析C语言编程中的数组越界问题》是由用户自行发布的知识型内容!下面请观看由(电工技术网 - www.9ddd.net)用户发布《浅析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

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函数的参数开始,堆栈的调用情况如下

浅析C语言编程中的数组越界问题

图1 压入参数

浅析C语言编程中的数组越界问题

图二 通过call 命令压入下一跳地址 IP

浅析C语言编程中的数组越界问题

图三 函数f 通过pushl %ebp 把 ebp保存起来

浅析C语言编程中的数组越界问题

图四 函数 f 通过movl %esp, %ebp让ebp指向esp,这样esp就可以进行修改,在函数返回的时候用ebp的值对esp进行恢复

浅析C语言编程中的数组越界问题

图五 函数 f 通过subl $40, %esp 给函数的局部变量预留空间

浅析C语言编程中的数组越界问题

图六 int数组 aa[5]占用了20个字节的空间,然后 int i占用了4个字节的空间(紧邻着之前压入栈的%ebp)

故,如果aa[5]进行赋值,则会把 i 的值覆盖掉,

如果对aa[6]进行赋值,则会把 栈中的 %ebp 覆盖掉,那么在函数 f 返回的时候则不能对ebp进行恢复,即main函数的ebp变成了我们覆盖掉的值,程序不知道会发生什么事情,但因为我们的程序接下来没有调用栈中的内容,故还是可以运行的。

如果对aa[7]进行赋值,则会把栈中的 %IP 覆盖掉,在函数 f 返回的时候就不能正确地找到下一跳的地址,会crash。

提醒:《浅析C语言编程中的数组越界问题》最后刷新时间 2024-03-14 00:59:42,本站为公益型个人网站,仅供个人学习和记录信息,不进行任何商业性质的盈利。如果内容、图片资源失效或内容涉及侵权,请反馈至,我们会及时处理。本站只保证内容的可读性,无法保证真实性,《浅析C语言编程中的数组越界问题》该内容的真实性请自行鉴别。