windows - Calling LoadLibrary fra DllMain

Indlæg af Hanne Mølgaard Plasc

Problem



MSDN siger: [4]



  Det må ikke kalde LoadLibrary eller LoadLibraryEx-funktionen
  (eller en funktion, der kalder disse funktioner),
  fordi dette kan skabe afhængighedsløkker i DLL-belastningsrækkefølgen.
  Dette kan medføre, at der bruges en DLL, før systemet har udført sin initialiseringskode.



Jeg forsøgte at ringe LoadLibrary fra DllMain og intet skete.


Det eneste problem, jeg ser er, at den indlæste DLL vil bruge funktioner i min DLL før resten af ​​mine DllMain udfører.


Hvorfor skal jeg ikke ringe LoadLibrary i DllMain?


EDIT:



OK, jeg indså, at jeg ikke må ringe LoadLibrary i DllMain bare fordi jeg skal tro MSDN som andre troende gør (jeg så nogle forkerte ting der, men jeg skulle også glemme dem).

Og fordi der kan ske noget i nyere versioner af Windows (selvom der ikke blev ændret i de sidste ti år).


Men kan nogen vise en kode, som vil gengive noget dårligt, hvad der sker, når LoadLibrary hedder DllMain? I et eksisterende Windows OS?

Ikke kun et opkald af en singleton-initialiseringsfunktion inde i en anden, men LoadLibrary i DllMain?

Bedste reference


Der er enkle, og endda ikke så enkle, omstændigheder, hvor kaldende LoadLibrary fra DllMain er helt sikkert. Men design er, at DllMain har tillid til ikke at ændre listen over indlæste moduler.


Selvom besiddelse af læsserlås faktisk begrænser, hvad der kan gøres i DllMain, er det kun indirekte relevant for LoadLibrary-reglen. Det relevante formål med læsserlås er serialise adgang til listen over indlæste moduler. Mens NTDLL virker på denne liste i en tråd, sikrer besiddelse af læsserlås, at listen ikke bliver ændret ved NTDLL-kode, der udføres i en anden tråd. Loader-lås er dog en kritisk sektion. Det gør ikke noget for at stoppe den samme tråd fra at genoptage læseren lås og ændre listen.


Dette ville ikke gøre noget, hvis NTDLL blev holdt helt til sig selv, mens man arbejdede på listen. NTDLL giver dog mulighed for at inddrage anden kode i dette arbejde, som ved initialisering af en nyligt indlæst DLL. Hver gang NTDLL kalder udenfor sig selv, mens man arbejder på listen, er der et valg at gøre for designet. Der er stort set to muligheder. Den ene er at stabilisere listen og frigive læseren lås, ringe udenfor, derefter erhverve loader lås og genoptage arbejde på listen som om fra bunden, fordi det eksterne opkald kan have ændret det. Den anden er at holde læseren lås og stoler på den kaldte kode ikke at gøre noget, der ændrer listen. Og således bliver LoadLibrary off-limits i DllMain.


Det er ikke sådan, at loader-lås gør noget for stop DllMain fra at kalde LoadLibrary eller endda at loader-låsen selv gør et sådant opkald usikkert. Det er i stedet, at ved at holde loader-lås NTDLL trusts DllMain ikke at ringe LoadLibrary.


I kontrast skal du overveje DllMain-reglen om ikke at vente på synkroniseringsobjekter. Her har låselåsen en direkte rolle i at gøre dette usikre. Venter på en synkroniseringsobjekt i DllMain opstiller muligheden for dødlås. Alt der behøves er, at en anden tråd allerede holder det objekt, du venter på, og så kalder denne anden tråd en funktion, der venter på loader-låsningen (fx LoadLibrary, men også sådanne funktioner som den tilsyneladende inokuøse GetModuleHandle).


Ønsker at strække eller bryde DllMain reglerne kan være uforskammet eller endda helt dumt. Jeg må dog påpege, at Microsoft i det mindste delvis skyldes, at folk spørger, hvor stærke eller meningsfulde disse regler er. Når alt kommer til alt, er nogle ikke altid blevet dokumenteret tydeligt og kraftigt, og da jeg sidst kiggede, var de stadig ikke dokumenteret i alle de situationer, hvor de helt sikkert behøvede. (Den undtagelse, jeg har i tankerne, er det i det mindste indtil Visual Studio 2005, MFC-programmører, der skrev DLL'er, blev bedt om at sætte deres initialiseringskode i CWinApp :: InitInstance, men blev ikke fortalt, at denne kode er underlagt DllMain-reglerne.)


Desuden ville det være lidt rigeligt for nogen fra Microsoft at tale som om DllMain-reglerne bør følges uden spørgsmål. Eksempler findes, hvor Microsofts egne programmører bryder reglerne, og fortsætter selv efter at bryde reglerne ses som at have forårsaget alvorlige virkelige problemer i verden.

Andre referencer 1


Dit argument for at gå videre med dette synes at være at omskrive:



  Microsoft siger ikke det her, men min
  Enkelt test tilfælde ser ud til at virke, derfor undlader jeg at se hvorfor ingen burde gøre det her.



Du arbejder under en stor antagelse: Du antager, at den underliggende implementering af Windows Loader aldrig vil ændre sig. Hvad hvis laderen er ændret i 'Windows 8' på en sådan måde, at din kode ikke længere fungerer korrekt? Nu Microsoft bliver skylden til det, og de skal også inkludere endnu en kompatibilitets hack til at arbejde rundt kode, som de fortalte dig ikke for at skrive i den første placere.


Følg vejledningen. De 'er ikke der bare for at gøre dit liv sværere, de' er der for at garantere, at din kode vil fungere lige så godt på fremtidens Windows som det gør nu.

Andre referencer 2


Som angivet i http://msdn.microsoft.com/en-us/library/ms682583\%28VS.85\%29.aspx:[5]



  Tråd i DllMain holder læsserlås, så ingen yderligere DLL'er kan indlæses eller initialiseres dynamisk.



Skål

Andre referencer 3


Jeg arbejdede på en sag, der kunne kræve brug af LoadLibrary i DllMain, så mens undersøgelsen fandt denne diskussion. En opdatering på dette fra min dagens oplevelse


At læse denne kan blive virkelig skræmmende http://blogs.msdn.com/b/oleglv/archive/2003/10/28/56142.aspx. Ikke kun forskellige låse betyder noget, men også den rækkefølge, hvor libs blev sendt til linkeren. Sagen er at sige en bi [6]


Nu har jeg prøvet dette med vc9 under win7. Ja, det er det. Afhængigt af rækkefølgen af, hvordan libs sendes til linkeren, fungerer LoadLibrary eller ej. Det samme med vc11 under win8 fungerer dog korrekt i betragtning af link ordre. Application Verifier gør ikke skyld i det.


Jeg opfordrer mig ikke til at bruge den på denne måde lige nu og overalt :) Men bare FYI, hvis det er det samme med win10 og videre - det kan være mere nyttigt. Under alle omstændigheder ser det ud til, at loader-mekanismen under win8 har gennemgået nogle mærkbare ændringer.


Tak.