什么是使C++程序崩溃的最简单方法?

347

我正在尝试编写一个与另一个容易崩溃的进程(不在我的控制范围内)交互的Python程序。不幸的是,我正在交互的程序甚至不能可靠地崩溃!因此,我想制作一个快速的C++程序来有意地崩溃,但实际上我并不知道最好和最短的方法是什么,是否有人知道在这之间应该放些什么:

int main() {
    crashyCodeGoesHere();
}

为了让我的C++程序可靠地崩溃


6
您可以使用内联汇编来尝试执行特权指令:asm { cli; }; - Nate Koppenhaver
@aitchnyu 我认为每个问题的答案可用性存在差异。(顺便说一下:我没有为任何一个问题投票) - Andrew Barber
有没有在已经传播异常的情况下再抛出异常的评论?请检查我下面的答案并发表评论。 - Abhinav
6
Redis使用*((char*)-1) = 'x';代码来引发崩溃,以便进行调试。更多细节请参阅我的答案 - Shafik Yaghmour
我通过搜索测试用例来寻找一个崩溃报告系统的问题。我需要在正常运行时强制触发崩溃以调用崩溃报告和堆栈转储发送。谢谢! - Cory Trese
这个程序在所有系统上都应该始终崩溃。int *p = (int *)-1; *p = 1;。这是因为在任何系统上都不存在地址2 ^ 64 - 1,至少现在是这样(假设指针长度为8字节)。 - user16083509
31个回答

293

abort() 函数可能是您最好的选择。它是 C 标准库的一部分,并被定义为“导致异常程序终止”(例如,致命错误或崩溃)。


14
注意,通过 abort() 引起的程序崩溃不会调用任何析构函数或 atexit 函数,但在这里可能并不重要。 - Xeo
155
如果它确实调用析构函数和atexit函数,那么现在就不会崩溃了,对吗? - Donal Fellows
既然abort()是正确的答案,那么exit(-1);是否可接受? - asir6
10
不,因为它并不会导致崩溃,只是报告某些事情无法完成。 - boatcoder
Windows。GCC-5.4.0。退出代码:3。没有错误消息框。控制台消息:“此应用程序已请求运行时以不寻常的方式终止。 请联系应用程序的支持团队获取更多信息。”。 - Vadzim
调用abort()会触发像crashpad这样的东西吗?我想崩溃我的应用程序是为了确保崩溃报告正常工作。 - Ben

127

尝试:

raise(SIGSEGV);  // simulates a standard crash when access invalid memory
                 // ie anything that can go wrong with pointers.

发现于:

#include <signal.h>

3
不仅仅是实现定义,使用 signal() 可以捕获信号。但大多数正常的应用程序并不这样做。 - user149341
13
在应用程序中,它会以与普通的SIGSEGV完全相同的方式崩溃(这是大多数应用程序崩溃的方式)。它的行为已经定义明确(默认情况下,它会退出应用程序并生成一个核心文件)。是的,你可以设置处理程序,但如果你有一个处理程序,难道不想以同样的方式测试它吗! - Martin York
2
+1 for raise()。这让您仅通过更改参数就可以测试大量不同类型的异常。 - user836352
3
最喜欢的解决方案,然而它取决于平台。 - Nadim Farhat
@NadimFarhat:以哪种方式。信号在所有平台上都是信号。 - Martin York
Windows。GCC-5.4.0。退出代码:3。没有错误消息框。没有控制台消息。 - Vadzim

76

除以零会导致应用程序崩溃:

int main()
{
    return 1 / 0;
}

33
根据编译器的智能程度,这个错误可能会在编译时被捕获。我知道Visual Studio 2008不能编译此C ++或C#代码。 - AidanO
2
我已经编译并运行了它,你想要我把 .exe 文件发送给你吗? - Roee Gavirel
1
在Visual Studio最近的版本(如2010)中,以发布配置运行时不会出现问题。我猜这是一些优化所致。 - tedyyu
2
如果我没记错的话,它在 ARM 上不会崩溃。 - sherpya
3
这是未定义行为,无法保证会导致崩溃。通常编译器会假设未定义行为是不可到达的。这可能导致main函数的全部代码被删除,包括ret指令。程序执行可能直接跳转到后面的函数中。 - usr
显示剩余5条评论

70
*((unsigned int*)0) = 0xDEAD;

57
不能保证一定会崩溃。 - Windows programmer
8
不,这并不是“保证”。但是哪个明智的操作系统不会停止试图访问地址为0的内存的应用程序呢? - Joachim Sauer
33
“哪个正常的操作系统不会阻止试图访问地址0内存的应用程序?”--这并不是你想要问的,但我仍然会回答。在一些计算机中,地址0处有RAM,对于程序在那里存储一个值是完全有意义的。更有意义的问题应该是“哪个操作系统不会阻止应用程序访问C++实现保留为空指针的地址?”在这种情况下,我不知道任何操作系统不会阻止它。但原始程序是关于C++语言而不是操作系统的。 - Windows programmer
6
这是未定义行为。这样什么也不做是完全可以的。一个不会崩溃的机器:任何运行Z80系列处理器的设备(我假设我的Z80a就是这样)。 - Martin York
29
尽管这并不保证会崩溃,但这是C++中最常见的崩溃类型之一。因此,如果您想模拟崩溃,这是一种“真实”的方法 :) - Chris Burt-Brown
显示剩余14条评论

56

那么,我们是在堆栈溢出上吗?

for (long long int i = 0; ++i; (&i)[i] = i);

(没有任何标准可以保证会崩溃,但是包括被接受的答案在内,建议的所有答案都不能保证不会崩溃,因为SIGABRT其实也可能被捕获。在实践中,这个代码会在任何地方都崩溃。)


4
我能看出,在一个没有受保护的代码页的系统上,当你用一些意外成为无限循环但什么也不做的代码覆盖你的程序时,这会很有趣。极其极其极其不太可能,但有潜在可能性。 - Martin York
@Loki:如果它只从每4000个字节中读取,那会不会更不容易崩溃?绝对更安全。 - Mooing Duck
78
那个崩溃的算法不是O(1)! - Anton Barkovsky
1
@LokiAstari:你说得完全正确。我本来想用(&i)[i] += !i,但我担心编译器可能会聪明到想要优化掉它。 :-) - sam hocevar
即使这个程序崩溃:你的同事们能理解吗? - Wolf
显示剩余2条评论

36
 throw 42;

只需要答案... :)


1
Windows。GCC-5.4.0。退出代码:3。没有错误消息框。控制台消息:“抛出'int'实例后终止调用”。此应用程序已请求运行时以不寻常的方式终止。 请联系应用程序的支持团队获取更多信息。 - Vadzim

17
根据ISO/IEC 9899:1999,当未定义NDEBUG时,assert(false);保证导致崩溃:

如果定义了NDEBUG[...]则简单地定义断言宏为空操作。

也就是说,当未定义NDEBUG时,assert(false);将终止程序并生成错误消息。

#define assert(ignore) ((void)0)

每次包含头文件时,断言宏会根据NDEBUG的当前状态进行重新定义。

断言宏将诊断测试放入程序中;当表达式(必须具有标量类型)为false时[...]。然后调用abort函数。


我依稀记得 VC 2005 在断言检查方面在调试模式和发布模式下的行为不同? - Tom Kerr
8
在发布模式下,assert被等同于((void)0) - Seth Carnegie
2
@SethCarnegie 我不明白这里有什么问题 - 只有在定义了NDEBUG的情况下才不会崩溃?Dans的回答在我看来相当公正。 - Adrian Cornish
@AdrianCornish 我只是回答Tom Kerr的问题,并没有说这个答案是错误的。我没有对这个答案进行负评。 - Seth Carnegie
4
我不知道为什么他会对这个测试代码进行“发布”版的构建。 - Joel B
显示剩余2条评论

12

由于崩溃是调用未定义行为的症状,并且调用未定义行为可能导致任何结果,包括崩溃。因此,我认为您不想真正使程序崩溃,而只是让其进入调试器。最可移植的方法可能是使用abort()

虽然 raise(SIGABRT) 有相同的效果,但写起来更复杂。无论哪种方式都可以通过为 SIGABRT 安装信号处理程序来拦截。因此,根据您的情况,您可能需要引发其他信号。例如SIGFPESIGILLSIGINTSIGTERMSIGSEGV,但它们也都可以被拦截。

当您可以不考虑可移植性时,您的选择可能更广泛,比如在Linux上使用SIGBUS


1
我真的怀疑他是否想要一个调试器。他似乎想要测试当崩溃程序的调用者遇到崩溃时会发生什么。这非常合理。 - Donal Fellows

10

答案因平台而异,取决于您的目标。但这里是 Mozilla JavaScript 崩溃函数,我认为它展示了许多使其工作具有挑战性的问题:

static JS_NEVER_INLINE void
CrashInJS()
{
    /*
     * We write 123 here so that the machine code for this function is
     * unique. Otherwise the linker, trying to be smart, might use the
     * same code for CrashInJS and for some other function. That
     * messes up the signature in minidumps.
     */

#if defined(WIN32)
    /*
     * We used to call DebugBreak() on Windows, but amazingly, it causes
     * the MSVS 2010 debugger not to be able to recover a call stack.
     */
    *((int *) NULL) = 123;
    exit(3);
#elif defined(__APPLE__)
    /*
     * On Mac OS X, Breakpad ignores signals. Only real Mach exceptions are
     * trapped.
     */
    *((int *) NULL) = 123;  /* To continue from here in GDB: "return" then "continue". */
    raise(SIGABRT);  /* In case above statement gets nixed by the optimizer. */
#else
    raise(SIGABRT);  /* To continue from here in GDB: "signal 0". */
#endif
}

3
你应该完全放弃那个,改用jQuery。 - Thomas Weller
1
这是未定义行为,不能保证崩溃。通常编译器会假设未定义行为是不可达的。在这种情况下,至少崩溃的代码行将被删除,其他代码也可能被删除。 - usr

9
我唯一掌握的是 abort() 函数
它会终止进程并导致异常程序结束,同时生成 SIGABRT 信号。默认情况下,该信号会导致程序以失败的终止错误码返回给主机环境。程序被终止时,不会执行具有自动或静态存储期限的对象的析构函数,也不会调用任何在程序终止前由 exit() 调用的 atexit() 函数。它永远不会返回到其调用者处。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接