如何确定导致分段错误的代码中的错误在哪里?

我的编译器(gcc)可以显示程序中错误的位置吗?


当前回答

如果您有一个可重复的异常,如分割错误,您可以使用像调试器这样的工具来重现错误。

我曾经找到源代码的位置,即使是不可复制的错误。它基于微软编译器工具链。但它是基于一个想法。

Save the MAP file for each binary (DLL,EXE) before you give it to the customer. If an exception occurs, lookup the address in the MAP file and determine the function whose start address is just below the exception address. As a result you know the function, where the exception occurred. Subtract the function start address from the exception address. The result is the offset in the function. Recompile the source file containing the function with assembly listing enabled. Extract the function's assembly listing. The assembly includes the offset of each instruction in the function. Lookup the source code line, that matches the offset in the function. Evaluate the assembler code for the specific source code line. The offset points exactly the assembler instruction that caused the thrown exception. Evaluate the code of this single source code line. With a bit of experience with the compiler output you can say what caused the exception. Be aware the reason for the exception might be at a totally different location. e.g. the code dereferenced a NULL pointer, but the actual reason, why the pointer is NULL can be somewhere else.

步骤6。和7。是有益的,因为您只要求代码行。但是我建议你应该注意这一点。

我希望GCC编译器在您的平台上也有类似的环境。如果没有可用的MAP文件,请使用工具链工具来获取函数的地址。我相信ELF文件格式支持这一点。

其他回答

您还可以使用一个核心转储,然后用gdb检查它。要获得有用的信息,还需要使用-g标志进行编译。

每当你收到这样的信息:

 Segmentation fault (core dumped)

一个核心文件被写入当前目录。您可以使用命令检查它

 gdb your_program core_file

该文件包含程序崩溃时内存的状态。核心转储在软件部署期间非常有用。

确保您的系统没有将核心转储文件大小设置为零。你可以通过以下方法将其设置为无限:

无限制

不过小心!核心转储可能变得巨大。

Lucas关于核心转储的回答很好。在我的.cshrc中,我有:

alias core 'ls -lt core; echo where | gdb -core=core -silent; echo "\n"'

输入“core”显示反向跟踪。和日期戳,以确保我在看正确的文件:(。

补充:如果存在堆栈损坏错误,那么应用于核心转储的回溯通常是垃圾。在这种情况下,根据接受的答案(假设错误很容易重现),在gdb中运行程序可以得到更好的结果。同时也要注意多个进程同时转储核心;有些操作系统会将PID添加到核心文件的名称中。

如果你们中有人(像我一样!)也在寻找同样的问题,但是使用gfortran而不是gcc,那么现在编译器要强大得多,在使用调试器之前,您还可以尝试这些编译选项。对我来说,这准确地确定了发生错误的代码行,以及我访问的哪个变量越界导致了分割错误错误。

-O0 -g -Wall -fcheck=all -fbacktrace

GCC不能这样做,但GDB(调试器)肯定可以。使用-g开关编译你的程序,像这样:

gcc program.c -g

然后使用gdb:

$ gdb ./a.out
(gdb) run
<segfault happens here>
(gdb) backtrace
<offending code is shown here>

这里有一个很好的教程,可以帮助您开始使用GDB。

段错误发生的位置通常只是“导致错误”在代码中的位置的线索。给定的位置并不一定是问题所在。

如果您有一个可重复的异常,如分割错误,您可以使用像调试器这样的工具来重现错误。

我曾经找到源代码的位置,即使是不可复制的错误。它基于微软编译器工具链。但它是基于一个想法。

Save the MAP file for each binary (DLL,EXE) before you give it to the customer. If an exception occurs, lookup the address in the MAP file and determine the function whose start address is just below the exception address. As a result you know the function, where the exception occurred. Subtract the function start address from the exception address. The result is the offset in the function. Recompile the source file containing the function with assembly listing enabled. Extract the function's assembly listing. The assembly includes the offset of each instruction in the function. Lookup the source code line, that matches the offset in the function. Evaluate the assembler code for the specific source code line. The offset points exactly the assembler instruction that caused the thrown exception. Evaluate the code of this single source code line. With a bit of experience with the compiler output you can say what caused the exception. Be aware the reason for the exception might be at a totally different location. e.g. the code dereferenced a NULL pointer, but the actual reason, why the pointer is NULL can be somewhere else.

步骤6。和7。是有益的,因为您只要求代码行。但是我建议你应该注意这一点。

我希望GCC编译器在您的平台上也有类似的环境。如果没有可用的MAP文件,请使用工具链工具来获取函数的地址。我相信ELF文件格式支持这一点。