Странный сбой с WTSOpenServer на Windows 7 (только в Delphi 2009/2010)
Я устраняю проблему с существующим кодом, который всегда работал нормально (это модуль терминального сервера из библиотеки безопасности Jedi Windows). После некоторого исследования проблемная часть была сведена к вызову WTSOpenServer:
while true do
begin
hServer := WTSOpenServer(PChar('server'));
WTSCloseServer(hServer);
hServer := 0;
end;
После случайного (но небольшого) числа запусков мы получаем полный сбой приложения, что затрудняет его отладку. Вот вещи, которые я уже пробовал:
- WTSOpenServer не записывает имя pServername параметр (как CreateProcessW) (на самом деле я проверил дизассемблирование и он делает копию)
- код прекрасно работает при передаче nil в качестве параметра (и, таким образом, работает с localmachine).
- При использовании удаленного сервера, localhost или даже dummy в качестве pServerName всегда происходит сбой (в Vista и выше даже недопустимое имя сервера возвращает допустимый дескриптор в соответствии с документацией).
- протестировано на Delphi 2009 и 2010
- тот же код прекрасно работает в Visual Studio (с++).
-
Проверил дизассемблирование в Visual Studio и вызвал WTSOpenServer в asm из Delphi (и изменил тип дескриптора на указатель, как в C):
hModule := LoadLibrary('wtsapi32.dll'); if hModule = 0 then Exit; WTSOpenServer := GetProcAddress(hModule, 'WTSOpenServerW'); if WTSOpenServer = nil then Exit; while true do begin asm push dword ptr pServerName; call dword ptr WTSOpenServer; mov [hServer], eax; end; hServer := nil; end;
-
Оставьте вызов WTSCloseServer
- проверьте код как на x64, так и на x86 версии Windows 7
- используйте внешний отладчик вместо Delphi one (кажется, работает нормально в этом случае, поэтому я предполагаю, что это какая-то проблема синхронизации/потока/взаимоблокировки)
- добавлено AddVectoredExceptionHandler Затем я вижу EXCEPTION_ACCESS_VIOLATION, но стеки, кажется, повреждены, EIP равен 1, поэтому не могу определить, где это происходит.
На данный момент я не знаю, как в дальнейшем устранить эту проблему или найти объяснение.
1 ответ:
Попробуйте запустить приложение с помощью FastMM в FullDebugMode. Это больше похоже на ошибку в вашем / 3rd party-lib коде-возможная перезапись памяти / переполнение буфера (moslty как sth. GetMem слишком мал для UnicodeString / String подобных операций, и он "работает", но рано или поздно выйдет из строя/AV).
У меня было несколько подобных ситуаций при переносе big app на D2009, и в большинстве случаев это было связано с предположением Char=1 байт. Иногда случались очень странные вещи, но всегда помогал FullDebugMode. Исключением был CreateProcessW, но это ноу-хау/документированное поведение.
С FullDebugMode если приложение перезаписывает память, то когда вы освобождаете ее, FastMM дает вам исключение, где она была выделена, так что вы легко можете отследить эту ошибку. Он добавляет несколько байт в начале и в конце выделения, так что будет знать, если он был перезаписан.
Я не могу воспроизвести его с новым / пустым проектом VCL, вы можете попробовать его самостоятельно (этот цикл работает около 5 минут):
uses JwaWtsApi32; procedure TForm7.FormCreate(Sender: TObject); var hServer: DWORD; begin while true do begin hServer := WTSOpenServer(PChar('server')); WTSCloseServer(hServer); hServer := 0; end; end;