2010-10-13 12 views
6

Ok, ho chiesto la differenza tra Stackoverflow e bufferoverflow ieri e ho quasi votato all'oblio e nessuna nuova informazione.Qual è lo scopo di ciascuna delle posizioni di memoria, stack, heap, ecc.? (perso in tecnicismi)

Quindi mi ha fatto riflettere e ho deciso di riformulare la mia domanda nella speranza di ottenere una risposta che risolva il mio problema.

Quindi qui non va nulla.

Sono a conoscenza di quattro segmenti di memoria (correggimi se ho torto). Il codice, i dati, lo stack e l'heap. Ora AFAIK il segmento di codice memorizza il codice, mentre il segmento di dati memorizza i dati relativi al programma. Ciò che mi confonde seriamente è lo scopo dello stack e del mucchio!

Da quello che ho capito, quando si esegue una funzione, tutti i dati relativi alla funzione vengono memorizzati nello stack e quando si richiama una funzione in modo ricorsivo all'interno di una funzione, all'interno di una funzione ... Mentre la funzione è in attesa dell'uscita della funzione precedente, la funzione e i dati necessari non escono dallo stack. Quindi finisci con un overflow dello stack. (Ancora una volta correggimi se ho torto)

Anche io so a cosa serve l'heap. Come ho letto da qualche parte, è per allocare dinamicamente i dati quando un programma è in esecuzione. Ma questo solleva più domande che risolvono i miei problemi. Cosa succede quando inizialmente inizializzo le mie variabili nel codice. Sono nel segmento di codice o nel segmento di dati o nell'heap? Dove vengono archiviati gli array? È che dopo che il mio codice è stato eseguito, tutto ciò che era nel mio heap viene cancellato? Tutto sommato, per favore dimmi di heap in un modo più semplice del solito, è per malloc e alloc perché non sono sicuro di capire completamente quali sono questi termini! Spero che le persone che rispondono non si perda nei tecnicismi e possa mantenere i termini semplici per un laico per capire (anche se il concetto da descrivere non è laico) e continua a educarci con i termini tecnici come noi andiamo d'accordo. Spero anche che questa non sia una domanda troppo grande, perché penso seriamente che non potrebbero essere chiesti separatamente!

+0

possibile duplicato di [Cosa e dove sono lo stack e l'heap] (http://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap) – Naveen

risposta

6

A cosa serve la pila?

Ogni programma è costituito da funzioni/subroutine/qualunque sia la lingua desiderata. Quasi sempre, queste funzioni hanno uno stato locale. Anche in un ciclo semplice, hai bisogno di un punto per tenere traccia del contatore del ciclo, giusto? Questo deve essere memorizzato da qualche parte.

Il problema delle funzioni è che l'altra cosa che fanno quasi sempre è chiamare altre funzioni. Queste altre funzioni hanno il loro stato locale - le loro variabili locali. Non vuoi che le tue variabili locali interferiscano con i locali del tuo chiamante. L'altra cosa che deve succedere è, quando FunctionA chiama FunctionB e quindi deve fare qualcos'altro, vuoi che le variabili locali in FunctionA siano ancora lì, e abbiano i loro stessi valori, quando FunctionB è fatto.

Tenere traccia di queste variabili locali è a cosa serve lo stack. Ogni chiamata di funzione viene eseguita impostando quello che viene chiamato un stack frame. Il frame dello stack include in genere l'indirizzo di ritorno del chiamante (per quando la funzione è terminata), i valori per qualsiasi parametro del metodo e l'archiviazione per qualsiasi variabile locale.

Quando viene chiamata una seconda funzione, viene creato un nuovo frame di stack, inserito nella parte superiore della pila e la chiamata viene eseguita. La nuova funzione può funzionare felicemente sul suo stack frame. Quando la seconda funzione ritorna, il suo stack frame viene fatto scoppiare (rimosso dalla pila) e il frame del chiamante è di nuovo posizionato come prima.

Quindi questo è lo stack. Allora, qual è il mucchio? Ha un uso simile - un posto dove archiviare i dati. Tuttavia, spesso c'è bisogno di dati che durino più a lungo di un singolo frame dello stack. Non può andare in pila, perché quando la chiamata alla funzione ritorna, il frame dello stack viene ripulito e boom: i dati vengono inviati. Quindi lo metti invece nell'heap. L'heap è un blocco di memoria fondamentalmente non strutturato. Chiedi il numero x di byte, e lo ottieni, e può quindi festeggiare su di esso. In C/C++, la memoria heap rimane allocata finché non viene deallocato esplicitamente. Nei linguaggi raccolti tramite garbage (Java/C#/Python/etc.) La memoria heap verrà liberata quando gli oggetti su di essa non verranno più utilizzati.

per affrontare le questioni specifiche dall'alto:

Qual è la differenza tra un overflow dello stack e un buffer overflow?

Sono entrambi casi di esecuzione su un limite di memoria. Un overflow dello stack è specifico per lo stack; hai scritto il tuo codice (la ricorsione è una causa comune, ma non l'unica) in modo che abbia troppe chiamate di funzioni nidificate, o stai memorizzando un sacco di cose grandi nello stack, e finisce fuori dalla stanza. La maggior parte dei sistemi operativi mette un limite alle dimensioni massime che lo stack può raggiungere e quando si raggiunge quel limite si ottiene lo stack overflow. L'hardware moderno è in grado di rilevare gli overflow dello stack e di solito è fatale per il tuo processo.

Un buffer overflow è leggermente diverso. Quindi prima domanda: cos'è un buffer? Bene, è un pezzo limitato di memoria. Quella memoria potrebbe essere in pila, o potrebbe essere in pila. Ma la cosa importante è che hai X byte che sai di avere accesso. Quindi scrivi del codice che scrive X + più byte in quello spazio. Il compilatore probabilmente ha già usato lo spazio oltre il tuo buffer per altre cose, e scrivendo troppo, hai sovrascritto quelle altre cose. Gli overrun del buffer spesso non si vedono immediatamente, poiché non li noti fino a quando non provi a fare qualcosa con l'altra memoria che è stata cestinata.

Inoltre, ricorda come ho menzionato che anche gli indirizzi di ritorno sono memorizzati nello stack? Questa è la fonte di molti problemi di sicurezza dovuti ai sovraccarichi del buffer. Hai codice che utilizza un buffer nello stack e ha una vulnerabilità di overflow. Un hacker intelligente può strutturare i dati che traboccano il buffer per sovrascrivere quell'indirizzo di ritorno, per puntare al codice nel buffer stesso, ed è così che ottengono il codice da eseguire. È brutto.

Cosa succede quando inizialmente inizializzare le variabili nel codice .. Sono nel segmento di codice o nel segmento di dati o nel mucchio?

Ho intenzione di parlare da una prospettiva C/C++ qui. Supponendo che tu abbia una dichiarazione di variabile:

int i;

Tale riserva (in genere) quattro byte sullo stack. Se invece si ha:

char * buffer = malloc (100);

Questo effettivamente riserva due blocchi di memoria. La chiamata a malloc alloca 100 byte nell'heap. Ma è necessario anche l'archiviazione per il puntatore, il buffer. Quella memoria è, ancora, in pila, e su una macchina a 32 bit sarà 4 byte (la macchina a 64 bit userà 8 byte).

Dove vengono memorizzati gli array ... ???

Dipende da come li si dichiara. Se si esegue un array semplice:

char str [128];

ad esempio, riserva 128 byte nello stack. C non colpisce mai l'heap a meno che non lo si chieda esplicitamente chiamando un metodo di allocazione come malloc.

Se invece si dichiara un puntatore (come il buffer sopra) la memoria per il puntatore è nello stack, i dati effettivi per l'array si trovano nell'heap.

È che dopo che il mio codice viene eseguito tutto ciò che era nel mio mucchio viene cancellato ... ???

Fondamentalmente sì. Il sistema operativo pulirà la memoria utilizzata da un processo dopo la sua uscita. L'heap è un frammento di memoria nel tuo processo, quindi il sistema operativo lo ripulirà. Anche se dipende da cosa intendi con "ripulisci". Il sistema operativo marca quei pezzi di RAM come ora gratuiti, e riutilizzerà in seguito. Se hai codice di pulizia esplicito (come i distruttori C++) dovrai assicurarti che vengano richiamati, il sistema operativo non li chiamerà per te.

Tutto sommato, per favore mi parli di heap in un modo più semplice del solito, è per malloc e alloc?

L'heap è, molto simile al suo nome, un mucchio di byte gratuiti che puoi prendere un pezzo alla volta, fare quello che vuoi, quindi tornare a usare per qualcos'altro. Afferri un pezzo di byte chiamando malloc e lo rinvii chiamando gratis.

Perché dovresti farlo?Beh, ci sono un paio di motivi comuni:

  1. Non sai quanti di una cosa è necessario fino fase di esecuzione (sulla base degli input dell'utente, per esempio). Pertanto, si assegna dinamicamente all'heap come necessario.

  2. Sono necessarie grandi strutture di dati. Su Windows, ad esempio, lo stack di un thread è limitato per impostazione predefinita a 1 meg. Se stai lavorando con grandi bitmap , ad esempio, questo sarà un modo rapido per far saltare lo stack e ottenere un overflow dello stack. Quindi prendi lo spazio dell'heap, che di solito è lo molto più grande dello stack.

Il codice, i dati, lo stack e l'heap?

Non proprio una domanda, ma volevo chiarire. Il segmento "codice" contiene i byte eseguibili per la tua applicazione. In genere i segmenti di codice vengono letti solo in memoria per impedire la manomissione. Il segmento dati contiene costanti che sono compilate nel codice: cose come le stringhe nel codice o gli inizializzatori di array devono essere memorizzati da qualche parte, il segmento di dati è dove vanno. Ancora, il segmento dati è in genere di sola lettura.

Lo stack è una sezione di memoria scrivibile e di solito ha una dimensione limitata. Il sistema operativo inizializzerà lo stack e il codice di avvio C chiamerà la funzione main() per te. L'heap è anche una sezione di memoria scrivibile. È riservato dal sistema operativo e funziona come malloc e gestisce gratuitamente i blocchi e li rimette a posto.

Quindi, questa è la panoramica. Spero che aiuti.

+0

Grande ... Mi aiuta davvero a capire la gestione della memoria in dettaglio .. –

+0

Come vengono gestite le variabili globali ... Non sono memorizzate nel segmento di dati? –

+0

Whoa è stata una lettura davvero lunga, ma sicuramente aiuta ... dovrà passare un paio di volte in cui affondare completamente, ma a questo è sicuramente risposto un bel po 'di domande! Tornerò indietro con dubbi qui come e quando vengono in mente :) Grazie. +1 – traumatized

0

In termini di programmi C/C++, il segmento di dati memorizza le variabili statiche (globali), lo stack memorizza le variabili locali e l'heap memorizza le variabili allocate dinamicamente (qualsiasi cosa è malloc o new per ottenere un puntatore). Il segmento di codice memorizza solo il codice macchina (la parte del programma che viene eseguita dalla CPU).

2

Riguardo allo stack ... Questo è esattamente dove vengono memorizzati i parametri e le variabili locali delle funzioni/procedure. Per essere più precisi, i parametri e le variabili locali della funzione attualmente in esecuzione sono accessibili solo dallo stack ... Altre variabili che appartengono alla catena di funzioni che sono state eseguite prima di essere nello stack ma non saranno accessibili fino alla funzione corrente completato le sue operazioni.

Per quanto riguarda le variabili globali, credo che queste siano memorizzate nel segmento di dati ed è sempre accessibile da qualsiasi funzione all'interno del programma creato.

Per quanto riguarda Mucchio ... Queste sono ulteriori memorie che possono essere fatte assegnato al vostro programma ogni volta che avete bisogno di loro (malloc o nuovo) ... Hai bisogno di sapere dove la memoria allocata è in mucchio (indirizzo/puntatore) in modo che tu possa accedervi quando ti serve. Nel caso in cui si perde l'indirizzo, la memoria diventa in-accessibile, ma i dati rimangono ancora lì. A seconda della piattaforma e della lingua, è necessario che venga liberato manualmente dal programma (o che si verifichi una perdita di memoria) o che sia necessario raccogliere i dati. L'heap è comparativamente enorme da impilare e quindi può essere utilizzato per memorizzare grandi volumi di dati (come file, flussi, ecc.) ...Ecco perché Oggetti/File vengono creati in Heap e un puntatore all'oggetto/file viene memorizzato nello stack.

+0

Grazie questo è byfar il modo più semplice in cui ho visto qualcuno metterlo :) BTW c'è anche un eccesso di heap? – traumatized

+0

Il "sovraccarico dell'heap" viene solitamente chiamato "memoria insufficiente". –