我刚刚将几个自制的Outlook COM-addins从Delphi 2007移植到Delphi 2009,现在我遇到了一些非常奇怪的错误(在你问之前:没有一个看起来与字符串处理有任何明显的关系),例如模式对话框,当一个人试图再次调用它们时挂起Outlook(第一次看起来很好),但只有当它们从一个特定的事件处理程序调用而不是在其他地方做同样的事情时.当我将错误跟踪到特定的代码行并注释掉该行或用不同的代码将其替换为相同的效果时(例如,通过将代码通过函数直接调用到调用站点),将出现错误离开 - 通常只是为了稍后再发表一些(同样不显眼的)陈述.
在Delphi调试器中运行时,我可以看到冻结通常在访问冲突之前GetMem.inc
.至少所有这些问题都是100%可重复的......
毋庸置疑,在Delphi 2007中编译这些插件时,我们没有遇到任何这些问题.
现在,我很茫然.我知道我很幸运,但即使我认为自己是一个相当有经验的程序员(虽然主要是在利基领域),我从来没有真正处理过这类错误.正如这个问题的标题所说,我甚至不知道从哪里开始.我可以尽可能多地浏览代码,但无限的汇编语句对我来说毫无意义,我也不熟练有效地使用CPU视图.
此外,我甚至不确定这是否是我自己的代码开头的问题(在这种情况下我实际上倾向于怀疑).我们大量使用了许多第三方库(例如JCL,ADX,Redemption).ADX特别指出其Delphi 2009支持"beta".
我也尝试过使用FastMM的FullDebugMode,事实上我确实发现了ADX中的一些错误(例如,在被释放后被修改的块)但是当我使用Delphi 2007进行编译时所有这些也会发生,所以它似乎还不是很有必要这些最终是观察到的回归的原因.
那么,我该如何处理呢? - 或者更好的是:我在哪里可以找到一些学习如何处理这个问题的好资源?例如,有关使用CPU视图或有效解释和处理FastMM提交的报告的教程?这些都是正确的工具吗?我还应该在哪儿看?
附录:
在这种情况下,我应该怀疑哪些类型的代码?什么样的代码甚至有可能在内存中造成这样的破坏?我可以想到我的代码执行远程接近显式内存操作的任何地方的唯一地方是在准备WinAPI调用时保留一些缓冲区空间.还要记住,我的所有代码在Delphi 2007和Delphi 2009版本之间是相同的,Delphi 2007版本没有出现这样的问题.
更新:
有一些概率,促使我发布此问题的问题现已解决.请看下面我自己的答案.
获得解决方案的最佳工具可能是内存断点.
调试内存损坏是很痛苦的,所以尽量让你的生活尽可能简单:找到一个准确的,保证可重复的步骤,每次都有效.如有必要,请模拟Outlook主机,以便您不需要依赖Outlook计时问题或解决空间布局问题等.
您必须获得可靠的可重复步骤,从而在可预测的地址处产生AV或其他错误.
然后你要做的是重新启动进程,为引用该地址的内容创建内存断点集,并熟悉该块内存的生命周期.最小化和合理化您的复制步骤有助于此.添加其他断点并仅在应用程序中稍后启用内存断点可能会有所帮助; 或使用D2009断点的日志记录功能来记录内存值/调用堆栈等,而不是实际进入调试对象.
对于更一般的问题,不完全是一个答案,但很可能解决了促使它的具体问题:
我95%肯定现在已经确定了问题!:)
这是我做的:
我在编译器中启用了RangeChecking和OverflowChecking
我追查并修复了所有导致ERangeError
或EIntOverflow
异常的问题
(每个都有一个)
我在启用FastMM和FullDebugMode的情况下再次运行程序
我终于能够在所有情况下确定问题的原因是调用JCL函数 GetWindowCaption
似乎GetWindowCaption
显然尚未检查Unicode兼容性:它使用从API函数返回的值GetWindowTextLength
(返回字符数)作为输入ReallocMem
(需要字节数)来分配缓冲区GetWindowText
(其中在Delphi 2009中返回一个WideChars缓冲区).繁荣!该函数为缓冲区分配的内存太少,但GetWindowText
只是覆盖了以下内存,从而破坏了块页脚.
我现在已经在JCL错误跟踪器中将其作为项目#4648提交
我从中得到的底线是:始终确保修复所有报告的错误!包括(看似)非关键的,如范围和溢出错误.如果不出意外,它将使调试变得更加可预测.