【问题标题】:Segmentation fault only when executing program via a makefile仅在通过 makefile 执行程序时出现分段错误
【发布时间】:2016-03-18 04:28:15
【问题描述】:

首先是我的程序的抽象:

int main ()
{
    My_Struct1 ms1; // sizeof (My_Struct1) is 88712 B  -- L1
    My_Struct2 ms2; // sizeof (My_Struct2) is 13208 B  -- L2

    // 1. Invoke parser to fill in the two struct instances.  -- L3

    printf ("%ul, %ul\n", &ms1, &ms2) // -- **L3b** doesn't produce seg. fault.

    my_fun (&ms1, &ms2); //  -- L4, does produce seg. fault.

    return 0;
}

如果我使用 ma​​kefile 运行我的程序,那么在 L4 会出现分段错误(总是)。

如果直接从 shell (./executable) 执行我的程序,那么分段确实会发生有时但不总是。 p>

错误是:分段错误:无法访问位于 L4 的内存地址,用于 &ms1 和 &ms2。 gdb 指出了错误的类型和位置。

我的猜测是错误是由于结构的大小。 请详细说明是怎么回事。

即使将 My_Struct1 的大小减小到 8112 B 并将 My_Struct2 的大小减小到 1208 B,错误行为也是相同的。

我正在努力:

  • Ubuntu 14.04
  • Intel® Core™ i5-4200M CPU @ 2.50GHz × 4
  • 3.8 GiB 内存
  • gcc - 4.8.4

【问题讨论】:

  • "即使将 My_Struct1 的大小减小到 8112 B"。你是说“KB”吗? 8112KB 约为 8MB,这是 Linux 中堆栈大小限制的常用值。因此,除非您增加了堆栈大小限制,否则可能会溢出堆栈。
  • 您的猜测是合理的,但没有看到 My_Struct1My_Struct2my_fun 的定义(特别是它声明的本地变量;如果是堆栈大小问题,那些可能会起作用),我们不能肯定地说。
  • 等我拿到水晶球
  • 只有 8112 B,而不是 KB,因为它是 sizeof () 返回的值。 My_Struct1 是一个包含基本块数组(大小为#defined)的结构,My_Struct2 是一个符号表。它们可能太大而无法发布问题,如果您仍然建议,我会的。但是重点是语句L3b(新添加的)不会产生分段错误而是语句L4 确实;正如 gdb 所指出的那样。
  • 您可能应该创建一个最小的、完整的、可验证的示例 (stackoverflow.com/help/mcve)。我们看不到您的结构的定义或my_fun 是什么。一个小问题是,如果格式为%ul,则不应将指针传递给printfprintf 将期望unsigned longs,仅此而已)。对于打印指针,您应该改用%p

标签: c memory makefile


【解决方案1】:

首先,使用所有警告和调试信息进行编译。可能在您的Makefile 中有CFLAGS= -g -Wall -Wextra。也许您可能有时添加一些 sanitize instrumentation options,例如 -fsanitize=address-fsanitize=undefined(那么在 2016 年 3 月将您的 GCC 编译器升级到 GCC 5 可能是值得的)。您还可以想要-Wstack-usage=1000warning&-fstack-usagedeveloper option

非常 afraidundefined behavior

然后,启用core(5) 转储。可能在您的~/.bashrc 中有一些ulimit -c 100000(或任何实际的数字),然后启动一个 new 终端;与cat /proc/self/limits(Linux 特定命令,与proc(5) 相关)检查限制是否设置正确。见setrlimit(2)

运行错误的测试,例如与make test。你会得到一个core 转储。检查ls -l corefile core

最后,做一个事后调试会话。如果您的二进制文件是someprog,请运行gdb someprog core。您输入的第一个gdb 命令可能是bt

确实,您在main 中将相当大的struct 声明为局部变量可能是错误的。经验法则是将您的调用帧限制为最多几千字节(因此,在call stack 中永远不要有超过一千字节的局部变量)。所以我建议将你的大struct 放在堆中(所以适当地使用mallocfree,阅读C dynamic memory allocation)。但是 Linux 上的典型调用堆栈可以增长到几兆字节。

另外,使用valgrind 运行您的程序

顺便说一句,%p(void*) 指针的正确格式,所以您添加的 printf 应该是

printf("ms1@%p, ms2@%p\n", (void*)&ms1, (void*)&ms2);

【讨论】:

    猜你喜欢
    • 2015-03-20
    • 1970-01-01
    • 2015-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-04
    • 1970-01-01
    相关资源
    最近更新 更多