4

在我的 Delphi XE2 32 位应用程序 (Update 4 Hotfix 1 Version 16.0.4504.48759) 中,我使用 Format() 例程来记录指针值。

例如:

Format('MyObject (%p)', [Pointer(MyObject)]);

但是,生成的字符串有时包含垃圾字符(例如,在这种情况下,“?”或“|”代替十六进制数字):

MyObject (4E?|2010)

当用 '%x' 替换 '%p' 时,我也会得到相同的结果,如下所示:

Format('MyObject (%x)', [Integer(MyObject)]);

但是,使用整数值总是有效的:

Format('MyObject (%d)', [Integer(MyObject)]);

MyObject (1291453120)

是否有我不知道的错误,或者这可能与这里遇到的问题有关?

为什么将“%s”以外的任何内容与 Variant 一起使用时,Format 会崩溃?

更新

我接受了 Jeroen 的回答,因为它通过消除过程引导我找到了解决方案。在通过 F7 启动应用程序的情况之后(根据评论),我认为在此过程的早期一定会出现问题。凭直觉,我从它的 IDE 菜单中禁用了 madExcept,重新构建了应用程序,问题就消失了。显然,madExcept 链接到我的应用程序的任何代码都会导致 SysUtils 常量 TwoHexLookup 被覆盖。重新启用 madExcept 和重建(我没有任何其他更改)也有效,因此在链接阶段肯定存在一些损坏。

Jeroen 概述的用于检测内存损坏的策略是一个有用的练习,如果我遇到类似的情况应该证明是有价值的。

4

2 回答 2

4

我最好的假设是您的代码正在修改一些不应该修改的内存,可能是通过取消引用未初始化的指针。我创建了一个可重现的案例来证明这种可能性。至少,它可以在我的机器上使用我的编译器版本重现。在另一种情况下,完全相同的代码可能不会做同样的事情。

procedure TForm1.Button1Click(Sender: TObject);
var
  P : pbyte;
  S : string;
  T : ansistring;
begin
  // There's nothing special about HexDisplayPrefix.
  // It just happens to be one of the last global variables
  // declared in SysUtils.

  P := @ ( HexDisplayPrefix );

  // A few bytes beyond that is TwoHexLookUp.
  // This is a static array of unicode characters used by the IntToHex routine,
  // which is in turn used by Format when %p or %x are used.

  // I'll add an offset to P so that it points into that array.
  // I'll make the offset odd so that it points to the high byte of a character.
  // Of course, I can't guarantee that the same offset will work for you

  P := P + 5763;

  // Change the lookup table.
  // Of course, you would never do this on purpose.

  P ^ := 39;

  // Now let's call IntToHex

  S := IntToHex ( $E0, 2 );

  // Show the value on the screen.
  // Hey look, the zero has been replaced with a star.

  memo1 . lines . add ( S );

  // Convert the unicode string to an ansistring

  T := ansistring ( S );

  // Show the value on the screen.
  // When converting to Ansi, the system doesn't know what to do with the star,
  // so it replaces it with a question mark.

  memo1 . lines . add ( unicodestring(T) );

end;

显示带星号的 E 和带问号的 E

于 2013-02-15T12:30:59.217 回答
2

由于这似乎是内存覆盖(参见您对user1008646的评论),您可以尝试按照以下步骤操作:

  1. 首先尝试找出哪个内存地址被覆盖。你提到那s := IntToHex(2129827392, 8);失败了。找出正确的值,然后找出它是否在TwoHexLookUp.
  2. 如果它在 范围内TwoHexLookUp,则设置一个数据更改断点(请参阅如何在对象字段值更改时定义断点?添加数据断点了解如何执行此操作)。
  3. 运行您的应用程序,直到断点触发。

广告 1:可能最简单的方法是查看哪个值更改与您在运行时观察到TwoHexLookUp的结果相同,从而得到错误的结果。s := IntToHex(2129827392, 8);

星期四我正在为一个客户做一些德尔福的工作,所以我可能有时间更深入地挖掘。

编辑
当您使用 F7 逐步完成您的过程时,您确实进入了SysInit第一个。

你可以在那里做的已经在TwoHexLookup数组上设置了一个断点。
然后是 F9/F8/F7(取决于您想要的粒度)并密切关注 Watch 窗口中的阵列。那应该让你继续前进。

于 2013-02-19T19:37:54.470 回答