如何确定导致分段错误的代码中的错误在哪里?
我的编译器(gcc)可以显示程序中错误的位置吗?
如何确定导致分段错误的代码中的错误在哪里?
我的编译器(gcc)可以显示程序中错误的位置吗?
当前回答
以上答案都是正确的,建议回答;如果前面提到的方法都不能使用,这个答案只是作为最后的手段。
If all else fails, you can always recompile your program with various temporary debug-print statements (e.g. fprintf(stderr, "CHECKPOINT REACHED @ %s:%i\n", __FILE__, __LINE__);) sprinkled throughout what you believe to be the relevant parts of your code. Then run the program, and observe what the was last debug-print printed just before the crash occurred -- you know your program got that far, so the crash must have happened after that point. Add or remove debug-prints, recompile, and run the test again, until you have narrowed it down to a single line of code. At that point you can fix the bug and remove all of the temporary debug-prints.
这很乏味,但它的优点是几乎可以在任何地方工作——如果由于某种原因无法访问stdout或stderr,或者如果您试图修复的bug是一个竞态条件,其行为会随着程序的时间变化而变化(因为调试打印会减慢程序并改变其时间),则可能无法工作。
其他回答
这是一种粗略的方法来找到确切的线之后,有分割故障。
定义线路记录函数
# include \ < iostream > 无效日志(int line) { Std::cout << line << Std::endl; }
查找并替换log函数后的所有分号为";日志(_LINE_);“ 确保在for(;;)循环中替换为函数的分号被删除
Lucas关于核心转储的回答很好。在我的.cshrc中,我有:
alias core 'ls -lt core; echo where | gdb -core=core -silent; echo "\n"'
输入“core”显示反向跟踪。和日期戳,以确保我在看正确的文件:(。
补充:如果存在堆栈损坏错误,那么应用于核心转储的回溯通常是垃圾。在这种情况下,根据接受的答案(假设错误很容易重现),在gdb中运行程序可以得到更好的结果。同时也要注意多个进程同时转储核心;有些操作系统会将PID添加到核心文件的名称中。
您还可以使用一个核心转储,然后用gdb检查它。要获得有用的信息,还需要使用-g标志进行编译。
每当你收到这样的信息:
Segmentation fault (core dumped)
一个核心文件被写入当前目录。您可以使用命令检查它
gdb your_program core_file
该文件包含程序崩溃时内存的状态。核心转储在软件部署期间非常有用。
确保您的系统没有将核心转储文件大小设置为零。你可以通过以下方法将其设置为无限:
无限制
不过小心!核心转储可能变得巨大。
以上答案都是正确的,建议回答;如果前面提到的方法都不能使用,这个答案只是作为最后的手段。
If all else fails, you can always recompile your program with various temporary debug-print statements (e.g. fprintf(stderr, "CHECKPOINT REACHED @ %s:%i\n", __FILE__, __LINE__);) sprinkled throughout what you believe to be the relevant parts of your code. Then run the program, and observe what the was last debug-print printed just before the crash occurred -- you know your program got that far, so the crash must have happened after that point. Add or remove debug-prints, recompile, and run the test again, until you have narrowed it down to a single line of code. At that point you can fix the bug and remove all of the temporary debug-prints.
这很乏味,但它的优点是几乎可以在任何地方工作——如果由于某种原因无法访问stdout或stderr,或者如果您试图修复的bug是一个竞态条件,其行为会随着程序的时间变化而变化(因为调试打印会减慢程序并改变其时间),则可能无法工作。
如果您有一个可重复的异常,如分割错误,您可以使用像调试器这样的工具来重现错误。
我曾经找到源代码的位置,即使是不可复制的错误。它基于微软编译器工具链。但它是基于一个想法。
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文件格式支持这一点。