数组越界如何产生段错误

2024-06-07 16:18
文章标签 数组 错误 产生 越界

本文主要是介绍数组越界如何产生段错误,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

数组越界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操作系统无法准确捕获越界访问,只能通过在虚拟地址空间的各个分离的区域之间设置虚拟地址空洞来捕获越界访问导致的异常。

这篇关于数组越界如何产生段错误的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1039675

相关文章

Windows Docker端口占用错误及解决方案总结

《WindowsDocker端口占用错误及解决方案总结》在Windows环境下使用Docker容器时,端口占用错误是开发和运维中常见且棘手的问题,本文将深入剖析该问题的成因,介绍如何通过查看端口分配... 目录引言Windows docker 端口占用错误及解决方案汇总端口冲突形成原因解析诊断当前端口情况解

Java数组初始化的五种方式

《Java数组初始化的五种方式》数组是Java中最基础且常用的数据结构之一,其初始化方式多样且各具特点,本文详细讲解Java数组初始化的五种方式,分析其适用场景、优劣势对比及注意事项,帮助避免常见陷阱... 目录1. 静态初始化:简洁但固定代码示例核心特点适用场景注意事项2. 动态初始化:灵活但需手动管理代

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

C/C++错误信息处理的常见方法及函数

《C/C++错误信息处理的常见方法及函数》C/C++是两种广泛使用的编程语言,特别是在系统编程、嵌入式开发以及高性能计算领域,:本文主要介绍C/C++错误信息处理的常见方法及函数,文中通过代码介绍... 目录前言1. errno 和 perror()示例:2. strerror()示例:3. perror(

Go标准库常见错误分析和解决办法

《Go标准库常见错误分析和解决办法》Go语言的标准库为开发者提供了丰富且高效的工具,涵盖了从网络编程到文件操作等各个方面,然而,标准库虽好,使用不当却可能适得其反,正所谓工欲善其事,必先利其器,本文将... 目录1. 使用了错误的time.Duration2. time.After导致的内存泄漏3. jsO

Python中ModuleNotFoundError: No module named ‘timm’的错误解决

《Python中ModuleNotFoundError:Nomodulenamed‘timm’的错误解决》本文主要介绍了Python中ModuleNotFoundError:Nomodulen... 目录一、引言二、错误原因分析三、解决办法1.安装timm模块2. 检查python环境3. 解决安装路径问题

如何解决mysql出现Incorrect string value for column ‘表项‘ at row 1错误问题

《如何解决mysql出现Incorrectstringvalueforcolumn‘表项‘atrow1错误问题》:本文主要介绍如何解决mysql出现Incorrectstringv... 目录mysql出现Incorrect string value for column ‘表项‘ at row 1错误报错

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法

《SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法》本文主要介绍了SpringBoot项目启动错误:找不到或无法加载主类的几种解决方法,具有一定的参考价值,感兴趣的可以了解一下... 目录方法1:更改IDE配置方法2:在Eclipse中清理项目方法3:使用Maven命令行在开发Sprin