2012-05-30 9 views
16

Sono nuovo alla programmazione di Windows e ho appena "perso" due ore a caccia di un bug di cui tutti sembrano a conoscenza: non è possibile creare un oggetto sull'heap in una DLL e distruggerlo in un'altra DLL (o nella principale programma).Le DLL (collegate in modo statico) utilizzano un heap diverso rispetto al programma principale?

Sono quasi sicuro che su Linux/Unix questo NON è il caso (se lo è, per favore dillo, ma sono abbastanza sicuro di averlo fatto migliaia di volte senza problemi ...).

A questo punto ho un paio di domande:

1) Se le DLL collegate staticamente utilizzare un mucchio diverso rispetto al programma principale?

2) La DLL collegata staticamente è mappata nello stesso spazio del processo del programma principale? (Sono abbastanza sicuro che la risposta qui è un grande SÌ altrimenti non avrebbe senso passare i puntatori da una funzione nel programma principale a una funzione in una DLL).

sto parlando plain/DLL regolare, non servizi/COM ATL

EDIT: Con il termine "legato staticamente" voglio dire che io non uso LoadLibrary per caricare la DLL, ma ho legame con la libreria di stub

+3

Dipende dalle impostazioni per ciascun modulo. Generalmente, se due moduli utilizzano il CRT dinamico, condividono l'heap poiché entrambi hanno la stessa istanza del CRT caricato. Se un modulo utilizza il CRT statico, ha il suo heap poiché ha una propria istanza del CRT collegata staticamente. – Luke

+1

@Luke - Inoltre, è possibile che diversi moduli utilizzino versioni diverse del CRT dinamico (DLL), e quindi diversi cumuli. – Bukes

+0

Praticamente ogni DLL non banale dovrà _ creare il proprio heap, se ci pensate. Prendi la libreria OpenAL come esempio. È possibile alimentare i dati su un oggetto buffer (la lib crea la propria copia dei dati), impostare alcuni parametri e la libreria riprodurrà il suono: grande, facile, perfetto, senza preoccupazioni. Ora immagina che _two_ programmi caricino la libreria. Dove mettere i dati, chi è il proprietario? In quale parte della RAM fisica si trova? Voglio che "qualche altro programma" sia in grado di vedere (o modificare) i dati sull'heap del mio programma? Se vive sull'heap del tuo modulo principale, sei nei guai ... – Damon

risposta

16

Le DLL/ex devono essere collegate a un'implementazione delle librerie di runtime C.

In caso di librerie C di Windows Runtime, si ha la possibilità di specificare, se si desidera collegare al seguente:

  1. libreria di tempo a thread singolo C Run (supporto per le librerie a thread singolo, è stato interrotto ora)
  2. DLL di debug multi-thread/DLL multi-threaded
  3. Librerie di runtime statiche.
  4. qualcuno in più (È possibile controllare il link)

Ognuno di loro si riferirà a un cumulo diverso, quindi non ti è permesso indirizzo passaggio ottenuto dal cumulo di una libreria di runtime ad altri.

Ora, dipende da quale libreria di runtime C è stata collegata la DLL di cui si sta parlando. Supponiamo di dire che la DLL che stai usando è stata collegata alla libreria di run time statica C e che il codice dell'applicazione (contenente la funzione principale) è collegato a una DLL di C Runtime multi-thread, quindi se passi un puntatore alla memoria allocata nella DLL al tuo programma principale e prova a liberarlo lì o viceversa, può portare a un comportamento indefinito. Quindi, la causa principale di base sono le librerie di runtime C. Si prega di scegliere con attenzione.

Si prega di trovare maggiori informazioni sulle librerie di tempo C esecuzione supportata here & here

Una citazione da MSDN:

AttenzioneNon mescolare le versioni statiche e dinamiche delle librerie di runtime. Avere più di una copia delle librerie di runtime in un processo può causare problemi, perché i dati statici in una copia non sono condivisi con l'altra copia. Il linker ti impedisce di collegarti con versioni sia statiche che dinamiche all'interno di un file .exe, ma puoi ancora finire con due (o più) copie delle librerie di runtime.Ad esempio, una libreria a collegamento dinamico collegata alle versioni statiche (non DLL) delle librerie di runtime può causare problemi se utilizzata con un file .exe collegato alla versione dinamica (DLL) delle librerie di runtime . (Si dovrebbe anche evitare di mischiare le versioni debug e non-debug delle librerie in un unico processo.)

+0

Sto parlando di qualsiasi tipo di DLL, non necessariamente quelle che contengono il codice runtime C – Emiliano

+1

Perché ogni variante di RTL dovrebbe usare heap diversi? – osgx

+0

Capisco il problema ora. Ma passare un puntatore oltre i confini del modulo dovrebbe essere sicuro, giusto? (purché l'oggetto non sia stato distrutto nel frattempo, naturalmente e fintanto che sia il programma principale che la DLL sono compilati con lo stesso compilatore) – Emiliano

3

Se ho un'applicazione che compila come .exe e voglio usare una libreria, posso sia collegarla staticamente che libreria da un file .lib o collegata dinamicamente a quella libreria da un file .dll.

Ogni modulo collegato (ie. Ogni exe o dll) saranno collegati ad un'implementazione del C o C++ tempi di esecuzione. I tempi di esecuzione stessi sono una libreria che può essere collegata staticamente o dinamicamente e venire in diverse configurazioni di threading.

Dicendo DLL collegate staticamente stai descrivendo un set up in cui un'applicazione collega .exe dinamicamente a una dll biblioteca e quella libreria collega internamente in modo statico al runtime? Assumerò che questo è ciò che intendi.

Vale anche la pena notare che ogni modulo (.exe o .dll) ha il proprio ambito per la statica, ovvero una statica globale in un file .exe non avrà la stessa istanza di una statica globale con lo stesso nome in un file .dll .

Nel caso generale, pertanto, non è possibile presumere che il codice in esecuzione all'interno di diversi moduli stia utilizzando la stessa implementazione del runtime, inoltre non utilizzeranno la stessa istanza di uno stato statico.

Pertanto certe regole devono essere rispettate quando si tratta di oggetti o puntatori che attraversano i confini del modulo. Le allocazioni e le deallocazioni devono essere eseguite nello stesso modulo per ogni dato indirizzo. Altrimenti gli heap non corrisponderanno e il comportamento non verrà definito.

COM risolve questo questo conteggio di riferimento utilizzando, oggetti eliminare stessi quando il conteggio di riferimento raggiunge lo zero. Questo è un modello comune utilizzato per risolvere il problema della posizione corrispondente.

Altri problemi possono esistere, ad esempio finestre definiscono determinate azioni, ad es. in che modo i problemi di allocazione sono gestiti su base per thread, non su base modulo. Ciò significa che il codice in esecuzione nel modulo A in una configurazione di thread dal modulo B può anche essere eseguito in un comportamento imprevisto.

2

Iniziamo a capire l'allocazione dell'heap e lo stack su Windows OS rispetto alle nostre applicazioni/DLL. Tradizionalmente, il sistema operativo e le librerie di runtime vengono fornite con un'implementazione dell'heap.

  1. All'inizio di un processo, il sistema operativo crea un heap predefinito chiamato heap del processo. L'heap del processo viene utilizzato per allocare i blocchi se non viene utilizzato nessun altro heap.
  2. I tempi di esecuzione della lingua possono anche creare heap separati all'interno di un processo. (Ad esempio, C run time crea un heap proprio.)
  3. Oltre a questi heap dedicati, il programma applicativo o una delle numerose librerie (DLL) a collegamento dinamico possono creare e utilizzare heap separati, chiamati heap privati ​​
  4. Questi heap si trovano in cima al gestore di memoria virtuale del sistema operativo in tutti i sistemi di memoria virtuale.
  5. Parliamo di più su CRT e cumuli associati:
    1. C/C++ Run-time (CRT) allocatore: Fornisce malloc() e free(), così come gli operatori new e delete.
    2. Il CRT crea un tale heap aggiuntivo per tutte le sue allocazioni (l'handle di questo heap CRT è memorizzato internamente nella libreria CRT in una variabile globale denominata _crtheap) come parte della sua inizializzazione.
    3. CRT crea il proprio heap privato, che si trova in cima all'heap di Windows.
    4. L'heap di Windows è un sottile strato che circonda l'allocatore di run-time di Windows (NTDLL).
    5. L'allocatore di run-time di Windows interagisce con Virtual Memory Allocator, che riserva e impegna le pagine utilizzate dal sistema operativo.

La DLL e EXE collegamento a librerie CRT statiche multithread. Ogni DLL e exe che si creano ha un proprio heap, ad esempio _crtheap. Le allocazioni e le de-allocazioni devono avvenire dal rispettivo heap. Quella allocata dinamicamente dalla DLL, non può essere deselezionata dall'eseguibile e viceversa.

Cosa si può fare? Compilare il nostro codice in DLL e exe utilizzando/MD o/MDd per utilizzare la versione specifica per il multithread e la DLL della libreria di runtime. Quindi sia DLL che EXE sono collegati alla stessa libreria di runtime C e quindi a _crtheap. Le allocazioni sono sempre associate alle de-allocazioni all'interno di un singolo modulo.

+0

Anche se su Linux, non sono sicuro di cosa succede quando si collega la libreria di runtime di Static C con la DLL (SharedLibrary) e exe? Anche lì affronteremo lo stesso problema? –

Problemi correlati