什么是最简单的方法来制作一个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
安装一个信号处理程序来拦截。 所以根据你的情况,你可能需要/需要提出另一个信号。 SIGFPE
, SIGILL
, SIGINT
, SIGTERM
或SIGSEGV
可能是要走的路,但它们都可以被拦截。
当你不能移植的时候,你的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
将有一个随机值(无论是在之前的内存位置)。 释放它会要求系统释放该地址的内存,这通常会导致分段错误并使程序崩溃。