格式和指针/十六进制值(内存覆盖)

时间:2013-02-13 19:00:52

标签: delphi memory delphi-xe2 string-formatting overwrite

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

例如:

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

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

MyObject (4E?|2010)

将'%p'替换为'%x'时,我也得到相同的结果:

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

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

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

MyObject (1291453120)

是否有我不知道的错误或者这与此处遇到的问题有关?

Why does Format crash when anything but "%s" is used with a Variant?

更新

我接受了Jeroen的回答,因为它让我通过淘汰过程找到了解决方案。在通过F7启动应用程序的情况之后(根据评论),我认为在此过程中必须出现问题。在预感,我禁用madExcept从其IDE菜单,重建应用程序,问题消失了。显然,无论代码madExcept链接到我的应用程序是什么导致在SysUtils常量TwoHexLookup中覆盖。重新启用madExcept和重建(我没有任何其他更改)也有效,所以在链接阶段肯定会有一些损坏。

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

2 个答案:

答案 0 :(得分: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;

Shows E with star and E with question mark

答案 1 :(得分:2)

由于这似乎是记忆覆盖(参见您的commentuser1008646),您可以尝试按照以下步骤操作:

  1. 首先尝试找出被覆盖的内存地址。你提到s := IntToHex(2129827392, 8);失败了。找出正确的值,然后找出它是否在TwoHexLookUp
  2. 如果它在TwoHexLookUp范围内,则设置数据更改断点(有关如何执行此操作,请参阅How to define a breakpoint whenever an object field value changes?Add data breakpoint。)
  3. 运行您的应用,直到断点发生。
  4. 广告1:可能最简单的方法是调查TwoHexLookUp哪个值更改具有相同的效果,以便在运行时观察到来自s := IntToHex(2129827392, 8);的错误结果。

    周四我正在客户端做一些Delphi工作,所以我可能有时间深入挖掘。

    修改
    当您使用F7逐步完成整个过程时,您确实首先进入SysInit

    你可以做的就是在TwoHexLookup数组上设置一个断点 然后是F9 / F8 / F7(取决于你想要的粒度)并在Watch窗口中关注数组。 这应该让你去。