什么是最简单的方法来制作一个C ++程序崩溃?

我试图做一个Python程序,与一个不同的crashy进程(这是我的手)。 不幸的是我连接的程序甚至不能可靠地崩溃! 所以我想制作一个快速崩溃的C ++程序,但是我实际上并不知道最好的和最短的方法来做这件事,有谁知道我的:

int main() { crashyCodeGoesHere(); } 

使我的C ++程序可靠地崩溃

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

尝试:

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

在发现:

 #include <signal.h> 

除以零会使应用程序崩溃:

 int main() { int i = 1 / 0; } 
 *((unsigned int*)0) = 0xDEAD; 

那么,我们在堆栈 溢出 ,或不?

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

(不能保证以任何标准崩溃,但是既然SIGABRT可以被捕获,那么也不会有任何build议的答案,包括被接受的答案,实际上,这将在任何地方崩溃。

  throw 42; 

只是答案… 🙂

assert(false); 也很好。

根据ISO / IEC 9899:1999,当NDEBUG未定义时,保证崩溃:

如果定义了NDEBUG,则assertmacros被简单地定义为

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

每次包含时,根据NDEBUG的当前状态重新定义断言macros。

[…]

断言macros将诊断testing放入程序中; 如果expression(应该是一个标量types)是假的[…]。 然后它调用中止函数。

由于崩溃是调用未定义行为的一个症状,并且由于调用未定义的行为可能会导致任何事情,包括崩溃,所以我不认为你真的要崩溃你的程序,而只是把它放到debugging器中。 最便携的方式可能是abort()

虽然raise(SIGABRT)具有相同的效果,但写入肯定更多。 然而,两种方式都可以通过为SIGABRT安装一个信号处理程序来拦截。 所以根据你的情况,你可能需要/需要提出另一个信号。 SIGFPESIGILLSIGINTSIGTERMSIGSEGV可能是要走的路,但它们都可以被拦截。

当你不能移植的时候,你的select可能会更广泛,比如在Linux上使用SIGBUS

我唯一的闪光是abort()函数

它终止程序,程序终止exception。它产生SIGABRT信号 ,默认情况下程序终止,向主机环境返回一个不成功的终止错误代码。程序终止, 不执行自动或静态存储持续时间的对象的析构函数 ,而不用调用任何atexit (在程序终止之前由exit()调用)函数。 它永远不会返回给调用者。

答案是平台特定的,取决于你的目标。 但是这里有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 } 

如何通过死循环recursion方法调用堆栈溢出?

 #include <windows.h> #include <stdio.h> void main() { StackOverflow(0); } void StackOverflow(int depth) { char blockdata[10000]; printf("Overflow: %d\n", depth); StackOverflow(depth+1); } 

请参阅Microsoft知识库中的原始示例

C ++可以通过并行有2个exception确定性地崩溃! 标准说永远不要从析构函数中抛出任何exception,也不要在可能抛出exception的析构函数中使用任何函数。

我们必须做一个function,所以让离开析构等。

来自ISO / IEC 14882§15.1-7的一个例子。 应该按照C ++标准进行崩溃。 在这里可以findideone的例子 。

 class MyClass{ public: ~MyClass() throw(int) { throw 0;} }; int main() { try { MyClass myobj; // its destructor will cause an exception // This is another exception along with exception due to destructor of myobj and will cause app to terminate throw 1; // It could be some function call which can result in exception. } catch(...) { std::cout<<"Exception catched"<<endl; } return 0; } 

ISO / IEC 14882§15.1/ 9提到没有尝试块的抛出导致隐式调用中止:

如果当前没有exception处理,执行没有操作数的throw-expression调用std :: terminate()

其他包括:从析构函数中抛出: ISO / IEC 14882§15.2/ 3

 *( ( char* ) NULL ) = 0; 

这会产生分段错误。

 int i = 1 / 0; 

你的编译器可能会提醒你这个问题,但是在GCC 4.4.3下编译得很好。这可能会导致一个SIGFPE(浮点exception),这在SIGSEGV(内存分割违例)其他的答案,但它仍然是一个崩溃。 在我看来,这更可读。

另一种方式,如果我们要作弊并使用signal.h ,则是:

 #include <signal.h> int main() { raise(SIGKILL); } 

这是保证杀死subprocess,以对比SIGSEGV。

这是在上面的答案中提出的一个更有保证的中止版本。它考虑到sigabrt被阻塞的情况。您可以使用任何信号而不是中止程序的默认行为。

 #include<stdio.h> #include<signal.h> #include<unistd.h> #include<stdlib.h> int main() { sigset_t act; sigemptyset(&act); sigfillset(&act); sigprocmask(SIG_UNBLOCK,&act,NULL); abort(); } 

这在我的Linux系统上崩溃,因为string文字存储在只读内存中:

 0[""]--; 

顺便说一下,g ++拒绝编译这个。 编译器变得更聪明更聪明:)

这一个是失踪的:

 int main = 42; 
 int* p=0; *p=0; 

这也应该崩溃。 在Windows上,它与AccessViolation崩溃,它应该在所有的操作系​​统,我猜的一样。

 int main(int argc, char *argv[]) { char *buf=NULL;buf[0]=0; return 0; } 

虽然这个问题已经有一个被接受的答案…

 void main(){ throw 1; } 

或者… void main(){throw 1;}

或者是另一种方式,因为我们在乐队的旅行车上。

一个可爱的无限recursion。 保证吹你的堆栈。

 int main(int argv, char* argc) { return main(argv, argc) } 

打印出来:

分割故障(核心转储)

写入只读内存将导致分段错误,除非您的系统不支持只读内存块。

 int main() { (int&)main = 0; } 

我已经用Windows 7上的MingGW 5.3.0和Linux Mint上的GCC进行了testing。 我想其他编译器和系统也会有类似的效果。

还没有提到的一个:

 ((void(*)())0)(); 

这将把空指针作为一个函数指针,然后调用它。 就像大多数方法一样,这不能保证程序崩溃,但是操作系统允许这个不受检查和程序返回的机会是微不足道的。

很短,它崩溃!

 int main() { main(); } 
 void main() { int *aNumber = (int*) malloc(sizeof(int)); int j = 10; for(int i = 2; i <= j; ++i) { aNumber = (int*) realloc(aNumber, sizeof(int) * i); j += 10; } } 

希望这崩溃。 干杯。

 void recurse(){ recurse(); } 

recurse()会一直在堆栈上分配,直到最后还有一个堆栈溢出。

 int main() { int *p=3; int s; while(1) { s=*p; p++; } } 

一个时髦的做法是纯粹的虚函数调用:

 class Base; void func(Base*); class Base { public: virtual void f() = 0; Base() { func(this); } }; class Derived : Base { virtual void f() { } }; void func(Base* p) { p->f(); } int main() { Derived d; } 

用gcc编译,打印出来:

纯虚的方法叫

终止调用没有活动的exception

中止(核心倾弃)

这是Google在Breakpad中提供的片段。

  volatile int* a = reinterpret_cast<volatile int*>(NULL); *a = 1; 
 char*freeThis; free(freeThis); 

释放未初始化的指针是未定义的行为。 在许多平台/编译器上, freeThis将有一个随机值(无论是在之前的内存位置)。 释放它会要求系统释放该地址的内存,这通常会导致分段错误并使程序崩溃。