【问题标题】:Format and Pointers/Hex Values (Memory Overwrite)格式和指针/十六进制值(内存覆盖)
【发布时间】:2013-01-29 10:30:31
【问题描述】:

在我的 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)

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

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

更新

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

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

【问题讨论】:

  • 如果这是真的,那肯定是一个错误......你有没有在一个空项目中发生过这种情况?
  • 看起来像个bug,你有重现它的例子吗?
  • 在你可以重现之前,这有点毫无意义。我们无能为力。您只需要一个简单的程序来演示故障。然后你提交一份质量控制报告。
  • @Doug:您可能错误地解释了结果吗?例如,Format 真的是System.Format 吗?你用什么方法读取Format返回的字符串?你确定MyObject 是你认为的那样吗?您的应用程序中是否存在内存损坏?
  • 感谢到目前为止的 cmets。 Andreas,我已经确认我正在调用 System.Format 以及所涉及的变量。 @David,感谢您澄清它不太可能是 RTL 中的错误,而是在我的代码中。如果我不能很快重现它,我会删除这个问题。 FWIW,我已经启用了 FastMM 中的所有选项(CheckForHeapCorruption、FullDebugMode 等),但到目前为止还没有出现任何东西。

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


【解决方案1】:

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

  1. 首先尝试找出被覆盖的内存地址。你提到s := IntToHex(2129827392, 8); 失败了。找出正确的值,然后找出它是否在TwoHexLookUp 之内。
  2. 如果它在TwoHexLookUp 内,则设置一个数据更改断点(有关如何执行此操作,请参阅How to define a breakpoint whenever an object field value changes?Add data breakpoint)。
  3. 运行您的应用,直到触发断点。

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

星期四我在一个客户那里做一些 Delphi 工作,所以我可能有时间深入挖掘一下。

编辑
当您使用 F7 逐步完成您的流程时,您确实首先进入了SysInit

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

【讨论】:

  • 损坏从 TwoHexLookup[227] 开始。我无法使用控制台应用程序重现这一点,如果我从 .dpr 文件的使用语句中删除 FastMM4 和 madExcept ,我将无法重现它。但是,即使在这两个单元初始化之前,调试器也会显示该值已损坏(并且它们在 uses 语句中首先出现 - 两个单元初始化部分中的断点尚未调用)。如果我从跟踪应用程序(F7)开始,调试器显示的第一行是 SysInit.pas 中的 1109 procedure _InitExe(InitTable: Pointer); 非常非常奇怪...
  • 澄清一下,我无法设置数据断点来查找问题,因为通过 F7 启动应用程序时损坏很明显。
  • 我已接受此作为答案,如我对原始问题的更新中所述。再次感谢大家的cmets。
  • @Doug SysInit 没问题。在我将很快做的答案中查看我的编辑。
【解决方案2】:

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

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;

【讨论】:

  • 是的,这是有道理的,感谢您复制它。覆盖将解释为什么这会在我的应用程序的完全不同领域给我带来问题。我可以通过简单地调用具有特定固定值(如s := IntToHex(2129827392, 8);)的 IntToHex 在同一位置复制它。我一定要覆盖那个记忆,但现在的诀窍是弄清楚它发生在哪里。你有什么隔离它的技巧吗?
  • 开始你的程序运行,也许在代码的第一行放一个断点。查看|调试窗口|断点。单击新断点按钮旁边的下拉箭头。选择数据断点。对于地址,输入 TwoHexLookup。大小将默认为 1024。确定完成。继续运行你的程序。一旦表被更改,断点就会触发并显示代码行。我为上面的代码做了这个,断点立即在“P^:=39;”上触发线。祝你好运。
  • +1,谢谢。它引导我找到答案,引导@Doug 逐步找到原因。
猜你喜欢
  • 2014-11-20
  • 1970-01-01
  • 2013-01-11
  • 2017-09-28
  • 2013-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多