Что правильный инструмент должен обнаружить VMT или повреждение "кучи" в Delphi?

XML правильно построен, если отвечает требованиям для всех XML-документов, изложенных стандартами - так вещи как наличие единственного корневого узла, наличие узлов, правильно вложенных, все узлы, имеющие закрывающий тэг (или использующие пустую стенографию узла наклонной черты перед закрывающей угловой скобкой), атрибуты, заключаемые в кавычки и т.д. Быть правильно построенным просто означает, что придерживается правил XML и может поэтому быть проанализировано правильно.

XML допустим, если он проверит против DTD или схемы. Это, очевидно, отличается от случая до случая - XML, который допустим против одной схемы, не будет допустимо против другой схемы, даже при том, что это все еще правильно построено.

, Если XML не правильно построен, он не может быть правильно проанализирован - синтаксические анализаторы просто выдадут исключение или сообщат об ошибке. Это универсально, и не имеет значения, что содержит Ваш XML. Только, как только это анализируется, может он быть проверенным на законность. Этот домен или контекстно-зависимый и требует, чтобы DTD или схема проверили против. Для простых XML-документов у Вас не может быть DTD или схемы, в этом случае Вы не можете знать, допустим ли XML - понятие или законность просто не применяются в этом случае. Конечно, это не означает, что Вы не можете использовать его, это просто означает, что Вы не можете сказать, допустимо ли это.

5
задан 17 revs 23 May 2017 в 12:07
поделиться

10 ответов

У меня нет решения, но есть некоторые подсказки об этом конкретном сообщении об ошибке.

System.tobject.nheritsfrom вычитает постоянную vmtparent от самоуказателя (класса), чтобы получить указатель на адрес родительского класса.

В Delphi 2007 определяется VMTParent:

VMTParent = -36;

Итак, ошибка $ fffffffdd (-35) звучит как указатель класса - это 1 в этом случае.

Вот тестовый случай для воспроизведения его:

procedure TForm1.FormCreate(Sender: TObject);
var
  I : integer;
  O : tobject;
begin
  I := 1;
  O := @I;
  O.InheritsFrom(TObject);
end;

Я попробовал его в Delphi 2010 и получите «читать адрес FFFFFFD1», потому что VMTParent отличается между версиями Delphi.

Проблема в том, что это происходит глубоко внутри Bold Framework, чтобы у вас возникли проблемы с охраной для него в вашем приложении.

Вы можете попробовать это на ваших объектах, которые используются в коде DmattraCStimers (которые, как я предполагаю ваш код приложения):

Assert(Integer(Obj.ClassType)<>1,'Corrupt vmt');
5
ответ дан 18 December 2019 в 09:07
поделиться

Вы пишете, что хотите, чтобы было исключение, если

есть запись по адресу памяти, который не выделен приложением

, но это все равно происходит, как аппаратное обеспечение и ОС убедитесь в этом.

Если вы имеете в виду, что хотите проверить недопустимые записи в память в выделенном для вашего приложения диапазоне адресов, то вы можете сделать лишь так . Вы должны использовать FastMM4 , и использовать его с его наиболее подробными и параноидальными настройками в режиме отладки вашего приложения. Это отловит много недействительных записей, обращений к уже освобожденной памяти и тому подобное, но не сможет отловить все. Рассмотрим висячий указатель, который указывает на другое записываемое место в памяти (например, середину большой строки или массива значений с плавающей запятой) - запись в него будет успешной,

6
ответ дан 18 December 2019 в 09:07
поделиться

Первое, что я сделал бы, - это добавил MadExcept в ваше приложение и получил трассировку стека, которая распечатывает точное дерево вызовов, что даст вам некоторое представление о том, что здесь происходит. Вместо случайного исключения и двоичного / шестнадцатеричного адреса памяти вам нужно увидеть вызывающее дерево со значениями всех параметров и локальных переменных из стека.

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

Например, в структурах памяти (классы или типы записей) можно организовать Magic1: Word в начале и Magic2: Word в конце каждой записи в памяти. Функция проверки целостности может проверить целостность этих структур, наблюдая за каждой записью Magic1 и Magic2, которые не были изменены по сравнению с тем, что они были установлены в конструкторе. Деструктор изменит Magic1 и Magic2 на другие значения, такие как $ FFFF.

Я также хотел бы добавить в свое приложение ведение журнала трассировки. Ведение журнала трассировки в приложениях delphi часто начинается с объявления формы TraceForm с TMemo, а функция TraceForm.Trace (msg: String) начинается как «Memo1.Lines.Add (msg)». По мере развития моего приложения средства ведения журнала трассировки позволяют мне наблюдать за запущенными приложениями на предмет общих закономерностей в их поведении и неправильном поведении. Затем, когда происходит «случайный» сбой или повреждение памяти без объяснения причин,

1
ответ дан 18 December 2019 в 09:07
поделиться

Мги, конечно, прав. (fastmm4 вызывает флаг fulldebugmode или что-то в этом роде.)

Обратите внимание, что это обычно работает с барьерами непосредственно перед и после выделения кучи, которые регулярно проверяются (при каждом доступе к heapmgr?).

Это имеет два последствия:

  • место, где fastmm обнаруживает ошибку, может отличаться от места, где это происходит
  • полная случайная запись (не переполнение существующего распределения) может не быть обнаружена.

Итак, вот некоторые другие вещи, о которых следует подумать:

  • включить проверку времени выполнения
  • просмотреть все предупреждения вашего компилятора.
  • Попробуйте скомпилировать с другой версией delphi или FPC. Другие компиляторы / rtls / менеджеры кучи имеют другую компоновку, и это может упростить обнаружение ошибки.

Если все это ни к чему не приводит, попробуйте упростить приложение, пока оно не исчезнет.

2
ответ дан 18 December 2019 в 09:07
поделиться

Я заметил, что таймер находится в трассе стека.
Я видел много странных ошибок, где причина была мероприятие таймера уволено после того, как форма, которую я освобождаю.
Причина в том, что в том, что на основе сообщения о событии таймера будет помещено в Que Message, а Noge обрабатывается BR для разрушения других компонентов.
Одним из способов этой проблемы является отключение таймера в качестве первой записи в уничтожении формы. После отключения приложения Time Call.ProcessMessages, поэтому любые события таймера обрабатываются до уничтожения компонентов.
Другой способ проверки, если форма уничтожает в момент времени. (CSDestreying в компоненте).

1
ответ дан 18 December 2019 в 09:07
поделиться

Похоже, у вас повреждена память данных экземпляра объекта.

Сама по себе VMT не повреждается, FWIW: VMT (обычно) хранится в исполняемом файле, а страницы, которые к нему привязываются, доступны только для чтения. Скорее, как говорит VilleK, это выглядит так, как будто первое поле данных экземпляра в вашем случае перезаписано 32-битным целым числом со значением 1. Это достаточно легко проверить: проверьте данные экземпляра объекта, вызов метода которого не удался, и убедитесь, что первое слово 00000001.

Если действительно повреждается указатель VMT в данных экземпляра, то вот как я найду код, который его повреждает:

  1. Убедитесь, что существует автоматический способ воспроизведения проблемы, не требующий пользовательского ввода. Проблема может быть воспроизведена только на одной машине без перезагрузки между воспроизведениями благодаря тому, что Windows может выбрать способ размещения памяти.

  2. Воспроизведите проблему и запишите адрес экземпляра данных, память которого повреждена.

  3. Повторный запуск и проверка второго воспроизведения: убедитесь, что адрес поврежденных во втором запуске данных экземпляра совпадает с адресом первого.

  4. Теперь, шаг в третий запуск, установите 4-байтовую точку останова данных на участок памяти, указанный в предыдущих двух запусках. Смысл состоит в том, чтобы прервать каждое изменение в этой памяти. По крайней мере, один разрыв должен быть вызовом TObject.InitInstance, который заполняет указатель VMT; могут быть другие, связанные с конструированием экземпляров, например, в аллокаторе памяти; и в худшем случае, соответствующие данные экземпляра могли быть переработаны из предыдущих экземпляров памяти. Чтобы сократить количество необходимых шагов, заставьте журнал точки останова данных стек вызовов, но на самом деле не сломать. Проверяяя стек вызовов после сбоя виртуального вызова, вы должны быть в состоянии найти плохую запись.

3
ответ дан 18 December 2019 в 09:07
поделиться

Я не запоминаю их в смысле rote запоминания кода или pseucode, но я всегда мог кодировать двоичный поиск и quicksort из памяти, потому что я знаю, как работает логика. Это происходит из изучения алгоритмов, которые я абсолютно рекомендую.

-121--2402957-

Ищите понимания вместо запоминания. Я нахожу, что это помогает мне работать с доказательствами алгоритма, чтобы получить внутреннюю работу того, что происходит, и это обычно доказано как хорошая мнемоническая стратегия.

-121--2402959-

Могут ли возникнуть проблемы с кодом повторного входа?

Попробуйте поместить защитный код вокруг кода обработчика событий TTimer:

procedure TAttracsTimerDataModule.AttracsTimerTimer(ASender: TObject);
begin
  if FInTimer then
  begin
    // Let us know there is a problem or log it to a file, or something. 
    // Even throw an exception
    OutputDebugString('Timer called re-entrantly!'); 
    Exit; //======> 
  end;

  FInTimer := True;
  try

    // method contents

  finally
    FInTimer := False;
  end;
end;

N @

0
ответ дан 18 December 2019 в 09:07
поделиться

Можно использовать функцию ACTION _ SHUTDOWN Intent , которая передается при завершении работы телефона. В документации говорится:

Приложениям обычно не нужно будет справляться с этим, так как действие переднего плана также будет приостановлено.

Другими словами, если вы должным образом реагируете на все события жизненного цикла для вашего Действия, нет необходимости использовать это, если вы действительно не хотите сделать что-то конкретное, связанное с завершением работы.

Функция ACTION _ SHUTDOWN была введена в API Level 4, другими словами, она будет отправляться только на телефоны под управлением Android 1,6 или более поздней версии .

Широковещательная рассылка осуществляется с помощью BroadcastReceiver . Это будет выглядеть примерно так:

public class ShutdownReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        //Insert code here
    }

}

Вам также потребуется запись в вашем Манифесте, например:

<receiver android:name=".ShutdownReceiver">
  <intent-filter>
    <action android:name="android.intent.action.ACTION_SHUTDOWN" />
  </intent-filter>
</receiver>

В зависимости от того, что вы делаете, другим вариантом будет использование ACTION _ BOOT _ COMPLETED Intent , который отправляется при перезапуске телефона.

-121--1159246-

Какая функция C++, по вашему мнению, поможет преобразовать 64-разрядный длинный в 32-разрядный int ?

-121--3677700-

Я думаю, что есть другая возможность: таймер запускается для проверки наличия «Сеансов Dangling Logon». Затем выполняется вызов объекта TLogonSession для проверки возможности его удаления (_GetMayDropSession), верно? Но что если объект уже уничтожен? Может быть, из-за проблем безопасности потоков или просто .Free вызов, а не FreeAndNil вызов (так что переменная по-прежнему < > nil) и т.д. В то же время создаются другие объекты для повторного использования памяти. Если вы попытаетесь получить доступ к переменной некоторое время спустя, вы можете/получите случайные ошибки...

Пример:

procedure TForm11.Button1Click(Sender: TObject);
var
  c: TComponent;
  i: Integer;
  p: pointer;
begin
  //create
  c := TComponent.Create(nil);
  //get size and memory
  i := c.InstanceSize;
  p := Pointer(c);
  //destroy component
  c.Free;
  //this call will succeed, object is gone, but memory still "valid"
  c.InheritsFrom(TObject);
  //overwrite memory
  FillChar(p, i, 1);
  //CRASH!
  c.InheritsFrom(TObject);
end;

Нарушение доступа по адресу 004619D9 в модуле «Project10.exe». Считывание адреса 01010101.

0
ответ дан 18 December 2019 в 09:07
поделиться

Можете ли вы опубликовать исходный код этой процедуры?

BoldSystem.TBoldMember.CalculateDerivedMemberWithExpression (BoldSystem.pas: 4016)

Итак, мы можем увидеть, что происходит в строке 4016.

А также представление ЦП этой функции?
(просто установите точку останова в строке 4016 этой процедуры и запустите. И скопируйте + вставьте содержимое представления ЦП, если вы попали в точку останова).
Итак, мы можем видеть, какая инструкция ЦП находится по адресу 00404E78.

0
ответ дан 18 December 2019 в 09:07
поделиться

Разве проблема не в том, что "_GetMayDropSession" ссылается на освобожденную переменную сеанса?

Я видел подобные ошибки раньше, в TMS, где объекты освобождались и ссылались на onchange и т. Д. (Только в некоторых ситуациях это давало ошибки, которые очень трудно / невозможно воспроизвести, теперь исправлены TMS :-)). Также с сессиями RemObjects я получил нечто подобное (из-за моей плохой ошибки программирования).

Я бы попытался добавить фиктивную переменную в класс сеанса и проверить ее значение:

  • публичная переменная iMagicNumber: integer;
  • конструктор create: iMagicNumber: = 1234567;
  • уничтожение деструктора: iMagicNumber: = -1;
  • «другие процедуры»: assert (iMagicNumber = 1234567)
0
ответ дан 18 December 2019 в 09:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: