修复 C++ 中的分段错误
Posted
技术标签:
【中文标题】修复 C++ 中的分段错误【英文标题】:Fixing Segmentation faults in C++ 【发布时间】:2011-04-12 18:01:38 【问题描述】:我正在为 Windows 和 Unix 编写一个跨平台的 C++ 程序。在 Window 端,代码将编译和执行没有问题。在 Unix 端,它会编译,但是当我尝试运行它时,会出现分段错误。我最初的预感是指针有问题。
什么是查找和修复分段错误的好方法?
【问题讨论】:
【参考方案1】:使用-g
编译您的应用程序,然后您将在二进制文件中包含调试符号。
使用gdb
打开gdb控制台。
使用file
并在控制台中将应用程序的二进制文件传递给它。
使用run
并传入应用程序启动所需的任何参数。
做某事导致分段错误。
在gdb
控制台中键入bt
以获取分段错误的堆栈跟踪。
【讨论】:
在CMake
的上下文中用g
编译是什么意思?
启用调试构建类型。一种方法是cmake -DCMAKE_BUILD_TYPE=Debug
。【参考方案2】:
有时崩溃本身并不是问题的真正原因——也许内存在较早的时候被破坏了,但损坏需要一段时间才能显现出来。查看valgrind,它对指针问题进行了大量检查(包括数组边界检查)。它会告诉您问题从哪里开始,而不仅仅是发生崩溃的那一行。
【讨论】:
【参考方案3】:在问题出现之前,尽量避免:
尽可能频繁地编译和运行您的代码。故障部位更容易定位。 尝试封装低级/容易出错的例程,这样您就很少需要直接使用内存(注意程序的建模) 维护一个测试套件。概述当前工作的内容,不再工作的内容等,将帮助您找出问题所在(Boost test 是一个可能的解决方案,我自己不使用它,但文档可以帮助您了解什么必须显示某种信息)。使用适当的工具进行调试。在 Unix 上:
GDB 可以告诉您程序崩溃的位置,并让您查看在什么情况下。 Valgrind 将帮助您检测许多与内存相关的错误。-fsanitize=address
标志编译来使用它。
最后我会推荐通常的东西。你的程序越是可读、可维护、清晰和整洁,就越容易调试。
【讨论】:
【参考方案4】:在 Unix 上,您可以使用 valgrind
来查找问题。它免费且功能强大。如果您想自己做,您可以重载new
和delete
运算符来设置一个配置,其中每个新对象前后都有一个带有0xDEADBEEF
的字节。然后跟踪每次迭代发生的情况。这可能无法捕获所有内容(您甚至不能保证触摸这些字节),但它过去在 Windows 平台上对我有用。
【讨论】:
嗯,这将是 4 个字节而不是 1 个......但原理很好。 我可以链接到我的non-intrusive heap debugger 吗? :-) 去吧。我们在这里都是为了帮助其他人,所以应该添加任何可以提供帮助的内容。 虽然重载new
和delete
可能非常有用,但使用-fsanitize=address
是更好的选择,因为编译器将在运行时检测问题时进行编译,并将内存自动转储到屏幕上,这使得调试方式更容易。
除了new
和delete
之外,如果你使用gcc
,你可以换行malloc
。见--wrap=symbol
。我将在发布代码中执行此操作,以便获得一些运行时诊断。【参考方案5】:
是的,指针有问题。很可能您使用的是未正确初始化的内存,但也有可能您使用双重释放或类似的方式弄乱了内存管理。
为避免将未初始化的指针作为局部变量,请尝试尽可能晚地声明它们,最好(这并不总是可能)当它们可以用有意义的值初始化时。通过检查代码,说服自己在使用它们之前它们将具有价值。如果您对此有困难,请将它们初始化为空指针常量(通常写为NULL
或0
)并检查它们。
为避免将未初始化的指针作为成员值,请确保它们在构造函数中正确初始化,并在复制构造函数和赋值运算符中正确处理。不要依赖init
函数进行内存管理,尽管您可以进行其他初始化。
如果您的类不需要复制构造函数或赋值运算符,您可以将它们声明为私有成员函数并且从不定义它们。如果显式或隐式使用它们将导致编译器错误。
在适用时使用智能指针。这里最大的好处是,如果你坚持并始终如一地使用它们,你可以完全避免写delete
,并且不会重复删除任何内容。
尽可能使用 C++ 字符串和容器类,而不是 C 样式的字符串和数组。考虑使用.at(i)
而不是[i]
,因为这将强制进行边界检查。看看你的编译器或库是否可以设置为检查[i]
的边界,至少在调试模式下是这样。分段错误可能是由缓冲区溢出导致的,将垃圾写入完美的指针。
执行这些操作将大大降低出现分段错误和其他内存问题的可能性。他们无疑无法解决所有问题,这就是为什么你应该在没有问题时不时使用 valgrind,而当你有问题时使用 valgrind 和 gdb。
【讨论】:
【参考方案6】:我不知道有什么方法可以用来解决此类问题。我认为不可能提出一个问题,因为手头的问题是您的程序的行为是未定义的(我不知道 SEGFAULT 不是由某种 UB 引起的任何情况) .
有各种各样的“方法”可以在问题出现之前避免它。一个重要的就是 RAII。
除此之外,你只需要投入你最好的精神能量。
【讨论】:
以上是关于修复 C++ 中的分段错误的主要内容,如果未能解决你的问题,请参考以下文章