在我的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提出的用于检测内存损坏的策略是一项有用的练习,如果我遇到类似的情况,它应该证明是有价值的。
答案 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;
答案 1 :(得分:2)
由于这似乎是记忆覆盖(参见您的comment至user1008646),您可以尝试按照以下步骤操作:
s := IntToHex(2129827392, 8);
失败了。找出正确的值,然后找出它是否在TwoHexLookUp
。TwoHexLookUp
范围内,则设置数据更改断点(有关如何执行此操作,请参阅How to define a breakpoint whenever an object field value changes?和Add data breakpoint。)广告1:可能最简单的方法是调查TwoHexLookUp
哪个值更改具有相同的效果,以便在运行时观察到来自s := IntToHex(2129827392, 8);
的错误结果。
修改
当您使用F7逐步完成整个过程时,您确实首先进入SysInit
。
你可以做的就是在TwoHexLookup
数组上设置一个断点
然后是F9 / F8 / F7(取决于你想要的粒度)并在Watch窗口中关注数组。
这应该让你去。