2010-01-11 9 views
17

OK per qualsiasi motivo ho problemi a causare un errore di seg. Voglio produrne uno in modo da poter usare gdb per vedere come eseguire il debug di uno. Ho provato entrambi gli esempi dall'articolo the Wikipedia ma nessuno dei due ha funzionato.Perché non posso causare un errore di seg?

Il primo:

char *s = "Hello World!"; 
*s = 'H'; 

E il secondo esempio:

int main(void) 
{ 
    main(); 
} 

EDIT: sto usando Ubutnu 9.10 e g++ come il mio compilatore. Qualcuno può mostrarmi un codice che è garantito per segfault?

+2

Il comportamento del codice di cui sopra non è definito, il che significa che può fare qualsiasi cosa vuole, incluso "sembrare lavorare", o causare demoni nasali. :-) –

+1

try char * = reinterpret_cast (0x1234); p [0] = 'H'; –

+13

Se vuoi causare un errore di seg, potrei mandarti alcuni dei programmi C++ che ho scritto al college :-) – ristonj

risposta

37

E impossable per cercare di affidabilità fanno dereferencing puntatori.
Questo perché il modo in cui l'applicazione gestisce la memoria può variare dal compilatore al compilatore anche attraverso lo stesso compilatore con diverse opzioni (modalità di debug/rilascio gestita in modo diverso).

Che cosa si può fare è sollevare esplicitamente il segfault utilizzando un segnale:

#include <signal.h> 

int main() 
{ 
    raise(SIGSEGV); 
} 
+0

Non è corretto affermare che "È impossibile provare e fare affidamento sui puntatori di dereferenziamento". - puoi utilizzare i test e l'analisi del tuo codice per stabilire che esso sia sicuro in modo affidabile. – user1976

+0

@ user1976: A quanto pare non si capisce cosa significhi un comportamento indefinito. –

+0

@ Loki Astari: Un comportamento indefinito significa che (molto) recenti compilatori (il clang è il peggiore autore di reati) si sentono liberi di essere fastidiosi e di cancellare il proprio codice. Tuttavia, ciò non significa che il codice generato non possa essere invocato per mostrare un comportamento ben definito. Devi semplicemente fare affidamento su un altro metodo, al di fuori dello standard C++, per garantirlo. – user1976

1
char * ptr = 0; 
*ptr = 1; 

Segmentation fault 
2
int *hello = NULL; 
printf(*hello); 

oppure si può definire una struct (dire struct HelloWorld)

HelloWorld *myWorld = NULL; 
myWorld->world = "hello"; 
5

Entrambe le cose che si fanno produrrà "un comportamento indefinito" in C++ (beh, chiamando main() è in realtà esplicitamente vietato). Non vi è alcuna garanzia che causeranno errori di segmentazione - ciò dipenderà da molte cose, ma principalmente dalla piattaforma su cui state lavorando, che non avete specificato.

In effetti, il metodo suggerito di causare un errore di seg può o non può funzionare nel metodo qualsiasi. Questo perché un errore seg è quasi sempre associato al concetto di comportamento non definito del C++.

+4

È un comportamento non definito dal punto di vista della lingua, ma il sistema operativo probabilmente definisce le condizioni in cui si verifica un errore di segmentazione ed è possibile forzare tali condizioni in C++. (Esempio: 'int * p = 0; while (true) * p ++ = 10;' a un certo punto o un altro colpiscono un segmento di memoria che non è scrivibile dal processo e sotto linux o macosx attiverà un errore di segmentazione) –

2

Un sacco di modi per generare un segfault.

Come dereferenziazione un puntatore errato:

char *s = (char *)0xDEADBEEF; 
*s = 'a'; 
+0

'0xDEADBEEF' è un numero. "Hello World" è una stringa. In questo caso, 's' finisce per puntare all'indirizzo di memoria' 0xDEADBEEF', che è (molto probabilmente) completamente non valido. Nell'esempio dell'OP, 's' finisce per contenere l'indirizzo della stringa - se il compilatore non ha dichiarato la memoria come di sola lettura, nessun errore risulta se proviamo a scriverci. –

+1

Prova 0xBADBADBAD - davvero, davvero, davvero male – user1976

16

mio sapore di una riga:

*(char *)0 = 0; 
+3

Anche questo non è garantito per produrre un segfault. È solo un comportamento indefinito. Quale può o non può funzionare. –

+2

@Martin - garantito su tutte le piattaforme, no. Ciò causerà un segfault su Ubuntu Linux, sì. –

+0

@R: non puoi garantirlo! Perché pensi che Ubunt sia così speciale! Affidarsi a comportamenti non definiti per fare qualcosa di speciale è solo chiedere di bruciare piuttosto male ad un certo punto lungo la strada. È descritto come non definito per una ragione. Non farlo se non sai esplicitamente cosa succederà e non lo fai. –

1

L'articolo di Wikipedia in realtà elenca tre metodi (uno dei quali è un puntatore nullo); perché non hai provato quello?

Per quanto riguarda il motivo per cui i due esempi che hai provato non lo hanno, beh, la risposta corretta, come altri hanno notato, è che è un comportamento indefinito, quindi potrebbe accadere qualsiasi cosa (che include non segfaulting). Ma si potrebbe ipotizzare che il motivo per cui il primo modulo non ha fallito per te è perché il tuo compilatore o il tuo sistema non è sicuro della protezione della memoria. Per quanto riguarda il secondo caso, un compilatore coda-ricorsivo-coscientemente in grado di ottimizzare il ciclo infinitamente ricorsivo main e non finire traboccare lo stack.

2

Per il primo esempio, il compilatore probabilmente inserisce la stringa nella memoria scrivibile, quindi non vi è alcun errore di seg quando si tenta di cambiarlo.

Per il secondo, il compilatore potrebbe ottimizzare la chiamata o potrebbe ottimizzare la chiamata da solo a un salto (poiché è un tail call), il che significa che lo stack non cresce effettivamente con gli indirizzi di ritorno per ogni chiamata , quindi potresti recitare all'infinito.

Ma come Neil ha menzionato nel suo post, una di queste cose risulta in "comportamento non definito", quindi il codice non è richiesto in fase di esecuzione per generare un errore di seg.

1

Se si tenta di concatenare due costanti ... ne otterrai uno ...almeno è un modo semplice ...

strcat ("a", "b");

=)

+1

solo se i valori letterali sono allocati nella memoria di sola lettura. Che apparentemente non è nel suo caso, o la sua manipolazione delle stringhe avrebbe causato un segfault in primo luogo. – jalf

+0

In realtà, strcat ("seg", "fault"); è garantito per produrre un segfault. – user1976

5

segfault più breve mai:

*(int*)0=0; 
+29

molto più breve: '* (breve *) 0 = 0' lol – smerlin

+1

@smerlin: +1 per l'umorismo sottile. –

Problemi correlati