Qual è il modo più semplice per bloccare un programma C ++?

Sto cercando di creare un programma Python che si interfaccia con un diverso processo di crash (che è fuori dalle mie mani). Sfortunatamente il programma con cui sto interagendo non si arresta nemmeno in modo affidabile! Quindi voglio fare un rapido programma C ++ che si blocca di proposito, ma in realtà non conosco il modo migliore e più breve per farlo, qualcuno sa cosa mettere tra i miei:

int main() { crashyCodeGoesHere(); } 

per far sì che il mio programma C ++ si blocchi in modo affidabile

La funzione abort() è probabilmente la soluzione migliore. Fa parte della libreria standard C ed è definito come “causa di interruzione anomala del programma” (ad esempio, un errore irreversibile o un arresto anomalo).

Provare:

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

Trovato in:

 #include  

Dividendo per zero si bloccherà l’applicazione:

 int main() { return 1 / 0; } 
 *((unsigned int*)0) = 0xDEAD; 

Bene, siamo in overflow dello stack o no?

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

(Non è garantito il crash da nessuno standard, ma nessuna delle risposte suggerite include quella accettata dal momento che SIGABRT potrebbe essere stato catturato comunque. In pratica, questo andrà in crash ovunque.)

  throw 42; 

Solo la risposta … 🙂

assert(false); è abbastanza buono anche

Secondo ISO / IEC 9899: 1999 è garantito il crash quando NDEBUG non è definito:

Se NDEBUG è definito […] la macro assert viene definita semplicemente come

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

La macro assert viene ridefinita in base allo stato corrente di NDEBUG ogni volta che viene incluso.

[…]

La macro assertiva mette i test diagnostici in programmi; […] se l’espressione (che deve avere un tipo scalare) è falsa […]. Quindi chiama la funzione di interruzione.

Poiché un arresto anomalo è un sintomo di invocazione di un comportamento indefinito, e poiché invocare un comportamento indefinito può portare a qualsiasi cosa, incluso un arresto anomalo, non penso che tu voglia veramente mandare in crash il tuo programma, ma semplicemente farlo cadere in un debugger. Il modo più semplice per farlo è probabilmente abort() .

Mentre raise(SIGABRT) ha lo stesso effetto, è sicuramente più da scrivere. Entrambi i modi tuttavia possono essere intercettati installando un gestore di segnale per SIGABRT . Quindi, a seconda della situazione, potresti volere / dover aumentare un altro segnale. SIGFPE , SIGILL , SIGINT , SIGTERM o SIGSEGV potrebbero essere la strada da percorrere, ma tutti possono essere intercettati.

Quando puoi essere non portabile, le tue scelte potrebbero essere anche più ampie, come usare SIGBUS su Linux.

L’unico flash che ho avuto è la funzione abort () :

Interrompe il processo con una terminazione anomala del programma. Genera il segnale SIGABRT , che per impostazione predefinita causa la chiusura del programma restituendo un codice di errore di terminazione non riuscito all’ambiente host. Il programma viene terminato senza eseguire i distruttori per oggetti di durata di archiviazione automatica o statica e senza chiamare alcun atexit (che viene chiamato da exit () prima che il programma termini). Non ritorna mai al suo chiamante.

La risposta è specifica per la piattaforma e dipende dai tuoi obiettivi. Ma ecco la funzione di crash di Mozilla Javascript, che a mio avviso illustra molte delle sfide per farlo funzionare:

 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 ++ può essere arrestato in modo deterministico avendo 2 eccezioni in parallelo! Lo standard dice non lanciare mai alcuna eccezione da un distruttore OPPURE non utilizzare mai alcuna funzione in un distruttore che potrebbe generare un’eccezione.

dobbiamo fare una funzione così lasciamo il distruttore ecc. ecc.

Un esempio da ISO / IEC 14882 §15.1-7 . Dovrebbe essere un crash secondo lo standard C ++. L’esempio di Ideone può essere trovato qui .

 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"< 

La norma ISO / IEC 14882 §15.1 / 9 cita il lancio senza blocco try con conseguente richiamo implicito di una interruzione:

Se non viene gestita alcuna eccezione, l'esecuzione di un'espressione throw senza alcun operando chiama std :: terminate ()

Altri includono: lancio dal distruttore: ISO / IEC 14882 §15.2 / 3

Che dire dello stack overflow con una chiamata al metodo ricorsivo a ciclo morto?

 #include  #include  void main() { StackOverflow(0); } void StackOverflow(int depth) { char blockdata[10000]; printf("Overflow: %d\n", depth); StackOverflow(depth+1); } 

Vedere l’ esempio originale su Microsoft KB

 *( ( char* ) NULL ) = 0; 

Ciò produrrà un errore di segmentazione.

Questa è una versione più sicura di abort presentata nelle risposte di cui sopra. Si prende cura della situazione quando sigabrt è bloccato. È ansible infatti utilizzare qualsiasi segnale invece di interrompere che ha l’azione predefinita di arrestare il programma.

 #include #include #include #include int main() { sigset_t act; sigemptyset(&act); sigfillset(&act); sigprocmask(SIG_UNBLOCK,&act,NULL); abort(); } 

Questo manca:

 int main = 42; 

Questo si blocca sul mio sistema Linux, perché i valori letterali delle stringhe sono memorizzati nella memoria di sola lettura:

 0[""]--; 

A proposito, g ++ si rifiuta di compilare questo. I compilatori stanno diventando più intelligenti e intelligenti 🙂

 int i = 1 / 0; 

Il compilatore probabilmente ti avviserà di questo, ma si compila bene con GCC 4.4.3 Questo probabilmente causerà un SIGFPE (eccezione a virgola mobile), che forse non è così probabile in un’applicazione reale come SIGSEGV (violazione della segmentazione della memoria) come le altre risposte causano, ma è ancora un incidente. A mio parere, questo è molto più leggibile.

Un altro modo, se vogliamo imbrogliare e usare signal.h , è:

 #include  int main() { raise(SIGKILL); } 

Questo è garantito per uccidere il sottoprocesso, in contrasto con SIGSEGV.

 int* p=0; *p=0; 

Anche questo dovrebbe bloccarsi. Su Windows si blocca con AccessViolation e dovrebbe fare lo stesso su tutti i sistemi operativi che immagino.

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

Anche se questa domanda ha già una risposta accettata …

 void main(){ throw 1; } 

Oppure … void main(){throw 1;}

Questo è lo snippet fornito da Google in Breakpad.

  volatile int* a = reinterpret_cast(NULL); *a = 1; 

La scrittura su una memoria di sola lettura causerà un errore di segmentazione a meno che il sistema non supporti blocchi di memoria di sola lettura.

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

L’ho provato con MingGW 5.3.0 su Windows 7 e GCC su Linux Mint. Suppongo che altri compilatori e sistemi daranno un effetto simile.

O in un altro modo visto che siamo sul carro del gruppo.

Un bel pezzo di ricorsione infinita. Garantito per far saltare il tuo stack.

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

Stampa fuori:

Errore di segmentazione (core dumped)

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

Spero che questo si blocca. Saluti.

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

Un modo elegante per farlo è una pura chiamata di funzione virtuale:

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

Compilato con gcc, questa stampa:

metodo virtuale puro chiamato

terminare chiamato senza un’eccezione triggers

Aborted (core dumped)

Uno che non è stato ancora menzionato:

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

Questo tratterà il puntatore nullo come puntatore a funzione e quindi lo chiamerà. Proprio come la maggior parte dei metodi, non è garantito il crash del programma, ma le possibilità che il sistema operativo lo consenta di passare senza controllo e del programma che ritorna sempre sono trascurabili.

 char*freeThis; free(freeThis); 

Liberare un puntatore non inizializzato è un comportamento indefinito. Su molte piattaforms / compilatori, freeThis avrà un valore casuale (qualunque fosse in quella posizione di memoria prima). Liberandolo chiederà al sistema di liberare la memoria a quell’indirizzo, che di solito causerà un errore di segmentazione e farà crashare il programma.