Повторная загрузка динамической бибилитеки (Windows))

Все, что вы хотели знать о программизме, но боялись спросить.
Ответить
Аватара пользователя
Old_Tuzik
Житель
Сообщения: 795
Зарегистрирован: 28 авг 2007, 16:38
Контактная информация:

Повторная загрузка динамической бибилитеки (Windows))

Сообщение Old_Tuzik »

Чего то странное происходит с повторной загрузкой дин. библиотеки на Windows.
Условие: есть библиотека которая загружается разными потоками. Затем она динамически погружает другую библиотеку (h = LoadLibrary(), where h is the base address and handle at the same time, let it be for example 0x16e000000) пользуется ее и выгружает ее когда считает нужным:

FreeLibrary(h) ;
UnmapViewOfFile() - имеено эта фунция ответвенна за выгрузку блиотеки из памяти, занятые адреса освобождаются. Я физически вижу что после этого вызова все сегменты библиотки в памяти не присутсвуют и это что требывалось.

А вот теперь наступает плохо - после второго вызова h = LoadLibrary(), h is again set to 0x16e000000 (as if the library was loaded at the same address), but memory examination confirms that this region is not present in the memory :shock:

Therefore, all further calls referring to the handle of the library make the main library/app crash with the message that you cannot access invalid memory at 0x16e000000

Question: How can it be that the second call returns something that looks like a valid handle/base address but the library itself is not loaded in the memory ??

Я вначале думал что при втором вызове OS пытается relocate the library (because the previously used region is already occupied) but cannot since the library is not relocatable - that's not true, the previous range of addresses is free and can be used again. Why does the API return the handle of the DLL that points to nowhere? A bug?

Может есть какой то способ использовать LoadLibraryEX with a flag meaning "now please load the library no matter what" ?
Аватара пользователя
Old_Tuzik
Житель
Сообщения: 795
Зарегистрирован: 28 авг 2007, 16:38
Контактная информация:

Re: Повторная загрузка динамической бибилитеки (Windows))

Сообщение Old_Tuzik »

Решение проблемы оказалость простым. Загрузка каждой библиотеки в процесс инкрементирует reference counter - который не доступен прогрммисту пока он сам ручками не захочет распарсить связанный список хранимый в PEB (Process Environment Block). Вот и получилось:
1) приложение загрузило DLL B (import library, explicit load) (and ref. counter = 1 if it was loaded through LoadLibrary())
2) DLL A manually loaded DLL B (LoadLibrary()) - nothing happened, DLL B is already in the memory, LoadLibrary() just returned the existing address, ref. counter = 2
3) DLL A manually unloaded DLL B (FreeLibrary()) - nothing happend DLL B is still in the memory, ref. counter = 1; it was not enough for DLL A and it called UnmapViewOfFile() and that forcefully unloaded DLL B from the memory.

4) 2) DLL A manually loaded DLL B (LoadLibrary()) -LoadLibrary() just returned the existing address ( because ref. counter = 1 / or in case of import library / explicit load, DLL B must be present in the memory) and the DLL B should be present in the memory (but we forcefully released the memory used by DLL B and nobody knows about that except us :cry: ).

Ok, next time when we try to use the handle of DLL B returned in the step 4 we crash because there is nothing at this address (the handle for DLL is its base address).

So, in this scenario UnmapViewOfFile() must not be used (actually if you are a peaceful programmer, otherwise you might want to inject your library into another process, do your things and cover the tracks by removing it from the memory permanently later).
Reference counter is affected by Load/FreeLibrary, so the library loaded manually can be unloaded from the memory and reloaded later again and if the app was statically linked with the use of import library for DLL B then DLL B must not unloaded (UnmapViewOfFile() from the memory at all in case if it may be needed in future - most likely you will not be able to load it back.
Ответить