代码之家  ›  专栏  ›  技术社区  ›  Remko

在Windows7上与wtsopenserver发生奇怪的崩溃(仅在Delphi2009/2010中)

  •  2
  • Remko  · 技术社区  · 15 年前

    我正在用一直运行良好的现有代码排除一个问题(它是 Terminal Server unit Jedi Windows Security Library ) 经过一番调查,问题部分已被要求 WTSOpenServer :

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

    在一个随机的(但很小的)数字或运行之后,我们会得到一个应用程序崩溃的总数,这使得它很难调试。 以下是我已经尝试过的事情:

    • wtsopenserver不写入pservername参数(如createprocessw)(事实上,我检查了反汇编,它生成了一个副本)
    • 当将nil作为参数传递时(因此与localmachine一起工作),代码运行良好。
    • 当使用远程服务器、localhost甚至dummy作为pservername时,结果总是崩溃(在vista和更高版本上,即使是无效的servername也会根据文档返回有效的句柄)。
    • 使用Delphi 2009和2010进行测试
    • VisualStudio(C++)中相同的代码运行良好。
    • 检查了Visual Studio中的反汇编,并从Delphi调用asm中的wtsopenserver(并将句柄类型更改为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上测试代码
    • 使用外部调试器而不是DelphiOne(在这种情况下似乎运行良好,所以我猜这是某种时间/线程/死锁问题)
    • 补充 AddVectoredExceptionHandler 然后,我看到一个例外情况“访问”冲突,但堆栈似乎已损坏,EIP为1,因此无法确定它发生的位置。

    此时,我不知道如何进一步排除故障或找到解释。

    1 回复  |  直到 15 年前
        1
  •  1
  •   Krystian Bigaj    15 年前

    尝试在fulldebugmode中使用fastmm运行应用程序。它看起来更像是/3rd-party lib代码中的一个bug——可能的内存覆盖/缓冲区溢出(大多数情况下,getmem对于unicodestring/string类似的操作来说太小了,它“有效”,但迟早会崩溃/av)。

    在将大应用程序迁移到D2009时,我遇到过几个类似的情况,在大多数情况下,这是由于假设char=1字节造成的。有时会发生一些很奇怪的事情,但始终是完整的调试码帮助。异常是createProcessW,但它是已知/记录的行为。

    如果应用程序覆盖了内存,那么当你释放内存时,fastmm会给你分配内存的异常,这样你就可以轻松地跟踪这个bug。它在分配的开始和结束时添加了一些字节,因此将知道它是否被覆盖。

    我无法用新的/空的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;
    
    推荐文章