DLL peklo
DLL peklo (anglicky DLL hell) je označení pro komplikace, které v operačním systému Microsoft Windows způsobuje používání dynamických knihoven (DLL) – nemožnost spuštění některých programů kvůli chybějícím knihovnám, chybné fungování programů kvůli nekompatibilním verzím knihoven nebo hromadění nevyužívaných knihoven a jejich verzí. Problémy byly závažné zejména u starší 16bitové verze, ve které všechny aplikace používají stejný paměťový prostor. DLL peklo je konkrétní forma obecného problému závislostního pekla (anglicky dependency hell).
Problémy
editovatPoužívání DLL knihoven přináší kromě výhod (znovupoužitelnost kódu, zmenšení obsazené paměti, standardizace vzhledu a chování aplikací) také problémy, které narůstají s množstvím instalací a odinstalací aplikací. Problémy způsobené nejednoznačnou korespondencí mezi aplikacemi a knihovnami se projevují konflikty mezi knihovnami, shánění knihoven až po spoustu nevyužívaných kopií knihoven. Problém se zvyšuje množstvím aplikací používajících stejné knihovny, jejich nekoordinovaným vývojem, nezralostí knihoven, nedostatkem informací o správných postupech a nevhodným používáním softwarových balíčků.
Nekompatibilní verze
editovatUrčitá verze knihovny může být kompatibilní s určitými verzemi softwaru, které ji používají. Bohužel nemusí být kompatibilní s jinými verzemi softwaru. Windows byl zvláště zranitelný, protože kladl velký důraz na dynamické linkovaní C++ knihoven a OLE objektů. C++ třídy obsahovaly velké množství metod a malá změna v jedné z jejich mohla způsobit nekompatibilitu s programy, které ji využívaly. Linkování a propojování objektů má řadu striktních pravidel, aby se právě tomuto zabránilo. Například používání rozhraní, která se nesmí měnit, nebo nepoužívání sdílené paměti. Ani to však není dostatečné, protože fungování uvnitř třídy může být stále změněno. Úprava knihovny může být pro jednu aplikaci opravou chyby, pro jinou odstranění důležité funkčnosti. Systém Windows před verzí Windows 2000 byl v tomto ohledu velmi citlivý, protože COM tabulka tříd byla sdílena všemi uživateli a procesy. V COM objektu bylo pro každou DLL/EXE knihovnu vytvořeno pouze jedno specifické COM ID. Pokud nějaký program potřeboval vytvořit instanci dané třídy nebo knihovny, použila se knihovna z centralizovaného úložiště. Naopak když se nainstaloval nový program, stará verze knihovny byla odstraněna a nainstalovala se verze s novým programem. Důsledkem toho bylo že instalací nového programu přestal fungovat ten starý.
DLL podupávání
editovatProblém DLL podupávání (anglicky DLL stomping) nastal, když nový program přehrál jinému programu starou funkční DLL knihovnu novou knihovnou, se kterou starý program nedokázal fungovat. Častým problémem byly knihovny ctl3d.dll
a ctl3dv2.dll
pro Windows 3.1. Dodavatelé mohli používat ve svých aplikacích Microsoftem vytvořené knihovny, ale raději ke svým programům přidávali knihovny vlastní. Dupání DLL se objevilo z důvodů:
- Microsoft distribuoval runtime DLL knihovny jako systémové komponenty (původně v C:\WINDOWS a C:\WINDOWS\SYSTEM). Tím ušetřil místo v paměti, proto knihovny byly sdílené. To mělo smysl u strojů, které měly malou paměť.
- Instalátory aplikaci jsou typicky spuštěny v privilegovaném kontextu, který má přístup k instalaci DLL knihoven do systémových adresářů a má také přístup do registrů, kde může nové DLL knihovny registrovat jako COM objekty. Špatně napsaný instalátor může nainstalovat starší verzi systémové DLL knihovny a nic ho v tom nezastaví. Ve Windows Vista a vyšších to může provést pouze instalátor, který je označen jako důvěryhodný nebo si vyžádá administrátorské heslo.
- Aplikacím ve Windows bylo povoleno, aby v rámci svých instalací stahovaly aktualizace operačního systému. Pokud tedy nějaká aplikace potřebovala knihovnu, začlenila si ji k sobě už při instalaci.
- Před vydáním Windows Installeru existovaly pouze komerční programy, které instalátor zastupovaly a spousta lidí si začala psát vlastní instalátory. Bohužel ne všichni znali pravidla, jakými by se instalátory měly řídit. Tím se do operačního systému dostávaly různé verze DLL knihoven.
- Některá vývojová prostředí automaticky nepřidávala verzi knihovny ke svým kompilovaným knihovnám a spousta vývojářů na to taky zapomínala. Tím se opět dostaly do systému knihovny, které neodpovídaly ve verzi, které softwary potřebovaly.
- Občas operační systém DLL knihovnu odstranil nebo nahradil starší nebo zastaralou verzí. Například systém Windows 2000 nahradil ovladač barevné tiskárny ovladačem černobílé tiskárny, pokud byla barevná tiskárna nainstalována první.
Nesprávná COM registrace
editovatV COM objektech a další částech Microsoft Windows je důležité, aby si všechny aplikace mohly registrovat svoje komponenty. Registry byly určeny pro to, aby řekly, která DLL se má ve výsledku použít. Pokud ovšem byla v registrech zapsána jiná DLL (jiná verze), tak program dostal knihovnu, která pro něj byla nefunkční. Toto se stalo, pokud jedna aplikace při instalaci přepsala jinému programu verzi knihovny, která měla sice stejné jméno, ale jinou verzi.
Sdílené paměťové moduly
editovatVšechny 16bitové verze Windows pro DOS načítají jen jednu instanci každé DLL knihovny. Všechny aplikace odkazují na jednu kopii v operační paměti, a teprve když ji žádná aplikace nepoužívá, je DLL z paměti uvolněna. V řadě Windows NT (32bitové i 64bitové) dochází ke sdílení knihoven mezi procesy pouze v případě, že různé spustitelné soubory načítají DLL modul ze stejného adresáře a souboru. Sdílí se pouze výkonný kód, nikoliv však zásobník. Sdílení kódu mezi procesy je zajištěno mechanismem mapováním paměti (anglicky memory mapping), takže i když je požadovaná DLL knihovna umístěná v adresáři, kde je očekáváno její umístění, jako například v systémovém adresáři nebo v adresáři aplikace, sdílení se nepoužije, když jiná aplikace začala používat nekompatibilní verzi z jiného adresáře. Tento problém se může projevovat jako chyba 16bitové aplikace, ke které dochází pouze tehdy, když se aplikace spustily ve určitém pořadí.
Nedostatek provozuschopnosti
editovatV přímém rozporu s problémem DLL podupávání: Pokud aktualizace DLL nemá vliv na všechny aplikace, které ji používají, tak se DLL knihovny stávají těžší na správu, což znamená k odstranění problémů, které se vyskytují v současných verzích DLL (bezpečnostní opravy jsou zvláště přesvědčivý a bolestivý případ). Místo použití pouze nejnovější verze DLL, musí implementace v ideálním případě opravit problémy a otestovat jejich kompatibilitu na každé vydané verzi DLL.
Příčiny
editovatNekompatibilitu DLL způsobuje:
- Nedostatek operační paměti v kombinaci s neoddělením paměti procesů v 16bitových verzích Windows.
- Nepřítomnost vynuceného standardního verzování, tj. pojmenování a systémových umístění schémat pro DLL.
- Není vyžadována jednotná metoda pro instalaci a odstraňování softwaru (správce balíčků).
- Centralizovaná autoritativní podpora pro binární rozhraní řízení a záruk DLL aplikace, dovolující vydání nekompatibilním DLL knihovnám se stejným názvem souboru a interním číslem verze.
- Příliš zjednodušené nástroje pro správu, které brání identifikaci změněných problematických DLL uživateli a administrátory.
- Vývojářské obcházení zpětné kompatibility funkcí ve sdílených modulech.
- Microsoft vydává aktualizace běhového prostředí operačního systému mimo standardní aktualizace.
- Neschopnost dřívějších verzí systému Windows spustit vedle sebe různé verze téže knihovny.
- Spolehnutí se na aktuální adresář nebo proměnnou prostředí
%PATH%
, kde oba parametry se mění v čase a systém od systému, k najití závislé DLL knihovny (namísto jejich načtení z explicitně nakonfigurovaného adresáře). - Developeři znovu používají ClassID z ukázkové aplikace pro COM rozhraní svých aplikací místo toho, aby vytvořili svoje vlastní nové GUID.
DLL peklo byl velmi častý jev na systémech před vydáním Windows NT. Hlavní příčinou je, že 16bitové operační systémy neuměly omezovat procesy k jejich vlastnímu paměťovému prostoru, a tím jim nedovolit nahrání vlastní verze sdílených modulů, které jsou s ním kompatibilní. U aplikačního instalátoru se očekává, že bude kvalitní a bude ověřovat informace o verzi DLL knihovny před přepsáním existující systémové DLL knihovny. Standardní nástroje ke zjednodušení nasazení aplikací (které vždy zahrnují dodání vlastní potřebné DLL knihovny na operačním systému) byly poskytnuty společností Microsoft a dalšími dodavateli softwaru. Microsoft dokonce vyžaduje po dodavatelích aplikace použití standardního instalátoru a verifikaci jejich programu, aby správně fungoval, než mu bude povoleno použití loga Microsoftu.
Použití malwarem
editovatNejednoznačnost, s níž knihovny, které nejsou plně kvalifikované, mohou být vloženy do operačního systému Windows je v posledních letech zneužívána malwarem k otevření nových cest zranitelnosti, které ovlivňují aplikace od mnoha různých dodavatelů software, stejně jako systém Windows.
Řešení
editovatRůzné druhy DLL pekla byly v průběhu let vyřešeny nebo zmírněny.
Statické linkování
editovatJedním z nejjednodušších řešení DLL pekla v aplikaci je k ní připojit všechny statické knihovny. Toto je běžné v Microsoft C/C++ aplikacích, kde místo toho, abychom se museli starat o to, které verze MFC42.DLL jsou nainstalovány, aplikace je sestavena tak, aby se propojila se statickými knihovnami. To eliminuje DLL úplně, a je přijatelné pro samostatné aplikace, které používají pouze knihovny, které nabízejí statické možnosti, jako je například Microsoft Foundation Class Library. Tím mizí hlavní výhoda DLL (sdílení knihoven v paměti mezi za účelem snížení zatížení paměti), ale zjednodušuje se další vývoj softwaru a komplikované nasazení bezpečnostních oprav nebo novějších verzí softwaru.
Ochrana souborů systému Windows
editovatProblém přepsání DLL byl poněkud snížen s příchodem Ochrany souborů systému Windows (Windows File Protection, WFP), která byla zavedena v systému Windows 2000. WFP zabrání neautorizovaným aplikacím přepsání systémové knihovny DLL, pokud nepoužívají specifické rozhraní Windows API, které toto umožňují. Stále ale existuje riziko, že aktualizace od společnosti Microsoft budou neslučitelné s existujícími aplikacemi, ale toto riziko je obvykle sníženo v současných verzích systému Windows pomocí Side-by-side assembly (SFC).
Aplikace třetích stran nemohou měnit soubory OS, pokud neobsahují balík legitimních aktualizací systému Windows přímo v jejich instalaci, nebo v případě, že tuto službu zakázala ochrana souborů systému Windows během instalace. Od Windows Vista aplikace třetích stran nemohou převzít vlastnictví systémových souborů a udělit si k nim přístup. Nástroj SFC může kdykoliv tyto změny vrátit.
Spuštění konfliktních knihoven DLL
editovatŘešení spočívá v tom, mít obě odlišné kopie stejné DLL knihovny pro každou aplikaci, obě na disku i v paměti.
Snadné manuální řešení konfliktů bylo umístění různých verzí problémových DLL knihoven do složek aplikací, než do společné složky celého systému. Toto funguje obecně tak dlouho, dokud aplikace je 32bitová nebo 64bitová a pokud DLL nepoužívá sdílenou paměť. V případě 16bitových aplikací nelze spustit na 16bitové platformě dvě aplikace současně nebo na 16bitovém virtuálním stroji pod 32bitovým operačním systémem. Před Windows 98 SE/Windows 2000 tomuto zabraňovalo Object Linking and Embedding (OLE), protože starší verze systému Windows měla jediný registr COM objektů pro všechny aplikace.
Systémy Windows 98 SE/Windows 2000 představily řešení s názvem Side-by-side assembly (SFC), které načte samostatné kopie DLL pro každou aplikaci, která je vyžaduje (a tím umožňuje aplikacím, které vyžadují konfliktní DLL, se spustit současně). Tento přístup eliminuje konflikty tím, že aplikaci umožní načíst požadovanou verzi modulu do svého adresního prostoru, při zachování primárního přínosu sdílení DLL mezi aplikacemi (tj. snížení využití paměti) pomocí metody mapování paměti a sdílení společného kódu mezi různými procesy, které nadále používají stejný modul. Avšak u DLL knihoven využívajících sdílená data mezi více procesy tento přístup nemusí fungovat. Jeden negativní vedlejší efekt jsou osamocené instance DLL knihovny, které nemusí být aktualizovány během automatizovaných aktualizací.
Přenosné aplikace
editovatV závislosti na architektuře aplikace a běhového prostředí může být přenosná aplikace efektivní způsob, jak snížit některé problémy s DLL, protože každý program obsahuje svazky svých vlastních soukromých kopií všech DLL knihoven, které potřebuje.
Virtualizace aplikací může také umožnit běh aplikace v „bublině“, která zabraňuje instalaci DLL knihoven přímo do souborů operačního systému.
Reference
editovatV tomto článku byl použit překlad textu z článku DLL Hell na anglické Wikipedii.