Каков самый простой способ сделать сбой программы на C++?



Я пытаюсь сделать программу Python, которая взаимодействует с другим crashy процессом (это не в моих руках). К сожалению, программа, с которой я взаимодействую, даже не падает надежно! Поэтому я хочу сделать быструю программу на C++, которая специально падает, но я на самом деле не знаю лучшего и кратчайшего способа сделать это, кто-нибудь знает, что положить между моими:



int main() {
crashyCodeGoesHere();
}


чтобы сделать мою программу C++ аварийно завершить работу надежно

1064   28  

28 ответов:

на 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;
}
*((unsigned int*)0) = 0xDEAD;

Ну, мы на стекпереполнения, или нет?

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

(не гарантируется сбой по любым стандартам, но ни один из предложенных ответов, включая принятый, так как SIGABRT мог быть пойман в любом случае. На практике это будет крах везде.)

 throw 42;

просто ответ... :)

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

*( ( char* ) NULL ) = 0;

это приведет к ошибке сегментации.

Как насчет переполнения стека при вызове рекурсивного метода мертвого цикла?

#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();
}

Это отсутствует:

int main = 42;

этот сбой в моей системе 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, я думаю.

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

хотя этот вопрос уже есть принятый ответ...

void main(){
    throw 1;
}

или... void main(){throw 1;}

Это фрагмент, предоставленный 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;
  }

}

надеюсь, что это падает. Овации.

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, это печатает:

чисто виртуальный метод называется

завершить вызов без активного исключения

прервана (ядро бросила)

тот, который еще не был упомянут:

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

Это позволит обработать нулевой указатель как указатель на функцию, а затем вызвать его. Так же, как и большинство методов, это не гарантирует сбой программы, но шансы на то, что ОС позволит этому пройти незамеченным и программа когда-либо вернется, ничтожны.

char*freeThis;
free(freeThis);

освобождение неинициализированного указателя является неопределенным поведением. На многих платформах/компиляторах freeThis будет иметь случайное значение (что бы ни было в этом месте памяти раньше). Освобождение его попросит систему освободить память по этому адресу, что обычно вызовет ошибку сегментации и приведет к сбою программы.

Comments

    Ничего не найдено.