| 2 копии DLL в одном процессе | Оценить ![]() ![]() ![]() ![]() ![]() ![]() |
| От: | TheRawGod | |
| Дата: | 20.12.07 13:08 | |
| Оценка: | 10 (2) | |
| Коллеги, сразу хочу отметить, что вопрос сюда пришел постепенно, по пути msdn -> microsoft.public.vc.atl -> wasm -> rsdn. К сожалению, ответ нигде получить не получилось, поэтому дублирую здесь, прошу прощения у тех, если кто его читает не в первый раз. Ситуация следующая: в процессе работы над проектом мы натолкнулись на то, что при определенных условиях нам удается загрузить одну и ту же dll в один процесс 2 раза. Фактический mapping type в обоих случаях Image, пути загрузки — идентичны. Чтобы показать проблему был сделан простенький пример (solution из 3-х native win32 C++ проектов для Visual Studio 2005). В нем мы грузим проблемную длл вначале с помощью SxS COM, создавая объект, живущий в ней, а воторой раз — как статически прилинкованную к загружаемой через LoadLibrary длл (т.е. делаем LoadLibrary "промежуточной" длл, в таблице импорта которой находится "проблемная" первоначальная дублирующаяся длл (та, в которой живут созданные раньше через SxS com объекты)). Порядок загрузки изображен тут. В результате смотрим, например, Process Explorer'ом и видим 2 копии одной и той же длл. Меня бы может и устроил ответ, что, типа, в одном случае у нас com грузит, а в другом — LoadLibrary, да и то опосредованно через таблицу импорта и все такое (хотя это, имхо, бред, какая разница как оно грузится, если образ один и тот-же, да и поискать в ctnb если, то везде говорят, что "dll can't be loaded twice" с различным вариациями), если бы не еще несколько НО с нашей точки зрения: 1. Если в указанном примере использовать обычный com, а не SxS, то копия длл оказывается одна. 2. Если изменить порядок загрузки и вначале грузить через LoadLibrary, а потом создавать объект через SxS com — то опять-же, копия одна. И пускай уже, пункт 1 я готов принять как некий by design, но вот пункт 2 ставит большой знак вопроса. Какими бы ни были разными механизмы загрузки, но порядок их использования не должен влиять на конечный результат. Более того, если поставить бряки в DllMain дублирующейся длл, то студия дуреет: при первоначальной загрузке через SxS все красиво брякается, а вот при повторной непонятной загрузке студийные бряки не срабатывают. Если поусердствовать и вручную всунуть int3, то это приводит студию в шок и она показывает в стеке вызовов полную ерунду + асм код вместо исходников. Т.е. она видит, что длл загружена по одному базовому адресу и никак не хочет принимать тот факт, что та же длл есть и еще по другому адресу в том-же процессе. В результате мы подозреваем баг в загрузчике WinXP SP2 / Vista (воспроизводится аналогично), неким образом очевидно связанный с Side by Side COM. Очень буду вам благодарен за опровержение и любые иные аргументированные соображения. |
| Re: 2 копии DLL в одном процессе | Оценить ![]() ![]() ![]() ![]() ![]() ![]() |
| От: | Tom rsdn | http://www.RSDN.ru |
| Дата: | 20.12.07 14:14 |
| TRG>Очень буду вам благодарен за опровержение и любые иные аргументированные соображения. А ты уверен, что Dll не выгружена COM-ом? Попробуй протрейсить события в dllmain-е. Народная мудрось | всем все никому ничего(с). |
| Re[2]: 2 копии DLL в одном процессе | Оценить ![]() ![]() ![]() ![]() ![]() ![]() |
| От: | TheRawGod | |
| Дата: | 20.12.07 14:37 |
| Здравствуйте, Tom, Вы писали: TRG>>Очень буду вам благодарен за опровержение и любые иные аргументированные соображения. Tom>А ты уверен, что Dll не выгружена COM-ом? Попробуй протрейсить события в dllmain-е. Большое спасибо за Ваш ответ. Я абсолютно уверен, что не выгружена В случае описаного сценария (когда длл грузится именно 2 раза) мы имеем такие события (ставим int 3 в DllMain и в конструкторе глобального объекта, объявленного в длл): --- Создаем SxS com объект --- 1. Конструктор глобального объекта. 2. DllMain: ATTACH --- Делаем LoadLibrary "промежуточной" dll --- 3. Конструктор глобального объекта, но студия не может с этим разобраться и показывает асм код + безымянный стек trace 4. DllMain: ATTACH, асм код + безымянный стек trace --- Закрываем программу --- 5. DllMain: DETACH, нормальный, т.е. загруженой com'ом dll'ки. 6. DllMain: DETACH, асм код + безымянный стек trace, т.е. выгружается загруженная ранее "опосредовано" через LoadLibrary dll'ка Деструктор объекта просто не объявлен, но он тут сути не играет. К моменту закрытия уже и трейсить особо ничего больше не надо (шаги 5,6) — т.к. проблема налицо. |
| Re[3]: 2 копии DLL в одном процессе | Оценить ![]() ![]() ![]() ![]() ![]() ![]() |
| От: | Tom rsdn | http://www.RSDN.ru |
| Дата: | 20.12.07 15:46 |
| TRG>Я абсолютно уверен, что не выгружена Это ничего не значит. TRG>В случае описаного сценария (когда длл грузится именно 2 раза) мы имеем такие события (ставим int 3 в DllMain и в конструкторе глобального объекта, объявленного в длл): Не надо int 3, хватит простого outputDebugString-а. TRG>--- Создаем SxS com объект --- TRG>1. Конструктор глобального объекта. TRG>2. DllMain: ATTACH Который attach? ПС: Запустить не удалось, у меня 2008-я студия не стоит, только 2005. Народная мудрось | всем все никому ничего(с). |
| Re[4]: 2 копии DLL в одном процессе | Оценить ![]() ![]() ![]() ![]() ![]() ![]() |
| От: | TheRawGod | |
| Дата: | 20.12.07 16:19 |
| Здравствуйте, Tom, Вы писали: TRG>>Я абсолютно уверен, что не выгружена Tom>Это ничего не значит. TRG>>В случае описаного сценария (когда длл грузится именно 2 раза) мы имеем такие события (ставим int 3 в DllMain и в конструкторе глобального объекта, объявленного в длл): Tom>Не надо int 3, хватит простого outputDebugString-а. TRG>>--- Создаем SxS com объект --- TRG>>1. Конструктор глобального объекта. TRG>>2. DllMain: ATTACH Tom>Который attach? Tom>ПС: Tom>Запустить не удалось, у меня 2008-я студия не стоит, только 2005. 2008 не нужна, у меня тоже 2005. Собственно, о 2005 и шла речь в оригинальном сообщении, почему вы решили, что нужна 2008? Аттач — тот, который DLL_PROCESS_ATTACH, оба раза. Второй раз надо смотреть в дизасме, так как студия не соображает, что есть код, как я и писал. Тем не менее, оба раза DLL_PROCESS_ATTACH. |
| Re[5]: 2 копии DLL в одном процессе | Оценить ![]() ![]() ![]() ![]() ![]() ![]() |
| От: | Tom rsdn | http://www.RSDN.ru |
| Дата: | 26.12.07 02:30 |
| TRG>2008 не нужна, у меня тоже 2005. Собственно, о 2005 и шла речь в оригинальном сообщении, почему вы решили, что нужна 2008? Потому, что при запуске требует CRT от 2008-й Народная мудрось | всем все никому ничего(с). |
| Re[6]: 2 копии DLL в одном процессе | Оценить ![]() ![]() ![]() ![]() ![]() ![]() |
| От: | TheRawGod | |
| Дата: | 27.12.07 13:30 |
| Здравствуйте, Tom, Вы писали: TRG>>2008 не нужна, у меня тоже 2005. Собственно, о 2005 и шла речь в оригинальном сообщении, почему вы решили, что нужна 2008? Tom>Потому, что при запуске требует CRT от 2008-й Коллега, ошибаетесь. 2008 студии не видел в глаза ни один из моих рабочих PC, 9-й CRT там быть неоткуда. Тем более в зависимостях студийного (2005!) проекта. Требуется CRT версий 8.хххх. Не знаю, обновляллось ли CRT с выходом SP1 для студии 2005. Подозреваю, что как раз обновлялось, и что у Вас, возможно, это обновление не стоит. В любом случае, это имеет мало отношения к сути проблемы. После Нового Года будем контактировать с MS в рамках Gold Partner программы, должны уделить внимание, по идее. Больше ничего не остается. Оказыается, есть не так много людей, которые используют SxS COM и еще меньше людей, которые при этом вызывают LoadLibrary тех же библиотек |
| Re: 2 копии DLL в одном процессе | Оценить ![]() ![]() ![]() ![]() ![]() ![]() |
| От: | Ivan rsdn | www.rsdn.ru |
| Дата: | 27.12.07 19:20 | |
| Оценка: | 12 (2) | |
| Здравствуйте, TheRawGod, Вы писали: TRG>В результате мы подозреваем баг в загрузчике WinXP SP2 / Vista (воспроизводится аналогично), неким образом очевидно связанный с Side by Side COM. TRG>Очень буду вам благодарен за опровержение и любые иные аргументированные соображения. посмотрел пример в отладчике — выяснилось следующее: — нужно ли загружать dll определяет фукнция LdrpCheckForLoadedDll, при повторной загрузке SideBySide.dll она возвращает false и поэтому dll загружается повторно, при этом взводится флаг 0x10000000 в LDR_MODULE.flags (в WinDbg это можно увидеть с помощью команды !dlls -c <адрес модуля>) описание LDR_MODULE http://undocumented.ntinternals.net/UserMode/Structures/LDR_MODULE.html — эта логика как-то связана с тем, что предыдущая загрузка была в некотором activation context'е (т.е. с использованием манифеста), а текущая загрузка происходит через импорт другой dll. — в последующих загрузках (через таблицу импорта) LdrpCheckForLoadedDll уже будет проверять флаг 0x10000000) является ли это багом или фичей — непонятно. механизм загрузки модулей через LoadLibrary и таблицы импорта разный. как минимум тем, что в первом случае передаются пути для поиска dll, а во втором — нет. могу предположить, что манифесты предназначены для динамической загрузки модулей, в случае статической загрузки манифест никак не влияет на поиск подходящего модуля, с этим возможно и связан тот факт, что при статической загрузке ранее загруженного с помощью манифеста модуля будет создана отдельная копия. наличие специального флага 0x10000000 и логики по его проверке подтверждает версию, что все-таки это фича, а не баг |
| Re: 2 копии DLL в одном процессе | Оценить ![]() ![]() ![]() ![]() ![]() ![]() |
| От: | dZab | |
| Дата: | 28.12.07 02:27 |
| Подобный эффект должен наблюдаться, если набор прав у загружающих dll моделей, разный. У Рихтера эта ситуация подробно описана. Однако обычной ситуация является, когда dll грузят разные процессы, как могут быть разные права в пределах одного процесса, мне не понятно. К сожалению, не знаю, что скрывается за сочетанием "SxS", может оно и обеспечивает секьюрити? Еще одна возможность — com-объект создается как внепроцессный. |
| Re[2]: 2 копии DLL в одном процессе | Оценить ![]() ![]() ![]() ![]() ![]() ![]() |
| От: | aloch | |
| Дата: | 28.12.07 21:55 |
| Здравствуйте, dZab, Вы писали: > К сожалению, не знаю, что скрывается за сочетанием "SxS" SxS — side-by-side ![]() |