但是要注意,如果这个时候我们根据缓冲区溢出发生的具体情况填充缓冲区,不但可以避免程序崩溃,还会影响到程序的执行流程,甚至会让程序去执行缓冲区里的代码 。示例运行结果为:
1请输入密码:12345
2密码错误!
3请输入密码:123456
4密码正确!
5请输入密码:1234567
6密码正确!
7请输入密码:aaaaaaa
8密码正确!
9请输入密码:0123456
10密码错误!
11请输入密码:
在示例代码中,flag 变量实际上是一个标志变量,其值将决定着程序是进入密码错误的流程(非 0)还是“密码正确”的流程(0) 。当我们输入错误的字符串1234567或者aaaaaaa,程序也都会输出“密码正确” 。但在输入0123456的时候,程序却输出“密码错误”,这究竟是为什么呢?
其实,原因很简单 。当调用 Test() 函数时,系统将会给它分配一片连续的内存空间,而变量char buffer[7]与int flag将会紧挨着进行存储,用户输入的字符串将会被复制进 buffer[7] 中 。如果这个时候,我们输入的字符串数量超过 6 个(注意,有字符串截断符也算一个),那么超出的部分将破坏掉与它紧邻着的 flag 变量的内容 。
当输入的密码不是宏定义的123456时,字符串比较将返回 1 或 -1 。我们都知道,内存中的数据按照 4 字节(DWORD)逆序存储,所以当 flag 为 1 时,在内存中存储的是0x01000000 。如果我们输入包含 7 个字符的错误密码,如aaaaaaa,那么字符串截断符 0x00 将写入 flag 变量,这样溢出数组的一个字节 0x00 将恰好把逆序存放的 flag 变量改为0x00000000 。在函数返回后,一旦 main 函数的 flag 为 0,就会输出“密码正确” 。这样,我们就用错误的密码得到了正确密码的运行效果 。
而对于0123456,因为在进行字符串的大小比较时,它小于123456,flag的值是 -1,在内存中将按照补码存放负数,所以实际存储的不是0x01000000而是0xffffffff 。那么字符串截断后符 0x00 淹没后,变成0x00ffffff,还是非 0,所以没有进入正确分支 。
【数组越界怎么处理数组越界】其实,本示例只是用一个字节淹没了邻接变量,导致程序进入密码正确的处理流程,使设计的验证功能失效 。
文章插图
尽量显式地指定数组的边界在 C 语言中,为了提高运行效率,给程序员更大的空间,为指针操作带来更多的方便,C 语言内部本身不检查数组下标表达式的取值是否在合法范围内,也不检查指向数组元素的指针是不是移出了数组的合法区域 。因此,在编程中使用数组时就必须格外谨慎,在对数组进行读写操作时都应当进行相应的检查,以免对数组的操作超过数组的边界,从而发生缓冲区溢出漏洞 。
要避免程序因数组越界所发生的错误,首先就需要从数组的边界定义开始 。尽量显式地指定数组的边界,即使它已经由初始化值列表隐式指定 。示例代码如下所示:
int a[]={1,2,3,4,5,6,7,8,9,10};
很显然,对于上面的数组 a[],虽然编译器可以根据始化值列表来计算出数组的长度 。但是,如果我们显式地指定该数组的长度,例如:
int a[10]={1,2,3,4,5,6,7,8,9,10};
它不仅使程序具有更好的可读性,并且大多数编译器在数组长度小于初始化值列表的长度时还会发生相应警告 。
当然,也可以使用宏的形式来显式指定数组的边界(实际上,这也是最常用的指定 *** ),如下面的代码所示:
#define MAX 10
…
int a[MAX]={1,2,3,4,5,6,7,8,9,10};
除此之外,在 C99 标准中,还允许我们使用单个指示符为数组的两段“分配”空间,如下面的代码所示:
int a[MAX]={1,2,3,4,5,[MAX-5]=6,7,8,9,10};
在上面的a[MAX]数组中,如果 MAX 大于 10,数组中间将用 0 值元素进行填充(填充的个数为MAX-10,并从 a[5] 开始进行 0 值填充);如果 MAX 小于 10,[MAX-5]之前的 5 个元素(1,2,3,4,5)中将有几个被[MAX-5]之后的 5 个元素(6,7,8,9,10)所覆盖,示例代码如下所示:
1#define MAX 10
2#define MAX1 15
3#define MAX2 6
4int main(void)
5{
6 int a[MAX]={1,2,3,4,5,[MAX-5]=6,7,8,9,10};
7 int b[MAX1]={1,2,3,4,5,[MAX1-5]=6,7,8,9,10};
8 int c[MAX2]={1,2,3,4,5,[MAX2-5]=6,7,8,9,10};
9 int i=0;
10 int j=0;
11 int z=0;
12 printf("a[MAX]:\n");
13 for(i=0;i<MAX;i++)
14 {
15 printf("a[%d]=%d ",i,a[i]);
16 }
17 printf("\nb[MAX1]:\n");
18 for(j=0;j<MAX1;j++)
推荐阅读
- 毛豆怎么吃,毛豆新吃法好吃到爆?
- 我想贷款10万哪里好贷 一分利息10万一年多少钱怎么算
- 在手机上怎么申请办医保卡 第一次办医保卡在哪里办
- 白皮甜瓜的种植与管理 白皮甜瓜怎么挑选
- 客一和客二的收费标准 客一客二客三怎么区分
- 迅雷下载加速教程 迅雷下载怎么加速
- 中兴双屏手机详细配置 中兴双屏手机怎么样
- 中兴axon天机体验 中兴axon天机怎么样
- 辣椒炒驴肉怎么炒好吃,熟驴肉怎么吃好吃家庭做法?
- 怎么算八字合不合?