Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

AV при использовании юнита Variants [D7, WinXP]


Страницы:   1 2

Сергей М. ©   (2010-03-09 11:15:00) 

Столкнулся с неожиданной засадой при использовании юнита Variants.

Целевая задача :

реализовать в D7EE DLL-модуль (использующий юнит Classes и собираемый без использования Run-Time пакетов), загружаемый в адр.пространства создаваемых системой процессов с использованием документированного механизма автозагрузки указанием модуля в списке
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs

Проблема:

при создании и инициализации процессов ряда приложений в ходе инициализации загружаемого в их АП моего DLL-модуля возбуждается AV-исключение с дословным сообщением постоянного содержания в появляющемся диалоговом окне:

Инструкция по адресу 0x7C918FEA обратилась по адресу 0x00000010. Память не может быть "written".

После закрытия диал.окна эти процессы продолжают и инициализацию и успешно стартуют, естественно без моего DLL-модуля в своих АП, поскольку его инициализация привела к отказу по необработанному моим DLL-модулем исключению.

В ходе анализа причин и условий возникающей проблемы выявлены следующие факты:

1. Исключение возбуждается в коде модуля ntdll.dll в теле ф-ции RtlInitializeCriticalSection()

2. Исключение возбуждается как минимум при условии явного (прямым указанием в USES) или неявного (фигурирантом в USES иных юнитов в составе VCL и RTL, например, Classes) использования в проекте моего DLL-модуля юнита Variants

3. Исключение возбуждается только при условии сборки моего DLL-модуля без использования Run-Time пакетов.

4. Инициализация критической секции фигурирует в тексте юнита Variants в секции INITIALIZATION.

Прошу тех, кто возможно вплотную сталкивался с такой проблемой, высказать свои соображения по ней и возможные варианты ее преодоления в упомянутых выше условиях.

Текст проекта DLL-модуля для тестирования:


library TestDll;

uses
 Variants;

{$R *.res}

begin

end.


Пример списка приложений, запуск которых приводит к возникновению вышеописанной проблемы:

delphi7.exe
mmc.exe
paint.exe
skype.exe
virtualbox.exe
TeamViewer.exe (TeamViewer4)

Пример списка приложений, запуск которых НЕ приводит к возникновению вышеописанной проблемы:

iexplore.exe
firefox.exe
procexpr.exe
calc.exe
wordpad.exe
excel.exe
notepad.exe
TeamViewer.exe (TeamViewer3)
FAR.exe

Воспроизводима ли проблемная ситуация в других условиях (иная ОС, иная Delphi IDE) ?


Сергей М.   (2010-03-09 16:25:00) [21]


> Игорь Шевченко


Игорь, я еще немного понаглею, с твоего позволения ?)

Структура параметра ApplicationGoo ключа в разделе
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
документирована где-либо ?


Сергей М.   (2010-03-09 15:20:00) [22]


> Игорь Шевченко ©   (09.03.10 14:51) [16]


Спасибо, понятно.


Игорь Шевченко   (2010-03-09 14:51:00) [23]

Сергей М. ©   (09.03.10 14:31) [15]


> Кстати, в Win7 и Vista механизм AppInit_Dlls еще поддерживается
> или уже нет ? Под рукой их сейчас нет, так что поверю на
> слово)


Гугля у тебя тоже под рукой нет ?

http://www.microsoft.com/whdc/driver/install/AppInit-Win7.mspx

там в документе, предлагаемом к скачиванию, есть фраза, что появился ключ
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT \CurrentVersion\Windows\LoadAppInit_DLLs типа DWORD, который определяет поведение.


Сергей М.   (2010-03-09 14:31:00) [24]


> Игорь Шевченко ©   (09.03.10 14:18) [14]


> Казалось бы, чего проще


Да не хотелось бы возиться).. Хотя может и придется.
Впрочем можно и без Windbg - думаю что и привычный дельфийский встроенный отладчик справится не хуже

Но проще, видимо, отказаться от геморроя с AppInit_Dlls в пользу иных подходящих механизмов, ибо, по правде говоря, залезть мне нужно в АП конкретного GUI процесса, а не вовсе подряд.

Да и к тому же MS предупреждает о возможной неподдержке AppInit_Dlls в перспективных версиях своих ОС.

Кстати, в Win7 и Vista механизм AppInit_Dlls еще поддерживается или уже нет ? Под рукой их сейчас нет, так что поверю на слово)


Игорь Шевченко   (2010-03-09 14:18:00) [25]

Сергей М. ©   (09.03.10 14:11) [13]

Казалось бы, чего проще - взять windbg, проверить, какие DLL загружены/инициализированы на этапе загрузки твоей DLL, пройти по вызовам (он это умеет делать, для подобных случаев самый подходящий отладчик).

к AdvApi32, кстати, обращается system.pas при определении, нужно ли загружать ресурсные DLL и инициализировать особым образом FPU


Сергей М.   (2010-03-09 14:11:00) [26]

Нет, предположения [12] не подтвердились ...


Сергей М.   (2010-03-09 14:03:00) [27]


> Leonid Troyanovsky ©   (09.03.10 13:55) [9]


Похоже что следы ведут в этот пункт:

• Call the registry functions. These functions are implemented in Advapi32.dll. If Advapi32.dll is not initialized before your DLL, the DLL can access uninitialized memory and cause the process to crash.

Сейчас проверю. не лезет ли процесс неявно в реестр при посредничестве ole32 (у нее в таблице импорта фигурируют ф-ции из состава advapi32 для доступа к реестру)


Игорь Шевченко   (2010-03-09 14:01:00) [28]

Leonid Troyanovsky ©   (09.03.10 13:55) [9]


> Для пищи добавлю выжимку из той ссылки


Ну и я добавлю:

http://transl-gunsmoker.blogspot.com/2009/01/dllmain_04.html
http://transl-gunsmoker.blogspot.com/2009/01/dllmain.html
http://transl-gunsmoker.blogspot.com/2009/01/dllmain_7983.html


Игорь Шевченко   (2010-03-09 13:58:00) [29]

Сергей М. ©   (09.03.10 13:30) [7]

Попробуй то же самое, без AppInit_DLL, это даст однозначный ответ - можно вызывать oleaut32 в момент инициализации user32 или нет.


Leonid Troyanovsky   (2010-03-09 13:55:00) [30]


> Сергей М. ©   (09.03.10 13:33) [8]

> Но пока не могу нарисовать в голове четкую картинку происходящего
> при  этом ..

Для пищи добавлю выжимку из той ссылки

You should never perform the following tasks from within DllMain:
• Call LoadLibrary or LoadLibraryEx (either directly or indirectly). This can cause a deadlock or a crash.
• Synchronize with other threads. This can cause a deadlock.
• Acquire a synchronization object that is owned by code that is waiting to acquire the loader lock. This can cause a deadlock.
• Initialize COM threads by using CoInitializeEx. Under certain conditions, this function can call LoadLibraryEx.
• Call the registry functions. These functions are implemented in Advapi32.dll. If Advapi32.dll is not initialized before your DLL, the DLL can access uninitialized memory and cause the process to crash.
• Call CreateProces. Creating a process can load another DLL.
• Call ExitThread. Exiting a thread during DLL detach can cause the loader lock to be acquired again, causing a deadlock or a crash.
• Call CreateThread. Creating a thread can work if you do not synchronize with other threads, but it is risky.
• Create a named pipe or other named object (Windows 2000 only). In Windows 2000, named objects are provided by the Terminal Services DLL. If this DLL is not initialized, calls to the DLL can cause the process to crash.
• Use the memory management function from the dynamic C Run-Time (CRT). If the CRT DLL is not initialized, calls to these functions can cause the process to crash.
• Call functions in User32.dll or Gdi32.dll. Some functions load another DLL, which may not be initialized.
• Use managed code.

Т.е., при загрузке User32 кто-то требует ole.
Осталось найти, возможно, где-то в дебрях system.

Но, проще отказаться от uses variants, IMHO.

--
Regards, LVT.


Сергей М.   (2010-03-09 13:33:00) [31]


> Leonid Troyanovsky ©   (09.03.10 13:17) [5]


Да и я уже нутром чувствую, что следы ведут в ole ..
Но пока не могу нарисовать в голове четкую картинку происходящего при  этом ..


Сергей М.   (2010-03-09 13:30:00) [32]


> Игорь Шевченко ©   (09.03.10 13:07) [4]


Спасибо за отклик.

> не совсем уверен, что проблема в InitializeCriticalSection

Да, ты прав, отказ в иной ф-ции, но тем не менее связанной с ожиданием некоей КС в ф-ции ntdll.RtlpWaitForCriticalSection

Иллюстрация картины:

Скриншот диал.окна с сообщением об AV (14 кб):
http://ifolder.ru/16756773

Скриншот соответствующего Delphi Debugger CPU Window (188 кб)
http://ifolder.ru/16756784

Посмотри, пож., вероятно это даст какой-то вектор для поиска кустов где притаилась засада..


Smile   (2010-03-09 13:19:00) [33]

Google для строки поиска: "Инструкция по адресу 0x7C918FEA обратилась по адресу 0x00000010" находит достаточное количество ссылок, в общем то, на первый взляд, не связанных с юнитом Variants


Leonid Troyanovsky   (2010-03-09 13:17:00) [34]


> Сергей М. ©   (09.03.10 12:49) [2]


Вот библиотеки екзешника (консоль) с uses variants:

770E0000-C:\WINDOWS\system32\oleaut32.dll
77160000-C:\WINDOWS\system32\ole32.dll
77BA0000-C:\WINDOWS\system32\msvcrt.dll
77C00000-C:\WINDOWS\system32\GDI32.dll
77C50000-C:\WINDOWS\system32\RPCRT4.dll
77D00000-C:\WINDOWS\system32\user32.dll
77DA0000-C:\WINDOWS\system32\advapi32.dll
77E40000-C:\WINDOWS\system32\kernel32.dll
77F40000-C:\WINDOWS\system32\ntdll.dll
--------------------------

А вот без оного:

77BA0000-C:\WINDOWS\system32\msvcrt.dll
77C00000-C:\WINDOWS\system32\GDI32.dll
77C50000-C:\WINDOWS\system32\RPCRT4.dll
77D00000-C:\WINDOWS\system32\user32.dll
77DA0000-C:\WINDOWS\system32\advapi32.dll
77E40000-C:\WINDOWS\system32\kernel32.dll
77F40000-C:\WINDOWS\system32\ntdll.dll

Видимо, то, что ole* не есть safe to use in the initialization of the AppInit DLLs.

Кто их там тянет через variants разобрать сложно.

--
Regards, LVT.


Игорь Шевченко   (2010-03-09 13:07:00) [35]

Я не совсем уверен, что проблема в InitializeCriticalSection - нечему там вызывать AV, на первый взгляд.

Но следует учесть, что загрузка такой DLL тянет за собой загрузку oleaut32 с возможным вызовом функций из нее, а допустимо ли загружать эту DLL в момент инициализации user32 - это вопрос, на который я не могу ответить.


Сергей М.   (2010-03-09 13:04:00) [36]


> Leonid Troyanovsky


И вот еще какая любопытная картина - тот же, к примеру, calc.exe в таблице импорта имеет  зависимость от user32, однако я не наблюдаю в его АП  своего DLL-модуля с Variants ни при использовании ею ран-тайм пакетов ни без использования оных.
При этом , как я уже сказал, calc.exe грузится и инициализируется безо всяких проблем и в том и в другом случае.


Сергей М.   (2010-03-09 12:49:00) [37]


> Leonid Troyanovsky ©   (09.03.10 12:25) [1]


Спасибо за отклик.


> в момент загрузки твоей библиотеки, необходимые для
> поддержки variant библиотеки еще не загружены


Есть ли соображения на тему о каких модулях может идти речь в этом случае ?

Если спотык действительно происходит в момент вызова юнитом Variants
функции
kernel32.InitializeCriticalSection(LVarTypeSync)
то это вроде бы не противоречит рекомендациям MS, к тому же kernel32+ntdll в этот момент уже гарантированно загружены и инициализированы

Согласно

http://support.microsoft.com/kb/q197571/

спотык происходит в момент выполнения инициализации user32.dll при ее загрузке целевым процессом

Я что-то не вижу пока явной связи между инициализацией КС и user32 ..


Leonid Troyanovsky   (2010-03-09 12:25:00) [38]


> Сергей М. ©   (09.03.10 11:15)  

> Прошу тех, кто возможно вплотную сталкивался с такой проблемой,
>  высказать свои соображения по ней и возможные варианты
> ее преодоления в упомянутых выше условиях.

Самые общие рекомендации by MS:
http://www.microsoft.com/whdc/driver/kernel/DLL_bestprac.mspx

Сталкивался давно, еще в ту пору, когда variants не выделялся
в отдельный юнит. Проблема была та же, в неявной инициализации,
т.е., в момент загрузки твоей библиотеки, необходимые для
поддержки variant библиотеки еще не загружены.

Если поддержка variants необходима, то,  видимо, нужно
добиваться более поздней инициализации. Not tested.

--
Regards, LVT.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо