为什么我没有使用此代码获得分段错误? (总线错误)

时间:2012-03-07 17:45:27

标签: c++ gcc segmentation-fault

我的代码中有一个像这样的错误。

char desc[25];
char name[20];
char address[20];
sprintf (desc, "%s %s", name, address);

理想情况下,这应该是一个段错误。但是,我看到这会给出一个总线错误。 维基百科说“总线错误”是指程序试图访问未对齐的内存位置或者当您尝试访问不存在或不允许的物理(非虚拟)内存位置时。 “

上述陈述的第二部分听起来与段故障类似。所以我的问题是,你什么时候得到一个SIGBUS和一个SIGSEGV?

编辑: - 不少人提到了背景。我不确定需要什么上下文,但这是一个缓冲区溢出,位于静态类函数中,可以从许多其他类函数中调用。如果有更具体的内容我可以给予帮助,请问。

无论如何,有人评论说我应该编写更好的代码。我想提出这个问题的意思是“应用程序开发人员能否从SIGBUS和SIGSEGV中推断出任何东西?” (摘自下面的博文)

6 个答案:

答案 0 :(得分:4)

当您使用内存进行腥味时,永远不会保证分段错误。这一切都取决于很多因素(编译器如何在内存中放置程序,优化等)。

对于某个程序,C ++程序可能不合法可能并非违法行为。例如,如果你走出一个数组,操作系统并不关心。它甚至不知道阵列是什么。但是,如果您触摸不属于您的内存,关心。

答案 1 :(得分:4)

正如您可能已经意识到的,基本原因是您的未定义行为 程序。在这种情况下,它会导致硬件检测到错误, 它被OS捕获并映射到信号。确切的映射 没有真正指定(我已经看到积分除以零结果 在SIGFPE)中,但通常会在您访问时发生SIGSEGV 边界,SIGBUS表示其他访问错误,SIGILL表示非法 指令。在这种情况下,最可能的探索是你的 bounds error已覆盖堆栈上的返回地址。如果 返回地址未正确对齐,您可能会获得SIGBUS, 如果是的话,你将开始执行任何可能的事情 结果为SIGILL。 (但是执行随机字节的可能性为 代码是标准委员会在定义时所考虑的内容 “未定义的行为”。特别是在没有记忆的机器上 保护,你最终可能直接进入操作系统。)

答案 2 :(得分:1)

在这种特殊情况下,您不知道格式字符串中的垃圾类型。该垃圾可能导致将剩余的参数视为“对齐”数据类型(例如intdouble)。将未对齐区域视为对齐参数肯定会在某些系统上导致SIGBUS

答案 3 :(得分:1)

如果您尝试对未映射到您的进程的虚拟地址进行数据访问,则会发生分段错误。在大多数操作系统上,内存映射为几千字节的页面;这意味着如果您注销数组的末尾,通常不会出现错误,因为在内存页面中有其他有效数据。

总线错误表示更低级别的错误;正如你所说,错误对齐访问或缺少物理地址是两个原因。但是,第一个不会发生在这里,因为你正在处理没有对齐限制的字节;我认为第二种只能在内存完全耗尽时才会发生数据访问,这可能不会发生。

但是,如果您尝试从无效的虚拟地址执行代码,我认为您可能还会收到总线错误。这很可能是这里发生的事情 - 通过写下 local 数组的末尾,您将覆盖堆栈帧的重要部分,例如函数的返回地址。这将导致函数返回无效地址,(我认为)会给出总线错误。这是我对你在这里遇到的特定风格的未定义行为的最好猜测。

通常,您不能依赖分段错误来捕获缓冲区溢出;我所知道的最好的工具是valgrind,尽管这仍然无法捕捉到某些超限。使用字符串时避免超出的最佳方法是使用std::string,而不是假装你正在编写C语言。

答案 4 :(得分:0)

鉴于您的字符串由两个其他字符串组成,每个字符串最多包含20个字符,但您将其放入一个25个字符的字段中,这是您的第一个问题所在。你很有可能超越自己的界限。

变量desc的长度至少应为41个字符(20 + 20 + 1 [对于您插入的空间])。

使用valgrindgdb找出您遇到段错误的原因。

答案 5 :(得分:0)

char desc[25];
char name[20];
char address[20];
sprintf (desc, "%s %s", name, address);

通过查看此代码,我可以假设nameaddress每个都可以20个字符长。如果是这样,那么这并不意味着desc应该最少20+20+1个字符? (1之间的nameaddress之间的空格sprintf字符。{/ 1}}。

这可能是segfault的一个原因。还有其他原因。例如,如果name长于20个字符,该怎么办?

使用std::string时更好:

std::string name;
std::string address;
std::string desc = name + " " + address;
char const *char_desc = desc.str(); //if at all you need this