在底层来看数组访问越界!

1.什么是数组访问越界
  如果定义了一个有n个元素的数组,那么,对这n个元素(下标为0 到 n-1的元素)的访问都合法,而对这n个元素之外的空间进行访问,就是非法的,称为“越界“。又在定义数组时,数组占用的地址空间是连续的,通过指定数组下标来访问这块内存里的不同位置,当我们粗心大意,将下标取得大于等于数组的元素个数,就会访问到其它地址空间。
  但是大多数编译器都不会指出你的数组访问越界了,你的代码会顺利的通过编译。数组存储区可看成是一个缓冲区,超越数组存储区范围的写入操作称为缓冲区溢出

  缓冲区溢出是一种非常普遍、非常危险的漏洞,在各种操作系统、应用软件中广泛存在。
如历史上的莫里斯蠕虫https://zh.wikipedia.org/wiki/莫里斯蠕虫

2.代码实例

#include <stdio.h>
#include <stdlib.h>

typedef struct {
		int a[2];
		double d;
} struct_t;
double fun(int i){
		volatile struct_t s;	//类型修饰符,确保本条指令不会因编译器的优化而省略,且要求每次直接读取。 
		s.d = 3.14;
		s.a[i] = c;	/* Possibly our of bounds*/
		return s.d; /* should be 3.14*/
}
int main(int argc, char *argv[]) {
		int i = 0;
		if(argc >= 2)  //argv是参数的个数
		i = atoi(argv[1]);	/*atoi 将字符串转换成int型*/ 
		double d = fun(i);
		printf("fun(%d) --> %.10f\n",i,d);
		return 0;	
}

这段代码在Linux操作系统下运行结果如下:
在这里插入图片描述
在这个程序中,有一个结构体变量struct_t

typedef struct {
		int a[2];
		double d;
} struct_t;
	s.d = 3.14;
	s.a[i] = 1073741824;

该结构体在“内存”中的存储结构可以用如下图表示:
在这里插入图片描述
运行代码时,带的参数就是i的值,从1~6变化:

  • 当参数为1,即将a[1]赋值为1073741824,即2的30次方,用十六进制表示为0x4000 0000。
    此时double变量d的值还是3.14,用双精度浮点数表示为0 10000000000 10010001111010111000011…(尾数部分未全部列举出来)
    输出的结果是d的值:3.14

  • 当i=2,即将a[2]赋值为0x4000 0000,然而,数组a只申请了两个变量的空间,对a[2]赋值,属于越界访问了,这里实际上是将0x4000 0000写入了d的低四位,使得d的位数发生了变化,但尾数的变化对值的改变是很小的,这里输出的"d"就变成了3.1399998665

  • 当i=3,将a[3]赋值为0x4000 0000,也属于越界访问,即将d的高四位赋值为0x4000 0000,将相应的浮点数转换过来,就是2.0000006104。

当i=6,就出现了存储保护出错,提示:stack smashing detected

参考链接:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值