Blogul gunsmoker (traducerile) sunt încă motive pentru care nu trebuie să faci nimic rău în dllmain aleatoriu

Mai multe motive pentru care nu trebuie să faceți nimic rău cu DllMain: blocare aleatorie

Funcția dvs. DllMain funcționează în interiorul blocării încărcătorului de încărcare - acesta este unul dintre puținele momente când sistemul de operare permite executarea codului dvs. când blocarea internă este ținută.





Aceasta înseamnă că codul dvs. trebuie să fie foarte atent pentru a nu rupe ierarhia de blocare în DllMain; altfel sunteți amenințați de un impas.

(Ai o astfel de ierarhie, nu?).

Blocarea încărcătorului OS este necesară pentru orice funcție care are nevoie de acces la lista DLL-urilor încărcate în proces. Aceasta include funcții precum GetModuleHandle și GetModuleFileName. Dacă DllMain dvs. intră în secțiunea critică sau de așteptare pe un obiect de sincronizare, iar secțiunea critică sau a unui obiect de sincronizare deținut (deținut) un alt fir, care, la rândul său, de așteptare pentru eliberarea bloca bootloader, tocmai ai creat un sistem de blocare mort (impas ): Acum, imaginați-vă că un fir execută cu fericire primul bloc de cod și intră în csGlobal, apoi controlul este transmis altcuiva. În acest moment, un alt fir își termină activitatea. În acest caz, încărcătorul este blocat și mesajul DLL_THREAD_DETACH este trimis (blocarea încărcătorului este ținută în acest moment).







Obțineți DLL_THREAD_DETACH și încercați să introduceți csGlobal. Acest lucru este blocat de primul fir, care deține acum secțiunea critică. Apoi acest thread continuă execuția și apelează GetModuleFileName. Această funcție necesită blocarea încărcătorului de boot (deoarece are nevoie de acces la lista DLL-urilor încărcate în proces), astfel încât firul este blocat deoarece altcineva blochează încărcătorul de boot.

Acum aveți un impas:
  • csGlobal deține primul fir, care așteaptă blocarea încărcătorului de boot.
  • Al doilea fir, care așteaptă csGlobal, are blocarea încărcătorului de încărcare.
Am văzut cum sa întâmplat. Și nu este nimic frumos în asta.

Moralul povestirii: nu uita de blocarea încărcătorului. Includeți-l în ierarhia de blocare dacă doriți să utilizați orice încuietori în DllMain.

Aparent, nu am o teorie bună.
Alexander, am înțeles corect că începutul / sfârșitul blocului fără nume, care se întâmplă de obicei în codul bibliotecii - aceasta este, în mod figurat vorbind, procedura DllMain? În ce, în general, este diferența dintre DllMain și DllProc și în ce ordine sunt executate?

Blocul de început / sfârșit din fișierul .dpr DLL este destul de complicat. Aceasta este partea "DllMain", dar numai pentru DLL_PROCESS_ATTACH.

DllEntryPoint este conceptul de API Windows. De fapt, acesta este punctul de intrare la modulul (IMAGE_OPTIONAL_HEADER.AddressOfEntryPoint). Pentru exe, acesta este un pointer la prima instrucțiune care va fi executată. DllEntryPoint nu este exportat și nu are un nume simbolic. "DllEntryPoint" este doar un set de litere care indică un concept. Pentru un DLL, acesta este un indicator al unei funcții care va servi drept "DllMain". În limbile de programare la nivel înalt, codul bibliotecii de limbă (RTL) este întotdeauna folosit drept punct de intrare (inclusiv cazul cu DllMain). În special, în Delphi pentru programe va fi _InitExe, iar pentru DLL - _InitLib. În C ++, acesta va fi _DllMainCRTStartup (pentru DLL).

DllMain este conceptul de RTL C ++. Aceasta este o funcție care este apelată de la DllEntryPoint (_DllMainCRTStartup), dar nu este încă scrisă - este responsabilitatea programatorului să o scrie. Funcția trebuie să aibă același nume, altfel nu va fi găsită de linker.

DllProc este conceptul de RTL Delphi. Acesta este un indicator normal al funcției (apel invers, eveniment). Se numește din DllEntryPoint (_InitLib). DllProc pointer în sine este numit, dar funcția la care puncte pot fi orice nume - DllProc, DllMain, DllEntryPoint, MySuperDuperHandler. Implicit (și în 99% din cazuri) DllProc nu este completat și = zero.

Ce este confuz aici, DllMain nu există în Delphi, acesta este conceptul de RTL C ++. DllMain este descris în MSDN, deoarece MSDN vorbește despre C ++. De fapt, toate "din obiceiuri" copiază acest nume, deși în contextul Delphi este mai corect să vorbim doar despre DllEntryPoint și DllProc.

În orice caz, lanțul de apeluri la încărcarea / descărcarea DLL Delphi merge astfel:
- LoadLibrary -> Kernel32 / Ntdll (undeva in interiorul vine aderenta încărcător de boot secțiunea critică) -> _InitLib (aka DllEntryPoint) -> InitializeModule (numai DLL_PROCESS_ATTACH) -> _StartLib -> DllProc (dacă este cazul) -> InitUnits -> secțiunea inițializarea modulelor -> revenire la începutul / sfârșitul .dpr -> ieșire din _InitLib.
- FreeLibrary -> Kerenel32 / Ntdll (undeva in interiorul vine aderenta încărcător de boot secțiunea critică) -> _InitLib (aka DllEntryPoint) -> _StartLib -> DllProc (dacă este cazul) -> _Halt0 -> FinalizeUnits -> testarea secțiunilor modulelor de finalizare -> ieșire de la _InitLib.







Trimiteți-le prietenilor: