修复C ++中的分段错误


95

我正在为Windows和Unix编写跨平台的C ++程序。在窗口方面,代码将编译并执行没有问题。在Unix方面,它将编译,但是当我尝试运行它时,出现了分段错误。我最初的预感是指针存在问题。

有什么好的方法来查找和修复分段错误?

Answers:


134
  1. 使用编译应用程序-g,然后在二进制文件中就有调试符号。

  2. 使用gdb打开GDB控制台。

  3. file在控制台中使用并传递您的应用程序的二进制文件。

  4. 使用run并传入您的应用程序需要启动的任何参数。

  5. 采取措施导致细分错误

  6. btgdb控制台中键入以获取Segmentation Fault的堆栈跟踪。


g在的上下文中进行编译意味着什么CMake
Schütze

2
启用调试构建类型。一种方法是cmake -DCMAKE_BUILD_TYPE=Debug
AntoninDécimo19年

36

有时崩溃本身并不是问题的真正原因-也许内存在更早的时候就被破坏了,但是花了一段时间才显示出错误。签出valgrind,它对指针问题进行了很多检查(包括数组范围检查)。它会告诉您问题何处开始,而不仅仅是崩溃发生的那一行。


19

在出现问题之前,请尝试尽可能避免它:

  • 尽可能多地编译和运行代码。查找故障部分将更加容易。
  • 尝试封装低级/容易出错的例程,这样您几乎不需要直接使用内存(请注意程序的建模)
  • 维持测试套件。概述当前正在工作的东西,不再工作的东西等,将帮助您找出问题所在(Boost测试是一种可能的解决方案,我自己不使用它,但是文档可以帮助您了解哪种类型。信息必须显示)。

使用适当的工具进行调试。在Unix上:

  • GDB可以告诉您程序崩溃的位置,并让您查看在什么情况下。
  • Valgrind将帮助您检测许多与内存相关的错误。
  • 在GCC中,您还可以使用mudflap在GCC,Clang中使用,从10月开始,MSVC可以使用Address / Memory Sanitizer。它可以检测到Valgrind没有的一些错误,并且性能损失更轻。通过与-fsanitize=address标志一起使用。

最后,我将推荐平常的事情。您的程序可读性,可维护性,清晰性和整洁性越强,调试起来就越容易。


5

在Unix上,您可以valgrind用来查找问题。它是免费且强大的。如果愿意,可以重载newanddelete运算符以设置一个配置,在该配置中0xDEADBEEF,每个新对象的前后都有1个字节。然后跟踪每次迭代发生的情况。这可能无法捕获所有内容(您甚至不能保证碰到那些字节),但是过去在Windows平台上它对我有用。


1
好吧,这将是4个字节而不是1个...但是原理很好。
乔纳斯·瓦格纳

1
我可以链接到我的非侵入式堆调试器吗?:-)
fredoverflow

去吧。我们都是在这里帮助他人,因此应该添加任何可以帮助的内容。
小麦色

虽然超载newdelete可超实用,采用的-fsanitize=address是一个更好的选择,因为编译器将在运行时检测编译的问题,并会自动转储内存,屏幕,这使得调试比较容易的方式。
Tarick Welling

3

是的,指针有问题。您很有可能正在使用未正确初始化的内存,但也有可能使用双重释放或诸如此类的方法来弄乱内存管理。

为了避免将未初始化的指针作为局部变量,请尝试尽可能晚地声明它们,最好是(这并不总是可能的)在可以使用有意义的值对其进行初始化时声明它们。通过检查代码,使自己确信在使用之前它们将具有价值。如果您对此感到困难,请将其初始化为空指针常量(通常写为NULL0)并检查它们。

为了避免将未初始化的指针作为成员值,请确保在构造函数中正确初始化了它们,并在副本构造函数和赋值运算符中对其进行了正确处理。init尽管可以进行其他初始化,但不要依赖于函数来进行内存管理。

如果您的类不需要复制构造函数或赋值运算符,则可以将它们声明为私有成员函数,而不用定义它们。如果显式或隐式使用它们,将导致编译器错误。

适用时使用智能指针。这里的最大优点是,如果您坚持使用它们并始终如一地使用它们,则可以完全避免书写,delete并且不会重复删除任何内容。

尽可能使用C ++字符串和容器类,而不是C样式的字符串和数组。考虑使用.at(i)而不是[i],因为这将强制进行边界检查。查看是否可以将您的编译器或库设置为[i]至少在调试模式下检查的界限。分段错误可能是由缓冲区溢出所引起的,缓冲区溢出将垃圾写入了非常好的指针。

这样做会大大降低分段错误和其他内存问题的可能性。他们无疑将无法修复所有问题,这就是为什么您不时出现问题时应立即使用valgrind的原因,而在出现问题时应使用valgrind和gdb的原因。


1

我不知道有什么方法可以用来解决这样的问题。我不认为有可能针对当前的问题提出一个方案,即您的程序的行为未定义(我不知道SEGFAULT并非由某种UB引起的) 。

有各种各样的“方法”可以避免出现问题。一个重要的是RAII。

除此之外,您只需要投入最好的心理能量即可。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.