Windows 7 上 WTSOpenServer 发生奇怪崩溃(仅在 Delphi 2009/2010 中)
我正在解决始终工作正常的现有代码的问题(它是 来自 Jedi Windows 安全库的终端服务器单元) 。 经过一番调查后,问题部分已归结为对 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 中的反汇编,并从 Delphi 中的 asm 中调用了 WTSOpenServer(并将 Handle 类型更改为 C 中的指针):
hModule := LoadLibrary('wtsapi32.dll'); 如果 hModule = 0 那么 出口; WTSOpenServer := GetProcAddress(hModule, 'WTSOpenServerW'); 如果 WTSOpenServer = nil 那么 出口; 虽然是真的 开始 汇编 推送 dword ptr pServerName; 调用 dword ptr WTSOpenServer; mov [hServer], eax; 结尾; hServer := nil; 结尾;
省略对 WTSCloseServer 的调用
- 调用 在 Windows 7 的 x64 和 x86 版本上测试代码
- 使用外部调试器而不是 Delphi 调试器(在这种情况下似乎运行良好,所以我猜测这是某种计时/线程/死锁问题)
- 添加了 AddVectoredExceptionHandler 然后我看到 EXCEPTION_ACCESS_VIOLATION 但是堆栈似乎已损坏,EIP 为 1,因此无法确定它发生在哪里。
此时我不知道如何进一步解决此问题或找到解释。
I am troubleshooting a problem with existing code that always worked fine (it's the Terminal Server unit from the Jedi Windows Security Library).
After some investigation the problem part has been brought down to a call to WTSOpenServer:
while true do
begin
hServer := WTSOpenServer(PChar('server'));
WTSCloseServer(hServer);
hServer := 0;
end;
After a random (but small) number or runs we get a total app crash which makes it hard to debug.
Here are the things I already tried:
- WTSOpenServer does not write to the pServername parameter (like CreateProcessW) (in fact I checked the disassembly and it makes a copy)
- The code runs fine when passing nil as parameter (and thus work with the localmachine).
- When using a remote server, localhost or even dummy as pServerName the result is always crash (On Vista and higher even an invalid servername returns a valid handle as per documentation).
- Tested with both Delphi 2009 and 2010
- The same code runs fine in Visual Studio (c++).
Checked the disassembly in Visual Studio and made the call the WTSOpenServer in asm from Delphi (and change the Handle type to a pointer like in 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;
Leave out the call to WTSCloseServer
- Test the code on both x64 and x86 version of Windows 7
- Use External Debugger instead of Delphi one (seems to run fine in that case so my guess is that it's some kind of timing/thread/deadlock issue)
- Added AddVectoredExceptionHandler then I see a EXCEPTION_ACCESS_VIOLATION but the stacks seems to be corrupted, EIP is 1 so cannot determine where it happens.
At this point I don't know how to further troubleshoot this or find an explanation.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
尝试在 FullDebugMode 下使用 FastMM 运行您的应用程序。它看起来更像是您/第 3 方库代码中的错误 - 可能的内存覆盖/缓冲区溢出(大多数情况下,GetMem 对于 UnicodeString/String 类似操作来说太小,并且它“有效”,但迟早会崩溃/AV) 。
在将大型应用程序迁移到 D2009 时,我遇到过几次类似的情况,并且在大多数情况下,这是由于假设 Char=1 字节。有时会发生非常奇怪的事情,但 FullDebugMode 总是有帮助。例外是 CreateProcessW,但它是已知/记录的行为。
使用 FullDebugMode,如果应用程序覆盖内存,那么当您释放它时,FastMM 会在分配内存的位置提供异常,因此您可以轻松地追踪此错误。它在分配的开始和结束时添加一些字节,因此可以知道它是否被覆盖。
我无法用新的/空的 VCL 项目重现它,你可以自己尝试(这个循环运行大约 5 分钟):
Try run your application with FastMM in FullDebugMode. It looks more like a bug in your/3rd party-lib code - possible memory overwrite/buffer overflow (moslty like sth. GetMem too small for UnicodeString/String alike operations, and it 'works' but will sooner or later crash/AV).
I've had several similar situations when migrating big app to D2009, and in most cases it was due to assumption Char=1 byte. Sometimes very strange things happened, but always FullDebugMode helped. Exception was CreateProcessW, but it's know/documented behaviour.
With FullDebugMode if app overwrite memory, then when you free it, FastMM gives you exception where it was allocated, so easly you can track down this bug. It adds some bytes at begining and end of allocation, so will know if it was overwritten.
I'm not able to reproduce it with new/empty VCL project, you can try it your self (this loop running for about 5 min):