Каков самый простой способ сделать сбой программы на C++?
Я пытаюсь сделать программу Python, которая взаимодействует с другим crashy процессом (это не в моих руках). К сожалению, программа, с которой я взаимодействую, даже не падает надежно! Поэтому я хочу сделать быструю программу на C++, которая специально падает, но я на самом деле не знаю лучшего и кратчайшего способа сделать это, кто-нибудь знает, что положить между моими:
int main() {
crashyCodeGoesHere();
}
чтобы сделать мою программу C++ аварийно завершить работу надежно
28 ответов:
на
abort()функция, вероятно, ваш лучший выбор. Это часть стандартной библиотеки C и определяется как "вызывающая ненормальное завершение программы" (например, фатальная ошибка или сбой).
попробуй:
raise(SIGSEGV); // simulates a standard crash when access invalid memory // ie anything that can go wrong with pointers.найти:
#include <signal.h>
Ну, мы на стекпереполнения, или нет?
for (long long int i = 0; ++i; (&i)[i] = i);(не гарантируется сбой по любым стандартам, но ни один из предложенных ответов, включая принятый, так как
SIGABRTмог быть пойман в любом случае. На практике это будет крах везде.)
assert(false);тоже неплохо.согласно ISO / IEC 9899: 1999 гарантируется сбой, когда NDEBUG не определен:
Если определен NDEBUG [...] макрос assert определяется просто как
#define assert(ignore) ((void)0)макрос assert переопределяется в соответствии с текущим состоянием NDEBUG каждый раз, когда он включен.
[...]
макрос assert помещает диагностические тесты в программы; [...] если выражение (которое должен иметь скалярный тип) является ложным [...]. Оно затем вызывает функцию abort.
поскольку сбой является симптомом вызова неопределенного поведения, и поскольку вызов неопределенного поведения может привести к чему угодно, включая сбой, я не думаю, что вы хотите действительно разбить свою программу, но просто поместите ее в отладчик. Самый портативный способ сделать это, вероятно,
abort().пока
raise(SIGABRT)имеет тот же эффект, это, конечно, больше писать. Однако оба способа могут быть перехвачены путем установки обработчика сигнала дляSIGABRT. Поэтому в зависимости от вашей ситуации, вы может потребоваться / нужно поднять другой сигнал.SIGFPE,SIGILL,SIGINT,SIGTERMилиSIGSEGVможет быть путь, но все они могут быть перехвачены.когда вы можете быть не переносимы, ваш выбор может быть еще шире, например, с помощью
SIGBUSна linux.
единственная вспышка у меня была функция abort ():
он прерывает процесс с анормалной программой termination.It генерирует сигнал 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 }
C++ может быть разбит детерминированно, имея 2 исключения параллельно! Стандарт говорит, что никогда не бросайте исключение из деструктора или никогда не используйте какую-либо функцию в деструкторе, которая может вызвать исключение.
мы должны сделать функцию, так что давайте оставим деструктор и т. д.
пример ISO / IEC 14882 §15.1-7. Должен быть сбой в соответствии со стандартом C++. пример Ideone можно найти здесь.
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 упоминает бросок без блока try, что приводит к неявному вызову для прерывания:
Если в настоящее время не обрабатывается ни одно исключение, выполнение a throw-выражение без операнда вызывает std:: terminate ()
другие включают : бросок из деструктора:ISO / IEC 14882 §15.2 / 3
Как насчет переполнения стека при вызове рекурсивного метода мертвого цикла?
#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 KB
Это более гарантированная версия прерывания, представленная выше answers.It заботится о ситуации, когда 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, потому что строковые литералы хранятся в памяти только:
0[""]--;кстати, g++ отказывается компилировать это. Компиляторы становятся все умнее и умнее :)
int i = 1 / 0;ваш компилятор, вероятно, предупредит вас об этом, но он компилируется просто отлично под GCC 4.4.3 Это будет наверное вызовите SIGFPE (исключение с плавающей запятой), что, возможно, не так вероятно в реальном приложении, как SIGSEGV (нарушение сегментации памяти), поскольку другие ответы вызывают, но это все еще сбой. На мой взгляд, это гораздо более читабельным.
другой способ, если мы собираемся обманывать и использовать
signal.h, является:#include <signal.h> int main() { raise(SIGKILL); }Это гарантированно убить подпроцесс, чтобы контрастировать с SIGSEGV.
int* p=0; *p=0;Это должно произойти сбой. В Windows он падает с AccessViolation, и он должен делать то же самое на всех ОС-es, я думаю.
Это фрагмент, предоставленный Google в Breakpad.
volatile int* a = reinterpret_cast<volatile int*>(NULL); *a = 1;
запись в память только для чтения приведет к ошибке сегментации, если ваша система не поддерживает блоки памяти только для чтения.
int main() { (int&)main = 0; }я протестировал его с MingGW 5.3.0 на Windows 7 и GCC на Linux Mint. Я полагаю, что другие компиляторы и системы дадут аналогичный эффект.
или другим способом, так как мы на группу вагонов.
прекрасный кусок бесконечной рекурсии. Гарантированно взорвать ваш стек.
int main(int argv, char* argc) { return main(argv, argc) }выводит:
ошибка сегментирования (ядро бросила)
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; } }надеюсь, что это падает. Овации.
стильный способ сделать это-чисто виртуальный вызов функции:
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, это печатает:
чисто виртуальный метод называется
завершить вызов без активного исключения
прервана (ядро бросила)
тот, который еще не был упомянут:
((void(*)())0)();Это позволит обработать нулевой указатель как указатель на функцию, а затем вызвать его. Так же, как и большинство методов, это не гарантирует сбой программы, но шансы на то, что ОС позволит этому пройти незамеченным и программа когда-либо вернется, ничтожны.
char*freeThis; free(freeThis);освобождение неинициализированного указателя является неопределенным поведением. На многих платформах/компиляторах
freeThisбудет иметь случайное значение (что бы ни было в этом месте памяти раньше). Освобождение его попросит систему освободить память по этому адресу, что обычно вызовет ошибку сегментации и приведет к сбою программы.
Comments