it-swarm.dev

Jaki jest najprostszy sposób na awarię programu C ++?

Próbuję stworzyć program Python, który łączy się z innym procesem powodującym awarie (który jest poza moim zasięgiem). Niestety program, z którym się komunikuję, nawet nie ulega awarii! chcę stworzyć szybki program C++, który celowo ulega awarii, ale tak naprawdę nie znam najlepszego i najkrótszego sposobu, aby to zrobić, czy ktoś wie, co umieścić między moim:

int main() {
    crashyCodeGoesHere();
}

aby niezawodnie zawiesić mój program C++

309
jonathan topf

Funkcja abort() jest prawdopodobnie najlepszym wyborem. Jest to część standardowej biblioteki C i jest zdefiniowana jako „powodująca nieprawidłowe zakończenie programu” (np. Błąd krytyczny lub awaria).

252
duskwuff

Próbować:

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

Znaleziono w:

#include <signal.h>
113
Martin York

Dzielenie przez zero spowoduje awarię aplikacji:

int main()
{
    return 1 / 0;
}
73
Roee Gavirel
*((unsigned int*)0) = 0xDEAD;
63
Keith Nicholas

Cóż, czy jesteśmy na stosie przepełnienie, czy nie?

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

(Nie ma gwarancji, że nastąpi awaria według żadnych standardów, ale nie ma też żadnej z sugerowanych odpowiedzi, w tym tej zaakceptowanej, ponieważ SIGABRT mógł i tak zostać złapany. W praktyce nastąpi awaria wszędzie).

51
sam hocevar
 throw 42;

Tylko odpowiedź ... :)

35
Macke

assert(false); też jest całkiem dobra.

Zgodnie z ISO/IEC 9899: 1999 gwarantuje się awarię, gdy NDEBUG nie jest zdefiniowany:

Jeśli zdefiniowano NDEBUG [...], makro assert definiuje się po prostu jako

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

Makro assert jest redefiniowane zgodnie z bieżącym stanem NDEBUG za każdym razem, gdy jest dołączane.

[...]

Makro assert umieszcza testy diagnostyczne w programach; [...] jeśli wyrażenie (które powinno mieć typ skalarny) jest fałszywe [...]. Następnie wywołuje funkcję przerwania.

15
Dan F

Ponieważ awaria jest objawem wywoływania nieokreślonego zachowania, a ponieważ wywoływanie niezdefiniowanego zachowania może prowadzić do czegokolwiek, w tym awarii, nie sądzę, że chcesz naprawdę zawiesić swój program, ale po prostu upuść go w debuggerze. Najbardziej przenośnym sposobem na to jest prawdopodobnie abort().

Podczas gdy raise(SIGABRT) ma taki sam efekt, z pewnością jest więcej do napisania. Oba sposoby można jednak przechwycić, instalując moduł obsługi sygnału dla SIGABRT. Więc w zależności od twojej sytuacji, możesz chcieć/trzeba podnieść kolejny sygnał. SIGFPE, SIGILL, SIGINT, SIGTERM lub SIGSEGV może być dobrym rozwiązaniem, ale wszystkie można przechwycić.

Jeśli możesz być nie do przeniesienia, twoje wybory mogą być jeszcze szersze, na przykład użycie SIGBUS na Linuksie.

11
PlasmaHH

Odpowiedź zależy od platformy i zależy od twoich celów. Ale oto funkcja awarii Mozilla Javascript, która moim zdaniem ilustruje wiele wyzwań, które sprawiają, że ta funkcja działa:

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
}
9
Paul Biggar

Jedyny flash jaki miałem to funkcja abort ():

Przerywa proces z nienormalnym zakończeniem programu. Generuje sygnał SIGABRT, co domyślnie powoduje zakończenie przez program zwracania nieudanego kodu błędu zakończenia do środowiska Hosta. Program zostaje zakończony bez wykonywania destruktorów dla obiektów o automatycznym lub statycznym czasie przechowywania oraz bez wywołania dowolna atexit (która jest wywoływana przez exit () przed zakończeniem programu). Nigdy nie wraca do dzwoniącego.

9
samridhi

Widzę, że opublikowano tutaj wiele odpowiedzi, które trafią w szczęśliwe przypadki, aby wykonać zadanie, ale żadna z nich nie jest w 100% deterministyczna w przypadku awarii. Niektóre ulegną awarii na jednym sprzęcie i systemie operacyjnym, inne nie. Istnieje jednak standardowy sposób, zgodnie z oficjalnym standardem C++, aby spowodować awarię.

Cytowanie z C++ Standard ISO/IEC 14882 §15.1-7 :

Jeśli mechanizm obsługi wyjątków, po zakończeniu inicjalizacji obiektu wyjątku, ale przed aktywacją modułu obsługi wyjątku, wywołuje funkcję, która kończy się przez wyjątek, wywoływana jest funkcja std :: terminate (15.5.1).

struct C {
    C() { }
    C(const C&) {
        if (std::uncaught_exceptions()) {
            throw 0; // throw during copy to handler’s exception-declaration object (15.3)
        }
    }
};
int main() {
    try {
    throw C(); // calls std::terminate() if construction of the handler’s
    // exception-declaration object is not elided (12.8)
    } catch(C) { }
}

Napisałem mały kod, aby to zademonstrować i można go znaleźć i wypróbować Ideone tutaj .

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 wspomina o rzucie bez bloku próbnego, co powoduje niejawne wezwanie do przerwania:

Jeśli obecnie nie jest obsługiwany żaden wyjątek, wykonanie wyrażenia typu throw bez wywołań argumentów std :: terminate ()

Inne obejmują: rzut z destruktora: ISO/IEC 14882 § 15,2/3

8
Abhinav

Brakuje tego:

int main = 42;
6
mvds
*( ( char* ) NULL ) = 0;

Spowoduje to błąd segmentacji.

5
wrren

Występuje awaria w moim systemie Linux, ponieważ literały łańcuchowe są przechowywane w pamięci tylko do odczytu:

0[""]--;

Nawiasem mówiąc, g ++ nie chce tego skompilować. Kompilatory stają się coraz mądrzejsze :)

5
fredoverflow

Co z przepełnieniem stosu wywołaniem metody rekurencyjnej w pętli martwej?

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

Zobacz oryginalny przykład w Microsoft KB

5
sll

Jest to bardziej gwarantowana wersja przerwania przedstawiona w powyższych odpowiedziach, która zajmuje się sytuacją, gdy sigabrt jest zablokowany. Możesz infact użyć dowolnego sygnału zamiast przerywania, który domyślnie powoduje zawieszenie programu.

#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();
}
4
bashrc
int i = 1 / 0;

Twój kompilator prawdopodobnie ostrzeże Cię przed tym, ale dobrze się kompiluje pod GCC 4.4.3. To prawdopodobnie spowoduje SIGFPE (wyjątek zmiennoprzecinkowy), co być może nie jest tak prawdopodobne w prawdziwej aplikacji jak SIGSEGV (naruszenie segmentacji pamięci), jak powodują inne odpowiedzi, ale wciąż jest to awaria. Moim zdaniem jest to o wiele bardziej czytelne.

Innym sposobem, jeśli będziemy oszukiwać i używać signal.h, jest:

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

Gwarantuje to zabicie podprocesu, w przeciwieństwie do SIGSEGV.

4
AlexWebr
int* p=0;
*p=0;

To też powinno się zawiesić. W Windows zawiesza się z AccessViolation i chyba powinien działać tak samo na wszystkich systemach operacyjnych.

3
laci37

Chociaż to pytanie ma już zaakceptowaną odpowiedź ...

void main(){
    throw 1;
}

Lub ... void main(){throw 1;}

2

To jest fragment kodu dostarczony przez Google w Breakpad.

  volatile int* a = reinterpret_cast<volatile int*>(NULL);
  *a = 1;
2
Cory Trese

Zapis w pamięci tylko do odczytu spowoduje błąd segmentacji, chyba że system nie obsługuje bloków pamięci tylko do odczytu.

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

Przetestowałem to z MingGW 5.3.0 na Windows 7 i GCC na Linux Mint. Przypuszczam, że inne kompilatory i systemy dadzą podobny efekt.

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

Lub w inny sposób, odkąd jesteśmy na wozie zespołu.

Cudowny kawałek nieskończonej rekurencji. Gwarantowane wysadzenie twojego stosu.

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

Wydruki:

Błąd segmentacji (zrzut rdzenia)

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

Ten, o którym jeszcze nie wspomniano:

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

Spowoduje to potraktowanie wskaźnika zerowego jako wskaźnika funkcji, a następnie wywołanie go. Podobnie jak w przypadku większości metod, nie ma gwarancji, że spowoduje to awarię programu, ale szanse systemu operacyjnego na pozostawienie go niezaznaczonego i powrotu programu są znikome.

0
Anton Golov

Stylowym sposobem na zrobienie tego jest czysto wirtualne wywołanie funkcji:

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;
}

Skompilowany z gcc, wyświetla:

zwana czystą metodą wirtualną

terminate wywoływany bez aktywnego wyjątku

Przerwany (zrzut rdzenia)

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;
  }

}

Mam nadzieję, że to się zawiesi. Twoje zdrowie.

0
senthil