Странная ошибка с WTSOpenServer в Windows 7 (только в Delphi 2009/2010) - PullRequest
2 голосов
/ 06 января 2010

Я устраняю проблему с существующим кодом, который всегда работал нормально (это Терминальный сервер из Jedi Windows Security Library ). После некоторого расследования проблемная часть была переведена на вызов WTSOpenServer :

  while true do
  begin
      hServer := WTSOpenServer(PChar('server'));
      WTSCloseServer(hServer);
      hServer := 0;
  end;

После случайного (но небольшого) числа или запусков мы получаем полный сбой приложения, что затрудняет его отладку. Вот что я уже пробовал:

  • WTSOpenServer не записывает в параметр pServername (например, CreateProcessW) (на самом деле я проверил разборку, и он делает копию)
  • Код работает нормально при передаче nil в качестве параметра (и, таким образом, работает с локальной машиной).
  • При использовании удаленного сервера, локального хоста или даже пустышки в качестве pServerName результат всегда приводит к сбою (В Vista и выше даже недопустимое имя сервера возвращает действительный дескриптор согласно документации).
  • Протестировано с Delphi 2009 и 2010
  • Тот же код отлично работает в Visual Studio (c ++).
  • Проверил разборку в 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 Ответ

1 голос
/ 06 января 2010

Попробуйте запустить приложение с FastMM в FullDebugMode. Это больше похоже на ошибку в вашем / стороннем коде lib - возможное перезапись памяти / переполнение буфера (в большинстве случаев, например, sth. GetMem слишком мал для операций типа UnicodeString / String, и он «работает», но рано или поздно вылетит / AV) .

У меня было несколько похожих ситуаций при переносе большого приложения на 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;
...