2009-11-17 14 views
5

Si ottiene uno strano risultato nel seguente codice C.malloc() e memoria heap

int main() 
{ 
    int *p = (int *) malloc(100); 
    p[120] = 5; 
    printf("\n %d", p[120]); 
} 

Poiché ho assegnato solo 100 byte, questo codice dovrebbe causare un errore di segmentazione. Tuttavia, stampa "5" e non fornisce alcun errore di runtime. Qualcuno può spiegare la ragione?

+4

Probabilmente sono stato fortunato. –

+5

Hai scritto un 5 in un posto che non ti apparteneva. Se il proprietario di quel posto non ha gradito quello che hai fatto a casa sua, otterrà la sua vendetta. ** Attenzione **, potrebbe appartenere al driver del disco USB e formatterà la prossima unità inserita. – pmg

+4

@pmg: Realisticamente, non è molto probabile in un moderno sistema operativo in modalità protetta. – bcat

risposta

20

No, il codice non deve (necessariamente) fornire un segfault. Un segfault si verifica quando si tenta di accedere a una pagina di memoria virtuale che non è allocata al processo.

"heap" o "negozio gratuito" è un'area di pagine di memoria virtuale di proprietà del processo. L'API malloc() suddivide questa regione in blocchi e restituisce un puntatore al blocco.

Se si indirizza oltre la fine del blocco a cui si ha un puntatore, di solito si accede alla memoria che fa parte dell'heap, ma non parte del blocco assegnato. In questo modo, è possibile corrompere altri blocchi heap o anche le strutture dati utilizzate da malloc() per definire l'heap.

Per ulteriori informazioni sulla corruzione heap, e metodi per rilevare nella versione di debug del codice, questo è un grande libro:

Writing Solid Code: Microsoft's Techniques for Developing Bug-Free C Programs by Steve Maguire alt text http://ecx.images-amazon.com/images/I/5148TK6JCVL._BO2,204,203,200_PIsitb-sticker-arrow-click,TopRight,35,-76_AA240_SH20_OU01_.jpg

un addendum per il saccente: In rari casi , accedendo alla memoria oltre la fine di un blocco heap, è possibile accedere alla memoria che non fa parte dell'heap. In questi casi, potresti ricevere il difetto di segmentazione che ti aspettavi. Potresti anche corrompere qualche altra struttura di dati rispetto all'heap. È davvero una questione di fortuna. Tuttavia, l'heap stesso è molto grande rispetto ai blocchi heap tipici, quindi il 99% del time code come l'esempio danneggia l'heap. L'esempio che fornisci rientra nel caso del 99%.

+0

In realtà, dal momento che ha chiesto di cambiare 20 byte oltre la fine dello stack, a seconda dell'architettura e del codice circostante, poteva invece filtrare lo stack, o addirittura modificare il programma stesso. Il comportamento è veramente indefinito. –

+2

T.E.D. Questo è solo "un po '" vero. Sicuramente sta usando una macchina con una dimensione di pagina di memoria virtuale. Il codice presumibilmente eseguibile ha una protezione VM diversa dall'heap. Scommetto che si trova su un sistema del genere perché esiste la funzione malloc() della libreria C standard. Ciò che scrivi è vero, tuttavia, in particolare su Radio Shack Model III che esegue TRS-DOS su uno Z-80. ;) –

+0

E sì, anche su un sistema di pagine VM, ciò che si scrive potrebbe accadere. Non è così probabile e non è molto pedagogico entrare in quel dettaglio che raramente conta. Affrontare il problema al livello in cui è dichiarato. Evita la pedanteria. –

0

Stai scrivendo in memoria che non hai assegnato. Il programma potrebbe terminare a causa degli effetti della corruzione dell'heap se il tempo di esecuzione fosse sufficientemente lungo.

6

Gli accessi non validi alla memoria non causano sempre un errore di segmentazione, errore del bus o altri arresti anomali. Ad esempio, se c'è un altro blocco assegnato immediatamente dopo l'array, stai modificando i valori in del blocco, che potrebbe essere qualsiasi cosa.

0

Stai scrivendo nella memoria non inizializzata; questo è permesso in C, non è solo una buona idea. Questo tipo di cose non dovrebbe necessariamente causare un errore di segmentazione.

+2

L'uso della parola "consentito" è fuorviante. È sintatticamente valido, ma invoca un comportamento indefinito. –

3

No, è possibile dare un segfault, ma solo se la memoria è al di fuori del processo. Altrimenti modificherà solo qualche altra area della memoria del programma. C non controlla questo o ti protegge in alcun modo, anche in casi ovvi come sopra. Molti cracker di software utilizzano questa "caratteristica" di C per riscrivere essenzialmente un programma che ha privilegi elevati e si dà il controllo sulla macchina. Si chiama buffer overflow exploit.

Questo è il motivo per cui C (e C++) dovrebbero essere evitati per i nuovi software, preferibilmente per linguaggi più sicuri come Ada.

+1

So che l'ultima frase mi farà votare in negativo. Non mi interessa È vero. –

+0

+1 da parte mia. Sono completamente d'accordo. – lesscode

0

cause comuni di errore di segmentazione:

  • dereferenziazione puntatore con valore non valido
  • dereferencing puntatori nulli
  • tentativo di scrivere in una sola lettura segmento
  • puntatori impropri free-ing o non blocchi di proprietà.

    int * x = 0;

    x = 200;/ cause errore di segmentazione */

segfaults sono generati da eccezioni MMU sulla base di ciò che è determinato a essere un accesso alla memoria illegale. A seconda di come il sistema operativo struttura la sua memoria, un accesso di memoria su un sistema operativo potrebbe essere legale (anche se sbagliato) e su un altro sistema operativo potrebbe essere illegale.

+0

Questo è in ritardo, ma ... x = 200 sta bene, * x = 200 porta a segfault. –