修复 C++ 中的分段错误
我正在为 Windows 和 Unix 编写一个跨平台 C++ 程序。在Window端,代码编译和执行没有问题。在 Unix 方面,它会编译,但是当我尝试运行它时,我遇到了分段错误。我最初的预感是指针有问题。
查找和修复分段错误的好方法是什么?
I am writing a cross-platform C++ program for Windows and Unix. On the Window side, the code will compile and execute no problem. On the Unix side, it will compile however when I try to run it, I get a segmentation fault. My initial hunch is that there is a problem with pointers.
What are good methodologies to find and fix segmentation fault errors?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
在 Unix 上,您可以使用 valgrind 来查找问题。它是免费且功能强大的。如果您想自己执行此操作,可以重载
new
和delete
运算符来设置一个配置,其中之前有 1 个字节的0xDEADBEEF
以及每个新对象之后。然后跟踪每次迭代时发生的情况。这可能无法捕获所有内容(甚至不能保证您触及这些字节),但它过去在 Windows 平台上对我有用。On Unix you can use
valgrind
to find issues. It's free and powerful. If you'd rather do it yourself you can overload thenew
anddelete
operators to set up a configuration where you have 1 byte with0xDEADBEEF
before and after each new object. Then track what happens at each iteration. This can fail to catch everything (you aren't guaranteed to even touch those bytes) but it has worked for me in the past on a Windows platform.是的,指针有问题。很可能您正在使用未正确初始化的内存,但也有可能您通过双重释放或类似操作搞乱了内存管理。
为了避免未初始化的指针作为局部变量,请尝试尽可能晚地声明它们,最好是在可以用有意义的值初始化它们时(这并不总是可能的)。通过检查代码,让自己相信它们在使用之前具有价值。如果您对此有困难,请将它们初始化为空指针常量(通常写为
NULL
或0
)并检查它们。为了避免将未初始化的指针作为成员值,请确保它们在构造函数中正确初始化,并在复制构造函数和赋值运算符中正确处理。不要依赖
init
函数进行内存管理,尽管您可以进行其他初始化。如果您的类不需要复制构造函数或赋值运算符,则可以将它们声明为私有成员函数并且永远不要定义它们。如果显式或隐式使用它们,将会导致编译器错误。
适用时使用智能指针。这里的一大优点是,如果您坚持使用它们并始终如一地使用它们,您可以完全避免编写
delete
并且不会出现双重删除。尽可能使用 C++ 字符串和容器类,而不是 C 风格的字符串和数组。考虑使用
.at(i)
而不是[i]
,因为这会强制进行边界检查。查看您的编译器或库是否可以设置为检查[i]
上的边界,至少在调试模式下如此。分段错误可能是由于缓冲区溢出在完美的指针上写入垃圾而引起的。做这些事情将大大减少分段错误和其他内存问题的可能性。毫无疑问,它们无法解决所有问题,这就是为什么当你没有问题时你应该时不时地使用 valgrind,当你遇到问题时使用 valgrind 和 gdb。
Yes, there is a problem with pointers. Very likely you're using one that's not initialized properly, but it's also possible that you're messing up your memory management with double frees or some such.
To avoid uninitialized pointers as local variables, try declaring them as late as possible, preferably (and this isn't always possible) when they can be initialized with a meaningful value. Convince yourself that they will have a value before they're being used, by examining the code. If you have difficulty with that, initialize them to a null pointer constant (usually written as
NULL
or0
) and check them.To avoid uninitialized pointers as member values, make sure they're initialized properly in the constructor, and handled properly in copy constructors and assignment operators. Don't rely on an
init
function for memory management, although you can for other initialization.If your class doesn't need copy constructors or assignment operators, you can declare them as private member functions and never define them. That will cause a compiler error if they're explicitly or implicitly used.
Use smart pointers when applicable. The big advantage here is that, if you stick to them and use them consistently, you can completely avoid writing
delete
and nothing will be double-deleted.Use C++ strings and container classes whenever possible, instead of C-style strings and arrays. Consider using
.at(i)
rather than[i]
, because that will force bounds checking. See if your compiler or library can be set to check bounds on[i]
, at least in debug mode. Segmentation faults can be caused by buffer overruns that write garbage over perfectly good pointers.Doing those things will considerably reduce the likelihood of segmentation faults and other memory problems. They will doubtless fail to fix everything, and that's why you should use valgrind now and then when you don't have problems, and valgrind and gdb when you do.
我不知道有什么方法可以用来解决这样的问题。我认为不可能提出一个,因为当前的问题是你的程序的行为是未定义的(我不知道 SEGFAULT 不是由某种 UB 引起的任何情况) 。
有各种各样的“方法”可以在问题出现之前避免它。其中一个重要的因素是 RAII。
除此之外,你只需要投入你最好的精神能量就可以了。
I don't know of any methodology to use to fix things like this. I don't think it would be possible to come up with one either for the very issue at hand is that your program's behavior is undefined (I don't know of any case when SEGFAULT hasn't been caused by some sort of UB).
There are all kinds of "methodologies" to avoid the issue before it arises. One important one is RAII.
Besides that, you just have to throw your best psychic energies at it.
使用
-g
编译您的应用程序,然后您将在二进制文件中包含调试符号。使用
gdb
打开gdb控制台。使用
file
并向其传递控制台中应用程序的二进制文件。使用
run
并传入您的应用程序启动所需的任何参数。执行某些操作会导致分段错误。
在
gdb
控制台中键入bt
以获取分段错误的堆栈跟踪。Compile your application with
-g
, then you'll have debug symbols in the binary file.Use
gdb
to open the gdb console.Use
file
and pass it your application's binary file in the console.Use
run
and pass in any arguments your application needs to start.Do something to cause a Segmentation Fault.
Type
bt
in thegdb
console to get a stack trace of the Segmentation Fault.有时崩溃本身并不是问题的真正原因——也许内存在早些时候就被破坏了,但过了一段时间损坏才显现出来。查看 valgrind,它对指针问题进行了大量检查(包括数组边界检查)。它会告诉您问题从哪里开始,而不仅仅是发生崩溃的行。
Sometimes the crash itself isn't the real cause of the problem-- perhaps the memory got smashed at an earlier point but it took a while for the corruption to show itself. Check out valgrind, which has lots of checks for pointer problems (including array bounds checking). It'll tell you where the problem starts, not just the line where the crash occurs.
在问题出现之前,尽量避免它:
使用适当的工具进行调试。在 Unix 上:
使用 GCC,您还可以使用 mudflap使用 GCC、Clang,从 10 月份开始实验性地 MSVC 您可以使用 地址/内存消毒剂。它可以检测到一些 Valgrind 检测不到的错误,并且性能损失更轻。它通过使用-fsanitize=address
标志进行编译来使用。最后我会推荐一些常见的东西。你的程序越是可读、可维护、清晰和整洁,就越容易调试。
Before the problem arises, try to avoid it as much as possible:
Use appropriate tools for debugging. On Unix:
With GCC you can also use mudflapWith GCC, Clang and since October experimentally MSVC you can use Address/Memory Sanitizer. It can detect some errors that Valgrind doesn't and the performance loss is lighter. It is used by compiling with the-fsanitize=address
flag.Finally I would recommend the usual things. The more your program is readable, maintainable, clear and neat, the easiest it will be to debug.