在 Visual Studio 中进行调试和不进行调试时,.NET 程序的行为有何不同?
在关闭 .NET 应用程序时,我在 DBEXPSDA40.DLL(Dev Art MS SQL Server dbexpress 驱动程序)中遇到访问冲突。我的应用程序(VB.NET)调用Delphi编写的COM服务器,它使用dbexpress连接到SQL Server。
如果我做同样的事情,但我的主机应用程序是本机 Delphi 应用程序或 Excel VBA,那么我看不到 A/V。如果我在 VS IDE 中通过调试运行 VB.NET 应用程序,我也看不到它。
我已经将 A/V 追踪到 dbexpress 单元中的一个终结子句,该子句负责关闭驱动程序(在本例中是两个,一个用于 SQL Server,另一个用于 SQL Server Compact),
如果我能弄清楚区别在于在 .NET 环境中进行调试和不进行调试,我也许可以知道在哪里进一步查看。
I'm getting an Access Violation in DBEXPSDA40.DLL (Dev Art MS SQL Server dbexpress driver) on closing down my .NET application. My application (VB.NET) calls a Delphi written COM Server which uses dbexpress to connect to SQL Server.
If I do the same thing, but my host application is a native Delphi application, or Excel VBA, then I do not see the A/V. I also do not see it if I run the VB.NET application in the VS IDE with debugging.
I have tracked down the A/V to a finalization clause in a dbexpress unit, which takes care of closing down the drivers (in this case two, one for SQL server and the other for SQL Server Compact)
If I can figure out what the difference is between with debugging and without in the .NET environment, I can perhaps know where to look further.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的区别在于内存布局。
有很多微妙的因素会影响这个过程。其一,在调试器下,JIT 生成略有不同的代码(以适应调试器)。根据您的调试器设置,Visual Studio 还可能在您的进程中注入一些其他代码(例如 .vshost.exe)。调试器还会影响时序,从而可能会暴露竞争条件和/或更改内存分配方式。
长话短说,在应用程序关闭时,您最终会得到[轻微或显着]不同的内存布局。显然,不同的主机应用程序也是如此。
但这只是故事的一方面。另一方面是dbexpress有一个bug。或者某些其他模块可能会导致 dbexpress 数据内存损坏。无论哪种方式,dbexpress 最终都会访问一些随机地址。
在一种情况下,该地址恰好位于未分配的内存页上,但在其他情况下恰好位于已分配的内存页上(因为内存布局不同,还记得吗?)。在后一种情况下,dbexpress 只是从内存中读取值,用它做一些事情,显然对结果感到满意,然后优雅地退出。
这(以及不可追踪的竞争条件)是不成熟编写的非托管代码的一个非常常见的问题(我的经验表明,涉及 Delphi 时经常出现这种情况)。
解决方案是什么?改变条件。
您可以在不同的机器上尝试。或者在同一台机器上,但负载很重。或者加载更多模块。或者不要加载一些你通常会加载的模块。玩它。
话虽这么说,但你个人从来不会那样做。这简直就是大海捞针,永无止境,令人心力交瘁的冒险。另外,您很有可能在其他地方获得 AV(但由于相同的根本原因)。
另一个(也是更好的)选项是调试打印。也就是说,如果你有 dbexpress 的源代码(抱歉,我不熟悉它)。
否则,我将从对 Delphi 组件进行非常仔细的代码审查开始。也可能在那里调试打印。
祝你好运。
Your difference is memory layout.
There is a lot of subtle factors that influence the process. For one, under debugger, the JIT generates slightly different code (to accommodate the debugger). Depending on your debugger settings, the Visual Studio may also inject some other code in your process (like the .vshost.exe, for example). The debugger can also affect the timing and that may in turn expose race conditions and/or change how memory is allocated.
Long story short, by the time of application closing, you end up with [slightly or significantly] different memory layout. And same goes for a different host application, obviously.
But that's only one side of the story. The other side is that there is a bug in dbexpress. Or maybe some other module causes memory corruption in dbexpress's data. Either way, dbexpress ends up accessing some random address.
And that address just happens to be on an unallocated memory page in one case, but happens to be on an allocated one in other cases (because the memory layout is different, remember?). And in the latter case, dbexpress just reads the value from memory, does something with it, apparently gets satisfied with the result, and gracefully exits.
This (along with untraceable race conditions) is a very common problem with immaturely written non-managed code (which, my experience shows, is very often the case where Delphi is involved).
The solution? Change conditions.
You can try on a different machine. Or on the same machine, but under heavy load. Or load some more modules. Or do not load some modules that you usually do. Play with it.
That being said, yours truly personally never goes that way. It just becomes searching for a pin in a haystack, never ending, emotionally draining kind of adventure. Plus, you have a high chance of getting an AV in some other place (but because of the same root cause).
Another (and better) option would be debug print. That is, in case you have source code of dbexpress (sorry, I'm not familiar with it).
Otherwise, I would start with a very careful code review for the Delphi component. And probably debug print there as well.
Good luck.
主机应用程序可能向您隐藏了异常。关闭错误是最难的。添加一些日志记录以查看调试器分离时是否发生异常。
It is possible that the host application is hiding the exception from you. Shutdown errors are the hardest. Add some logging to see if the exception occurs when the debugger is detached.