当我写入超过数组末尾时,为什么我的程序不会崩溃?

2023-12-11

为什么下面的代码可以在运行时没有任何崩溃的情况下工作?

而且大小完全取决于机器/平台/编译器!!。在 64 位机器上我什至可以给出最多 200 个。操作系统如何检测主函数中的分段错误?

int main(int argc, char* argv[])
{
    int arr[3];
    arr[4] = 99;
}

这个缓冲空间从哪里来?这是分配给进程的堆栈吗?


我之前为了教育目的写的一些东西......

考虑以下 c 程序:

int q[200];

main(void) {
    int i;
    for(i=0;i<2000;i++) {
        q[i]=i;
    }
}

编译并执行后,会生成一个核心转储:

$ gcc -ggdb3 segfault.c
$ ulimit -c unlimited
$ ./a.out
Segmentation fault (core dumped)

现在使用 gdb 进行事后分析:

$ gdb -q ./a.out core
Program terminated with signal 11, Segmentation fault.
[New process 7221]
#0  0x080483b4 in main () at s.c:8
8       q[i]=i;
(gdb) p i
$1 = 1008
(gdb)

呵呵,当一个人在分配的200个项目之外写入时,程序并没有出现段错误,而是在i=1008时崩溃了,为什么呢?

输入页面。

在 UNIX/Linux 上可以通过多种方式确定页面大小,一种方法是使用系统函数 sysconf(),如下所示:

#include <stdio.h>
#include <unistd.h> // sysconf(3)

int main(void) {
    printf("The page size for this system is %ld bytes.\n",
            sysconf(_SC_PAGESIZE));

    return 0;
}

给出输出:

该系统的页面大小为 4096 字节。

或者可以使用命令行实用程序 getconf,如下所示:

$ getconf PAGESIZE
4096

尸检

事实证明,段错误不是发生在 i=200 处,而是发生在 i=1008 处,让我们找出原因。启动 gdb 进行一些事后分析:

$gdb -q ./a.out core

Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
[New process 4605]
#0  0x080483b4 in main () at seg.c:6
6           q[i]=i;
(gdb) p i
$1 = 1008
(gdb) p &q
$2 = (int (*)[200]) 0x804a040
(gdb) p &q[199]
$3 = (int *) 0x804a35c

q 结束于地址 0x804a35c,或者更确切地说,q[199] 的最后一个字节位于该位置。正如我们之前看到的,页面大小为 4096 字节,机器的 32 位字大小将虚拟地址分解为 20 位页号和 12 位偏移量。

q[] 以虚拟页号结尾:

0x804a = 32842 抵消:

0x35c = 860 所以仍然有:

4096 - 864 = 3232 分配 q[] 的内存页上剩余的字节数。该空间可以容纳:

3232 / 4 = 808 整数,并且代码将其视为包含 q 在位置 200 到 1008 处的元素。

我们都知道这些元素不存在,编译器没有抱怨,硬件也没有抱怨,因为我们对该页面有写权限。仅当 i=1008 时 q[] 引用了我们没有写入权限的不同页面上的地址,虚拟内存硬件才会检测到这一点并触发段错误。

一个整数存储在 4 个字节中,这意味着该页面包含 808 (3236/4) 个额外的假元素,这意味着从 q[200]、q[201] 一直到元素 199 访问这些元素仍然是完全合法的+808=1007 (q[1007]) 而不触发段故障。访问 q[1008] 时,您将进入一个权限不同的新页面。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当我写入超过数组末尾时,为什么我的程序不会崩溃? 的相关文章

  • 如何读取扩展文件属性/文件元数据

    因此 我按照教程使用 ASP net core 将文件 上传 到本地路径 这是代码 public IActionResult About IList
  • C++ 中本地类中的静态成员变量?

    我知道我们不能宣布static本地类中的成员变量 但其原因尚不清楚 那么请问有人可以解释一下吗 另外 为什么我们不能访问非static函数内部定义的变量 内部已经定义了局部类 直接在局部类成员函数中 在下面给出的代码中 int main i
  • 启动时出现 OData v4 错误:找不到段“Whatever”的资源

    我正在构建新的 v4 服务 一切进展顺利 直到我为新模型 实体添加了新控制器 并在启动站点进行测试运行时收到此错误 控制器似乎编码正确 就像其他控制器一样 控制器 CustomersOData 中的操作 GetFeed 上的路径模板 Cus
  • 如何在 C# 中从 UNIX 纪元时间转换并考虑夏令时?

    我有一个从 unix 纪元时间转换为 NET DateTime 值的函数 public static DateTime FromUnixEpochTime double unixTime DateTime d new DateTime 19
  • 互斥体实现可以互换(独立于线程实现)

    所有互斥体实现最终都会调用相同的基本系统 硬件调用吗 这意味着它们可以互换吗 具体来说 如果我使用 gnu parallel算法 使用openmp 并且我想让他们称之为线程安全的类我可以使用boost mutex用于锁定 或者我必须编写自己
  • XamlReader.Load 在后台线程中。是否可以?

    WPF 应用程序具有从单独的文件加载用户控件的操作 使用XamlReader Load method StreamReader mysr new StreamReader pathToFile DependencyObject rootOb
  • 单元测试一起运行时失败,单独运行时通过

    所以我的单元测试遇到了一些问题 我不能只是将它们复制并粘贴到这里 但我会尽力而为 问题似乎是 如果我一项一项地运行测试 一切都会按预期进行 但如果我告诉它一起运行测试 则 1 5 将通过 TestMethod public void Obj
  • 读取文件特定行号的有效方法。 (奖励:Python 手册印刷错误)

    我有一个 100 GB 的文本文件 它是来自数据库的 BCP 转储 当我尝试导入它时BULK INSERT 我在第 219506324 行上收到一个神秘错误 在解决此问题之前 我想看看这一行 但可惜的是我最喜欢的方法 import line
  • 用于检查项目文件中的项目变量和引用路径的 api

    我正在研究一个 net application VS2010 与 x 没有 解和变量号这些解决方案中的项目数量 我需要检查项目属性 特定于一定数量的项目 是否同质 并且检查 验证构建期间的参考路径 有没有一个API是这样的吗 如果没有 我该
  • 无法在 Windows 运行时组件库的 UserControl 中创建依赖项属性

    我想在用户控件内创建数据可绑定属性 这个用户控件包含一个 Windows 运行时组件 项目 我使用下面的代码来创建属性 public MyItem CurrentItem get return MyItem GetValue Current
  • 获取 WPF 控件的所有附加事件处理程序

    我正在开发一个应用程序 在其中动态分配按钮的事件 现在的问题是 我希望获取按钮单击事件的所有事件 因为我希望删除以前的处理程序 我尝试将事件处理程序设置为 null 如下所示 Button Click null 但是我收到了一个无法分配 n
  • 如何使用 watin 中的 FileUploadDialogHandler 访问文件上传对话框

    我正在使用 IE8 和 watin 并尝试通过我的网页测试上传文件 我不能简单地使用 set 方法设置上传文件 例如 ie FileUpload Find ById someId Set C Desktop image jpg 因为上传文本
  • 批量更新 SQL Server C#

    我有一个 270k 行的数据库 带有主键mid和一个名为value 我有一个包含中值和值的文本文件 现在我想更新表格 以便将每个值分配给正确的中间值 我当前的方法是从 C 读取文本文件 并为我读取的每一行更新表中的一行 必须有更快的方法来做
  • 上下文敏感与歧义

    我对上下文敏感性和歧义如何相互影响感到困惑 我认为正确的是 歧义 歧义语法会导致使用左推导或右推导构建多个解析树 所有可能的语法都是二义性的语言是二义性语言 例如 C 是一种不明确的语言 因为 x y 总是可以表示两个不同的事物 如下所述
  • std::async 与重载函数

    可能的重复 std bind 重载解析 https stackoverflow com questions 4159487 stdbind overload resolution 考虑以下 C 示例 class A public int f
  • 为什么在setsid()之前fork()

    Why fork before setsid 守护进程 基本上 如果我想将一个进程与其控制终端分离并使其成为进程组领导者 我使用setsid 之前没有分叉就这样做是行不通的 Why 首先 setsid 将使您的进程成为进程组的领导者 但它也
  • 编译时“strlen()”有效吗?

    有时需要将字符串的长度与常量进行比较 例如 if line length gt 2 Do something 但我试图避免在代码中使用 魔法 常量 通常我使用这样的代码 if line length gt strlen Do somethi
  • Linq-to-entities,在一个查询中获取结果+行数

    我已经看到了有关此事的多个问题 但它们已经有 2 年 或更长 的历史了 所以我想知道这方面是否有任何变化 基本思想是填充网格视图并创建自定义分页 所以 我还需要结果和行数 在 SQL 中 这将类似于 SELECT COUNT id Id N
  • 如何将 Roslyn 语义模型返回的类型符号名称与 Mono.Cecil 返回的类型符号名称相匹配?

    我有以下代码 var paramDeclType m semanticModel GetTypeInfo paramDecl Type Type Where paramDeclType ToString returns System Col
  • 检查Windows控制台中是否按下了键[重复]

    这个问题在这里已经有答案了 可能的重复 C 控制台键盘事件 https stackoverflow com questions 2067893 c console keyboard events 我希望 Windows 控制台程序在按下某个

随机推荐

  • UIActivityController 在设备和模拟器上的行为不同

    我将 ActivityViewController 添加到我的应用程序中 如下所示 传递图像 UIActivityViewController avc UIActivityViewController alloc initWithActiv
  • 编写一个 C# 程序,扫描电子商务网站并从中提取产品图片+价格+描述

    我正在开发一个电子商务搜索引擎 可以让您在很多电子商务网站中搜索产品 我该如何处理这个问题 我需要一个能够扫描网站 解析 HTML 并确定网站中的哪些图像是产品图像 哪些是产品描述 哪些是产品价格的应用程序 很高兴听到任何想法 例如 提前致
  • 使用 Azure AD Graph 客户端 API 更改用户密码的权限问题

    我正在尝试在 ASP Net MVC 中创建一个页面来重置当前用户的密码 我正在使用 Azure Active Directory 进行用户身份验证 为了访问用户的 AD 信息 我使用 C Graph API 客户端 我的代码基于以下位置的
  • 在 eclipse 中创建连接 - ClassNotFoundException: com.mysql.jdbc.Driver

    我没有在代码中执行任何操作 我只是创建了一个 Eclipse 连接 但似乎无法 ping 它 连接属性 该罐子就是我所说的位置 GLASSFISH HOME domains domain1 lib ext 但我得到 java lang Cl
  • “texlive”应该有什么权限?

    多年来我一直使用 MacTeX 它安装在 usr local texlive 并且最近开始使用 Homebrew 来管理一些包 尽管还没有 TeX 由于采用了 Homebrew 我改变了所有的所有者 usr local to Me admi
  • JSF 中有浏览按钮吗?

    我需要这个来实现我创建的基于网络的应用程序的导入功能 我需要获取用户想要导入的文本文件的路径 以便获取文本文件内的数据并将其保存在数据库中 标准 JSF 中没有这样的组件 但是 有几个组件库提供文件选择 PrimeFaces
  • 我在应用德摩根定律时遇到问题...反馈?

    每次我的作业中出现这些问题时 我都会做错 有人能帮助我理解吗 还是老师的钥匙关了 我无法知道 因为我没有得到正确的答案 它只能让我知道我的答案是错误的 Assume x 7 and y 5 应用德摩根定律 选择与以下逻辑表达式等效的逻辑表达
  • 在 pandas 数据帧上使用 cumcount 并有条件增量

    考虑数据框 df pd DataFrame A 1 A 1 B 1 B 0 A 0 A 1 B 1 columns key cond 我想找到每个的累积 运行 计数 从 1 开始 key 只有当组中的前一个值有时我们才会增加cond 1 当
  • C++ GetTextExtentPoint32 没有给出正确的大小[重复]

    这个问题在这里已经有答案了 我正在尝试使用获取文本字符串的大小获取文本范围点32 我多次阅读文档并做了一些研究 据我所知 下面的代码应该给我正确的width and height的文本 vFontFamily Segoe UI font f
  • 如何将GC日志写入命名管道

    我想配置 gc 日志以便它可以写入命名管道 有谁知道是否可能 命名管道是一种文件类型 您可以像任何其他文件一样对其进行写入 Try Xloggc my named pipe 注意 您需要确保正在读取管道 否则可能会导致 JVM 停止
  • 如何判断 win32 c++ 应用程序在 CTRL-ALT-DEL 后是否失去焦点?

    I ve written a win32 App in C a game and I want to be able to know if the application has lost focus due to the user pre
  • 如何用C++在Mac上创建文件夹?

    如何让用户输入文件夹名称并在桌面上创建它 对于 Mac 这就是我到目前为止所拥有的 以及下面的额外代码 include
  • 谷歌地图设置为免费驾驶模式[关闭]

    Closed 这个问题需要调试细节 目前不接受答案 我有一个 Android 应用程序 在 xml 文件中添加了 SupportMapFragment 在片段中我将位置设置如下 mMap setMyLocationEnabled true
  • Arm 模板 Web 应用程序发布配置文件

    我正在使用 ARM 模板部署 Web 应用程序 并且需要获取发布配置文件作为输出 有没有办法做到这一点 我看到了这个 天蓝色模板输出发布配置文件内容 但无法让它发挥作用 我尝试了引用和 listKeys 但没有一个属性是发布配置文件 Tha
  • 在没有 UrlScan 的情况下删除/隐藏/禁用 Azure/IIS7 中过多的 HTTP 响应标头

    我需要删除过多的标头 主要是为了通过渗透测试 我花了时间寻找涉及运行 UrlScan 的解决方案 但这些很麻烦 因为每次启动 Azure 实例时都需要安装 UrlScan Azure 必须有一个不涉及从startup cmd 部署安装程序的
  • DataFrame 化的 zipWithIndex

    我正在尝试解决向数据集添加序列号的古老问题 我正在使用 DataFrames 似乎没有相当于的 DataFrameRDD zipWithIndex 另一方面 以下内容或多或少按照我想要的方式工作 val origDF sqlContext
  • 在 .NET 中,“for”或“foreach”哪个循环运行得更快?

    在C VB NET NET中 哪个循环运行得更快 for or foreach 自从我读到for循环比a更快foreach loop a 很久以前我假设它适用于所有集合 通用集合 所有数组等 我在谷歌上搜索并找到了一些文章 但大多数都是不确
  • 有没有办法检查 git 标签是否与相应提交的内容匹配?

    在我工作的公司中 有些项目有project info文件包含程序 库 其他内容的当前版本 实际上 当有人想要标记一个版本时 他必须首先确保project info文件 已版本化 是最新的 并且包含与他要创建的标签名称相同的版本 不用说这很容
  • Red5视频流录制中断

    最后 我创建了一个流视频录像机 Flash 应用程序及其简单的 Red5 后端 但当然 Red5 又跟我开玩笑了 大多数时候 录制的视频都已损坏 如果不随机停止 恢复就无法播放它们 挂出播放器 还有我 它为什么要这样做 我在网上查了一下 发
  • 当我写入超过数组末尾时,为什么我的程序不会崩溃?

    为什么下面的代码可以在运行时没有任何崩溃的情况下工作 而且大小完全取决于机器 平台 编译器 在 64 位机器上我什至可以给出最多 200 个 操作系统如何检测主函数中的分段错误 int main int argc char argv int