【问题标题】:What causes the segmention fault in this memset()?是什么导致这个 memset() 中的分段错误?
【发布时间】:2020-05-25 08:22:17
【问题描述】:

所以我知道发生了段错误,但我无法确定其背后的内部逻辑。 我相信这是因为在访问指针之前初始化指针失败。 但是在内存方面会触发这种情况。

前代码:

#include<stdio.h> 

int main(void) 
{ 
  memset((char *)0x0, 1, 100); //What causes this to seg fault
  printf("HELLO POFTUT.COM \n"); 
  return ; 
}

还有什么可以解决这个问题。 谢谢。

【问题讨论】:

  • 你希望这行代码做什么?你想在什么架构上运行它?地址 0-99 是否可以从系统上的用户空间写入?你从哪里复制的代码?
  • 写入 NULL 指针通常会导致崩溃。这是未定义的行为。你不能指望它会起作用。通常,MMU 被告知不要映射虚拟内存的第一页,因此如果您尝试对其进行读取或写入,则会出现分段错误,因为您正在写入无效(未映射)内存。
  • 定义为返回 int 的函数中的 return; 应该会出现编译器错误。
  • 'internal logic' 是您的 memset() 尝试将 100 个字节写入从地址 0 开始的地址范围。每个主要操作系统确保读取或写入地址 0 导致一个错误(默认情况下),以帮助捕获非常常见的未初始化变量错误。在内部,类 UNIX 操作系统 R/W 保护一些内存页面(Linux 通常为 4K 页面),“红色区域”,以捕获堆栈溢出,例如炸毁堆栈顶部(向低内存增长),因为与检测/查找/修复内存损坏相比,查找和修复显式运行时访问冲突(错误)要容易得多。

标签: c segmentation-fault memset


【解决方案1】:

解决方案是不要写入任意内存位置:-)

更详细地说,C11 标准规定了 * 间接运算符:

一元* 运算符表示间接。如果操作数指向一个函数,则结果是一个函数指示符;如果它指向一个对象,则结果是一个指定该对象的左值。如果操作数的类型为“类型指针”,则结果的类型为“类型”。 如果为指针分配了无效值,则一元 * 运算符的行为未定义。

该段引用脚注 102,其中指出:

通过一元 * 运算符取消引用指针的无效值包括 空指针、 与指向的对象类型不恰当对齐的地址,以及对象生命周期结束后的地址。

请注意,这不是一个详尽的列表,如果您使用0x01 而不是NULL-等价的0x00,您可能仍然会遇到麻烦。除非您知道您的实现允许访问(例如内存映射的 I/O 地址),否则您实际上应该只写入您知道存在某种描述的 C 对象的地址。

【讨论】:

  • 据我所知,C 标准实际上并不要求 NULL 为 0x00。
  • @Coffee,你说得对,它不需要底层 representation 为零,但源文件中零的整数常量表达式将被视为NULL(根据C11 6.3.2.3 Pointers /3)。
猜你喜欢
  • 1970-01-01
  • 2012-09-21
  • 1970-01-01
  • 2020-09-15
  • 2012-04-19
  • 1970-01-01
  • 2017-08-18
相关资源
最近更新 更多