数组越界VS段错误
1 栈中数组越界访问
1.1 示例代码
#include<stdio.h>
int main(int argc, char *argv[]){
printf("0x%x\n", (unsigned int)(-2));
int a[5] = {0};
int i;
printf("%d\n", getpid());
sleep(100);
for(i = 0;; i ++){
printf("0x%lx->%d\n", a + i, a[i]);
}
return 0;
}
1.2 测试步骤
(1)编译执行
(2)根据PID在proc下面查看进程虚拟地址空间分布
由上图得知,PID=2488,查看/proc/2488/maps文件,内容如下:
(3)程序执行结果
(4)结论
由/proc/2488/maps文件可以得知:栈stack的范围是:[0x7ffd5c0c1000, 0x7ffd5c0e2000),而由程序执行结果来看,从地址0x7ffd5c0e1ffc处取出一个32位的整数是正常的,但是当从地址0x7ffd5c0e2000处取出一个整数的时候,程序出现段错误。我们可以由文件/proc/2488/maps得到这样的结论:0x7ffd5c0e2000是虚拟地址空间[stack]和[vvar]之间留的空洞,可用于捕获越界访问异常。
2 BSS段中数组越界访问
2.1 示例代码
#include<stdio.h>
int a[5] = {0};
int main(int argc, char *argv[]){
printf("0x%x\n", (unsigned int)(-2));
int i;
printf("%d\n", getpid());
sleep(30);
for(i = 0;; i ++){
printf("0x%lx->%d\n", (unsigned long)(a + i), a[i]);
}
return 0;
}
2.2测试步骤
(1)编译执行
(2)根据PID在proc下面查看进程虚拟地址空间分布
由上图得知,PID=2645,查看/proc/2645/maps文件,内容如下:
(3)执行结果
(4)结论
由/proc/2645/maps文件可以得知:BSS段的范围是:[0x 00601000, 0x00602000),而由程序执行结果来看,从地址0x601ffc处取出一个32位的整数是正常的,但是当从地址0x00602000处取出一个整数的时候,程序出现段错误。我们可以由文件/proc/2645/maps得到这样的结论:0x00602000是虚拟地址空间BSS段和堆区之间留的空洞,可用于捕获越界访问异常。
3 堆中数组越界访问
3.1 示例代码
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char *argv[]){
printf("0x%x\n", (unsigned int)(-2));
int *a = (int *)malloc(10 * sizeof(int));
int i;
printf("%d\n", getpid());
sleep(30);
for(i = 0;; i ++){
printf("0x%lx->%d\n", (unsigned long)(a + i), a[i]);
}
return 0;
}
3.2测试步骤
(1)编译执行
(2)根据PID在proc下面查看进程虚拟地址空间分布
由上图得知,PID=2690,查看/proc/2690/maps文件,内容如下:
(3)执行结果
(4)结论
由/proc/2690/maps文件可以得知:堆的范围是:[0x012a5000, 0x012c6000),而由程序执行结果来看,从地址0x12c5ffc处取出一个32位的整数是正常的,但是当从地址0x012c6000处取出一个整数的时候,程序出现段错误。我们可以由文件/proc/2690/maps得到这样的结论:0x012c6000是虚拟地址空间堆区和mmap内存区域之间留的空洞,可用于捕获越界访问异常。
4 结论
linux操作系统无法准确捕获越界访问,只能通过在虚拟地址空间的各个分离的区域之间设置虚拟地址空洞来捕获越界访问导致的异常。