В частности, клиент пытался сделать так, чтобы диалог об ошибке показывался бы только для некоторых исключений. Делать он это пытался с помощью такого кода:
if AShowDlg then EI.Options.ExceptionDialogType := edtEurekaLog else EI.Options.ExceptionDialogType := edtNone;а проверял - на таком:
procedure TForm1.Button1Click(Sender: TObject); var List: TStringList; begin try List.Add('Test'); except on E: Exception do HandleError(E); end; end;Где
HandleError
- это код клиента по обработке исключения.При этом клиент утверждал, что "без EurekaLog всё работает верно", а "с EurekaLog после обработки тестогового исключения возбуждается (ещё один) Access Violation и приложение пропадает с монитора, но всё ещё показывается в диспетчере задач".
Видите ли вы проблему в указанном коде?
Проблема состоит в том, что тестовый пример использует неинициализированную переменную
List
. Это означает, что в ней может быть любое значение (равное произвольному мусору на стеке, оставшемуся после выполнения предыдущего кода).Так уж получилось (читай: "повезло"), что в приложении без EurekaLog этот мусор указывал на недопустимую область памяти, поэтому попытка вызова
List.Add
выбрасывала исключение Access Violation сразу же, при попытке вызова метода. Сообщение при этом выглядело следующим образом: 'Access violation at address 00000001 in module 'Project1.exe'. Read of address 00000001'. Заметьте, что оба адреса совпадают и являются недопустимыми.Однако когда в приложение была добавлена EurekaLog, ситуация изменилась, и на стеке оказалось иное мусорное значение. Так уж получилось (читай: "не повезло"), что этот мусор указывал на область памяти, в которой был записан адрес метода. Мы не знаем, какового было это значение на машине клиента, но при проверке у нас значение в памяти указывало на метод
TCustomForm.Create
. Поэтому вызов List.Add
на самом деле вызывал TCustomForm.Create
- с мусорным Self
(указывающим на главную форму) и мусорными аргументами. Разумеется, корректно отработать такое не может. Код VCL начинал выполнение, использовал мусор из аргументов, и в итоге вылетал при попытке зарегистрировать созданную форму в несуществующем Owner
. Сообщение при этом выглядело следующим образом: 'Access violation at address 004092F9 in module 'Project1.exe'. Read of address E8C78BD6'. Заметьте, что адреса различны; и первый адрес - корректен, а второй - нет.EurekaLog ловила это исключение (которое клиент ошибочно принимал за исключение при попытке вызова
List.Add
) и обрабатывала его корректно. Однако VCL при этом уже была в испорченном состоянии. Соответсвенно, при показе диалога EurekaLog (или после его закрытия) цикл обработки сообщений обращался к сохранённым мусорным данным, что и приводило к второму ("неправильному") исключению Access Violation (которое EurekaLog также ловила).Приложение же "пропадало" по той причине, что главная форма "затиралась", когда она передавалась как
Self
в TCustomForm.Create
.Именно поэтому, если вы хотите протестировать выброс исключений, то вам следует делать так:
List := nil; // - добавлено List.Add('Test');
Этот пример также отлично показывает почему вам следует перезапускать или закрывать приложение сразу после обработки исключения: ваше приложение может находится в испорченном состоянии. Действительно, если бы оно находилось в корректном состоянии, то непредвиденного исключения не произошло бы. А раз непредвиденное произошло, то приложение уже не находится в ожидаемом состоянии. Это означает, что его дальнейшее поведение не определено. Попытка продолжить выполнение может привести к порче данных, выбросу других, крайне сложно диагностируемых исключений, и так далее.
Конечно, при этом крайне важно отделять действительно "неожиданные" исключения от "штатных". К сожалению, это обширная тема, которая выходит за рамки этой заметки.
Комментариев нет:
Отправить комментарий
Можно использовать некоторые HTML-теги, например:
<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>
Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и (опционально) ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку.
Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.
Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.
Примечание. Отправлять комментарии могут только участники этого блога.