Какой самый простой способ вызвать сбой программы на C++?
Я пытаюсь создать программу на Python, которая взаимодействует с другим аварийным процессом (это не в моих руках). К сожалению, программа, с которой я взаимодействую, даже не дает сбоя! Итак, я хочу сделать быструю программу на C++, которая намеренно зависает, но я не знаю, какой самый лучший и кратчайший способ сделать это, кто-нибудь знает, что нужно поместить между моими:
int main() {
crashyCodeGoesHere();
}
чтобы моя C++ программа аварийно завершилась
32 ответа
abort()
функция, вероятно, ваш лучший выбор. Он является частью стандартной библиотеки C и определяется как "вызывающий ненормальное завершение программы" (например, фатальная ошибка или сбой).
Пытаться:
raise(SIGSEGV); // simulates a standard crash when access invalid memory
// ie anything that can go wrong with pointers.
Нашел в:
#include <signal.h>
Деление на ноль приведет к сбою приложения:
int main()
{
return 1 / 0;
}
Ну, у нас переполнениестека или нет?
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()
,
В то время как raise(SIGABRT)
имеет тот же эффект, это, безусловно, больше писать. Однако оба пути могут быть перехвачены установкой обработчика сигнала для SIGABRT
, Таким образом, в зависимости от вашей ситуации, вы можете / должны поднять другой сигнал. SIGFPE
, SIGILL
, SIGINT
, SIGTERM
или же SIGSEGV
может быть, путь, но они все могут быть перехвачены.
Когда вы можете быть непереносимым, ваш выбор может быть еще шире, например, использование SIGBUS
на Linux.
Ответ зависит от платформы и зависит от ваших целей. Но вот функция сбоя 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++ может быть детерминированно завершен с помощью двух параллельных исключений! Стандарт гласит, что никогда не выбрасывайте никаких исключений из деструктора ИЛИ никогда не используйте никакую функцию в деструкторе, которая может генерировать исключение.
мы должны сделать функцию, так что давайте оставим деструктор и т. д. и т. д.
Пример из ИСО / МЭК 14882 §15.1-7. Должен быть сбой согласно стандарту C++. Идеальный пример можно найти здесь.
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;
}
ИСО / МЭК 14882 §15.1/9 упоминает throw без блока try, что приводит к неявному вызову abort:
Если никакое исключение в настоящее время не обрабатывается, выполнение выражения броска без операндов вызывает std::terminate()
Другие включают: бросок от деструктора: ISO / IEC 14882 §15.2 / 3
Единственная вспышка, которая у меня была, это функция abort():
Он прерывает процесс с ненормальным завершением программы. Он генерирует сигнал SIGABRT, который по умолчанию заставляет программу завершить работу, возвращая неуспешный код ошибки завершения в среду хоста. Программа завершается без выполнения деструкторов для объектов автоматической или статической длительности хранения. и без вызова какой-либо функции atexit(которая вызывается методом exit() до завершения программы). Он никогда не возвращается к своему абоненту.
Это происходит сбой в моей системе Linux, потому что строковые литералы хранятся в постоянной памяти:
0[""]--;
Кстати, g++ отказывается компилировать это. Компиляторы становятся умнее и умнее:)
Как насчет переполнения стека при вызове рекурсивного метода мертвого цикла?
#include <windows.h>
#include <stdio.h>
void main()
{
Stackru(0);
}
void Stackru(int depth)
{
char blockdata[10000];
printf("Overflow: %d\n", depth);
Stackru(depth+1);
}
Это более гарантированная версия прерывания, представленная в приведенных выше ответах. Она заботится о ситуации, когда 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();
}
Это фрагмент, предоставленный Google в Breakpad.
volatile int* a = reinterpret_cast<volatile int*>(NULL);
*a = 1;
int i = 1 / 0;
Ваш компилятор, вероятно, предупредит вас об этом, но он прекрасно компилируется в GCC 4.4.3. Это, вероятно, вызовет SIGFPE (исключение с плавающей запятой), что, вероятно, не так вероятно в реальном приложении, как SIGSEGV (нарушение сегментации памяти), как другие ответы вызывают, но это все еще крах. На мой взгляд, это гораздо более читабельно.
Другой способ, если мы собираемся обмануть и использовать signal.h
, является:
#include <signal.h>
int main() {
raise(SIGKILL);
}
Это гарантированно уничтожит подпроцесс, в отличие от SIGSEGV.
Хотя на этот вопрос уже есть принятый ответ...
void main(){
throw 1;
}
Или же... void main(){throw 1;}
int* p=0;
*p=0;
Это тоже должно вылететь. В Windows происходит сбой с AccessViolation, и он должен делать то же самое на всех ОС, я думаю.
Запись в память только для чтения вызовет ошибку сегментации, если ваша система не поддерживает блоки памяти только для чтения.
int main() {
(int&)main = 0;
}
Я проверил это с MingGW 5.3.0 на Windows 7 и GCC на Linux Mint. Я предполагаю, что другие компиляторы и системы дадут аналогичный эффект.
int main(int argc, char *argv[])
{
char *buf=NULL;buf[0]=0;
return 0;
}
Или другой путь, так как мы в группе.
Прекрасный кусок бесконечной рекурсии. Гарантированно взорвать ваш стек.
int main(int argv, char* argc)
{
return main(argv, argc)
}
Распечатывает:
Ошибка сегментации (ядро сброшено)
Используйте __builtin_trap () в GCC или clang или __debugbreak () в MSVC. Отсутствие обработки этих точек останова / прерываний приведет к необработанному исключению / сбою точки останова. Другие предложения, которые используют abort() или exit(): они могут обрабатываться другими потоками, что затрудняет просмотр стека потока, который распространил сбой.
Вы можете использовать сборку в своем C++ code
НО INT 3
только для систем x86, другие системы могут иметь другие инструкции прерывания / точки останова.
int main()
{
__asm int 3;
return 0;
}
INT 3
вызывает прерывание и вызывает вектор прерывания, установленный ОС.
Стильный способ сделать это - вызов чисто виртуальной функции:
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)();
Это будет рассматривать нулевой указатель как указатель на функцию, а затем вызывать его. Как и большинство методов, это не гарантирует сбой программы, но шансы ОС, позволяющей это сделать, не проверяются, и программы, которая когда-либо возвращается, незначительны.
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;
}
}
Надеюсь, это потерпит крах. Приветствия.
#include <thread>
int main()
{
auto noop = [](){return;};
std::thread t1(noop); // Thread t1 is in a joinable state.
// When program returns t1 will be out of scope.
// Destructing a joinable thread creates a crash.
return 0;
}
Простой код переполнения буфера, который приведет к сбою программы
int main()
{
int n[0];
n[2] = 0;
}