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

 更新时间:2015年11月17日 17:22:09   作者:wind19  
这篇文章主要介绍了浅析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函数的参数开始,堆栈的调用情况如下

20151117171954436.gif (341×267)

图1  压入参数

20151117172018789.gif (315×241)

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

20151117172103760.gif (319×250)

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

20151117172121305.gif (414×210)

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

20151117172136004.gif (407×540)

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

20151117172152902.gif (418×531)

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

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

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

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

您可能感兴趣的文章:

相关文章

  • VSCode搭建STM32开发环境的方法步骤

    VSCode搭建STM32开发环境的方法步骤

    当我们的工程文件比较大的时候,编译一次代码需要很久可能会花费到四五分钟,但是我们用vscode编写和编译的话时间就会大大缩减,本文就介绍一下VSCode搭建STM32开发环境,感兴趣的可以了解一下
    2021-07-07
  • C语言中的字符(char)详细讲解

    C语言中的字符(char)详细讲解

    本篇文章主要介绍C语言中char的知识,并附有代码实例,以便大家在学习的时候更好的理解,有需要的可以看一下
    2016-07-07
  • VS2019中CMake项目的简单使用方法

    VS2019中CMake项目的简单使用方法

    这篇文章主要介绍了VS2019中CMake项目的简单使用方法,需要的朋友可以参考下
    2020-02-02
  • C语言实现的猜数字小游戏

    C语言实现的猜数字小游戏

    这篇文章主要为大家详细介绍了C语言实现的猜数字小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-01-01
  • c++用指针交换数组的实例讲解

    c++用指针交换数组的实例讲解

    下面小编就为大家分享一篇c++用指针交换数组的实例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-11-11
  • 使用C++一步步实现俄罗斯方块

    使用C++一步步实现俄罗斯方块

    本文给大家分享的是作者在使用C++制作俄罗斯方块的时候的思路分析以及开发准备和实验原理,都是些基础的知识储备,希望大家能够喜欢,具体的代码我们下一节再分享给大家
    2017-12-12
  • 利用C/C++实现较完整贪吃蛇游戏

    利用C/C++实现较完整贪吃蛇游戏

    这篇文章主要为大家详细介绍了利用C/C++实现较完整贪吃蛇游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-03-03
  • 如何求连续几个数之和的最大值

    如何求连续几个数之和的最大值

    本篇文章是对如何求连续几个数之和的最大值进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • 基于John Carmark密码详解

    基于John Carmark密码详解

    本篇文章对John Carmark密码进行了分析介绍。需要的朋友参考下
    2013-05-05
  • 关闭显示器软件代码分享

    关闭显示器软件代码分享

    这篇文章主要介绍了使用程序如何关闭显示器的代码,需要的朋友可以参考下
    2014-01-01

最新评论