2009-09-23 85 views
3

最近几天我们遇到了第三方开发的数据库组件出现的一些奇怪的问题。几个月来,这些组件都没有发生变化。 最近几天改变了的代码是我们自己的代码,我们也更新了由另一个第三方开发的gui组件。什么会导致System.Move偶尔给出错误的结果?

调试后我发现在一个数据库组件过程occationaly中调用System.Move会给出错误的结果!

请从数据库组件中查看下面的代码并阅读我的评论。这种不一致的行为如何发生? 任何人都可以给我一个如何开始找到这种不一致行为的原因的想法吗? 注意!我不认为这个代码有什么问题,它只是用来解释问题的“症状”。 我的猜测是由于我们的代码或更新的gui组件代码导致某种内存损坏或某种情况。

编辑:看看下面链接的博客帖子。看起来这可能与我的问题有关。至少在我读它,它证实了System.Move可以给错误的结果: http://blog.excastle.com/2007/08/28/delphi-bug-of-the-day-fpu-stack-leak/

编辑: 对不起,不张贴我的“解决方案” earlyer但这里说到: 当使用德尔福2007年我的问题是通过使用替代System.Move的FastMove解决。 升级到Delphi 2010后,我还没有遇到问题,我们不再使用FastMove。

Procedure InternalDescribe; 
var 
    cbufl: sb4; //sb4=LongInt 
    cbuf: array[0..30] of char; 
    cbufp: PChar; 
    //.... 
begin 
    //..Some code 
    repeat 
    //...Some code to initialize cbufp and cbufl 

    //On the 15. iteration the values immediately Before Move are always these: 
    //cbufp = 'STDPRODUCTSTOREDELEMENTSCOUNT' 
    //cbuf = ('S', 'T', 'A', 'T', 'U', 'S', #0, 'E', 'V', 'A', 'R', 'R', 'E', 'C', 'I', 'D', #0, 'D', 'U', 'C', 'T', 'I', 'D', #0, #0, #0, #0, #0, #0, #0, #0) 
    //cbufl = 29 

    Move(cbufp^, cbuf, cbufl); 

    //Values immediately After Move should then be: 
    //cbuf = ('S', 'T', 'D', 'P', 'R', 'O', 'D', 'U', 'C', 'T', 'S', 'T', 'O', 'R', 'E', 'D', 'E', 'L', 'E', 'M', 'E', 'N', 'T', 'S', 'C', 'O', 'U', 'N', 'T', #0, #0) 

    //But sometimes this Move results in this value(1 in 5..15 times): 
    //cbuf = ('S', 'T', 'D', 'P', 'R', 'O', 'D', 'U', 'C', 'T', 'S', 'T', 'O', 'R', 'E', 'D', #0, #0, #0, #0, #0, 'N', 'T', 'S', 'C', 'O', 'U', 'N', 'T', #0, #0) } 

    until SomeCondition; 
    //...Some more code 
end; 
+1

你真的应该包括你使用的Delphi版本,以及你是否最近升级了你的Delphi版本。它让人们更容易回答你的问题。 – 2009-09-23 18:33:49

+0

它是Delphi 2007 for Win32。另外,我们使用FastMM4。 (这不是我的问题,但我认识他) – 2009-09-23 20:39:00

+0

我已经修复了我的帐户,并将我所有的评论从我的“答案”中移除,并让他们对答案发表真实的评论。 – 2009-09-24 20:19:45

回答

0

是否可以在不修改当前代码的情况下恢复到较早的GUI组件代码?这样,你可以发现它是你的代码还是GUI组件。

另一个问题是,无论您是否使用多个线程。

编辑:我只是想要你为测试的原因恢复GUI组件。您应该将它们更新为最新版本。但我有另一个尝试给你。必须在移动操作之前尝试清零缓冲区?请参阅FillChar程序来实现此目的。这有帮助吗?

+0

是的,它有可能恢复。我本来打算试试这个,但我从来没有做到。我确实很确定问题来自gui组件,因为当我从代码中“分离”gui时,我还没有看到问题。然而,我不想仅仅回头并对此感到满意,因为我们升级了这些组件是有原因的。但我会试着确认/“反驳”我的怀疑。太糟糕了,我不会在几天的工作。 – 2009-09-24 19:57:20

6

移动不会给出错误的结果,或者至少我从来没有看到过它的任何情况。你更有可能在缓冲区中遇到意想不到的事情。尝试在此例程中添加对Windows.OutputDebugString的调用,以查看您之前和之后正在复制的内容。

+0

我知道System.Move通常不会给出错误的结果,但是这一次它尽我所见。如果你看看我在代码中的注释,我实际上看到了System.Move的正确输入有时会给出错误的结果。 – 2009-09-24 19:41:47

2

小心 - 你假设一个字符= 1字节。在D2009之前,这很好,但在D2009和D2010中,char是2个字节。移动始终与字节一起工作。升级到D2009或D2010后,是否可能发生这些问题?

+1

我们使用的是Delphi 2007,所以这不是我的问题的原因。 – 2009-09-24 19:45:56

1

我可以确认它有时会失败。我刚花了几天的时间来追踪它。简直不敢相信。在我们的例子中,我们有.NET 2.0,运行在IIS 6或IIS7下的网站调用Delphi 2007编写的一些COM组件,并且在中等负载下,它有时会突然开始无法移动28字节的字节16-19。大多数时候它工作。您可能会忽略9..31字节范围内的移动问题。

我们最终在每个系统之后放置了一个CompareMem()检查。Move()发现ComparewMem有时失败 - 这是在栈上分配的两个缓冲区/数组/结构之间移动的!男孩是我感到惊讶!

使年龄重复。实质上,从D2006开始的System.Move由于东西在FPU堆栈中留下而不可靠。如果FPU栈清晰的话,一切都会好起来的。

上面提到的博客文章条目是正确的。 HOwever无论修复是什么,它都不会影响system.Move(),因此如果你有一个在Delphi 2006或更高版本中编写的DLL/COM,你将在某个阶段遇到问题。

我检出了D2010并且System.Move中的代码没有被更改。在我们的例子中,我将把System.Move恢复到Delphi 7版本 - 只需使用make文件重新编译所有系统单元即可。

0

仅供参考(如果其他人也有同样的问题):我们为客户升级了我们的软件,并且在我们的应用程序启动时锁定了完整的触摸屏! Windows完全冻结!电脑必须重新启动(关闭电源)。花费一些时间才能找出完全冻结的原因。

幸运的是,我们在FastMove.LargeSSEMove中有一个AV(只有1!)stacktrace。 我在fastmove中禁用了SSE的使用,问题没有了。

顺便说一下:触摸屏有一个威盛Nehemiah CPU与S3芯片组。

相关问题