Странный сбой с 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 2

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;