我的 C 程序有以下问题: 某处是堆栈溢出。尽管在没有优化和调试器符号的情况下进行编译,但程序会以以下输出退出(在 Linux 上的 gdb 内部或外部):
程序因信号 SIGSEGV、分段错误而终止。该程序不再存在。
我可以检测到这实际上是堆栈溢出的唯一方法是通过 valgrind 运行程序。有什么办法可以强制操作系统转储调用堆栈跟踪,这将帮助我找到问题?
可悲的是,gdb 也不允许我轻松进入该程序。
我的 C 程序有以下问题: 某处是堆栈溢出。尽管在没有优化和调试器符号的情况下进行编译,但程序会以以下输出退出(在 Linux 上的 gdb 内部或外部):
程序因信号 SIGSEGV、分段错误而终止。该程序不再存在。
我可以检测到这实际上是堆栈溢出的唯一方法是通过 valgrind 运行程序。有什么办法可以强制操作系统转储调用堆栈跟踪,这将帮助我找到问题?
可悲的是,gdb 也不允许我轻松进入该程序。
如果您允许系统转储核心文件,您可以使用 gdb 分析它们:
$ ulimit -c unlimited # bash sentence to allow for infinite sized cores
$ ./stack_overflow
Segmentation fault (core dumped)
$ gdb -c core stack_overflow
gdb> bt
#0 0x0000000000400570 in f ()
#1 0x0000000000400570 in f ()
#2 0x0000000000400570 in f ()
...
有时我看到一个生成错误的核心文件有一个不正确的堆栈跟踪,但在大多数情况下,bt 会产生一堆对同一方法的递归调用。
核心文件可能有一个不同的名称,其中可能包含进程 ID,它取决于当前系统中内核的默认配置,但可以使用(以 root 身份运行或使用 sudo)进行控制:
$ sysctl kernel.core_uses_pid=1
使用 GCC,您可以尝试以下操作:
-fstack-protector
发出额外的代码来检查缓冲区溢出,例如堆栈粉碎攻击。这是通过将保护变量添加到具有易受攻击对象的函数来完成的。这包括调用 alloca 的函数,以及缓冲区大于 8 字节的函数。进入函数时初始化守卫,然后在函数退出时检查。如果保护检查失败,则会打印一条错误消息并退出程序。
-fstack-protector-all
与 -fstack-protector 类似,只是所有函数都受到保护。
http://gcc.gnu.org/onlinedocs/gcc-4.3.3/gcc/Optimize-Options.html#Optimize-Options
当一个程序因 SIGSEGV 而死时,它通常会在 Unix 上转储内核。您可以将该内核加载到调试器中并检查堆栈的状态吗?