Вопрос: Формат и указатели / шестнадцатеричные значения (перезапись памяти)


В 32-разрядном приложении Delphi XE2 (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)

Есть ли ошибка, о которой я не знаю, или это может быть связано с проблемой, испытываемой здесь?

Почему формат разбивается, когда что-либо, кроме «% s», используется с вариантом?

ОБНОВИТЬ

Я принял ответ Джероена, поскольку это привело меня к решению по процессу устранения. После того, как ситуация с запуском приложения через F7 (в соответствии с комментарием), я подумал, что что-то должно произойти намного раньше в этом процессе. По подозрению, я отключил madExcept из своего меню IDE, перестроил приложение, и проблема исчезла. Очевидно, какой бы код madExcept не связывался с моим приложением, это вызывало перезапись в константе SysUtils TwoHexLookup. Кроме того, работа по восстановлению madExcept и перестройке (без каких-либо других изменений с моей стороны) работала, поэтому на этапе связывания должна была произойти некоторая коррупция.

Стратегия Jeroen, изложенная для обнаружения коррупции памяти, была полезным упражнением и должна оказаться полезной, если я столкнусь с подобной ситуацией.


4


источник


Ответы:


Поскольку это, по-видимому, перезапись памяти (ср. комментарий  в user1008646 ), вы можете попытаться выполнить следующие действия:

  1. Сначала попробуйте выяснить, какой адрес памяти перезаписывается. Вы упомянули, что s := IntToHex(2129827392, 8); выходит из строя. Узнайте правильное значение, затем узнайте, находится ли оно внутри TwoHexLookUp,
  2. Если он находится внутри TwoHexLookUp, затем установите контрольную точку с измененной информацией (см. Как определить точку останова при изменении значения поля объекта?  а также Добавить точку останова данных  о том, как это сделать).
  3. Запустите приложение до тех пор, пока не остановится точка останова.

Объявление 1: возможно, самый простой способ - изучить TwoHexLookUp изменение значения имеет тот же эффект, чтобы получить неправильный результат из s := IntToHex(2129827392, 8); как вы наблюдаете во время выполнения.

Четверг. Я делаю работу над Delphi у клиента, поэтому у меня могло бы быть время, чтобы копать немного глубже.

редактировать
Когда вы проходите свой процесс с помощью F7, вы действительно попадаете в SysInit первый.

То, что вы можете сделать там, уже установило точку останова на TwoHexLookup массив.
Затем либо F9 / F8 / F7 (в зависимости от требуемой гранулярности), и следите за массивом в окне Watch. Это должно заставить вас идти.


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;

Shows E with star and E with question mark


4