Delphi 7 исключение не пойман - PullRequest
3 голосов
/ 09 октября 2008

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

try
  ...
except
  cleanup();
end;

просто чтобы заставить его вести себя. Но очистка никогда не будет сделана. При каких обстоятельствах исключение не попадает в ловушку? Это может произойти из-за некоторого переполнения памяти или из-за того, что приложение собирает довольно много данных.

О, и исключение, которое я получил до добавления try, было «Нарушение доступа» (что еще?), И окно ЦП указывает на очень низкие адреса. Любые идеи или указатели будут высоко оценены!

Ответы [ 7 ]

9 голосов
/ 09 октября 2008

«Очень низкий адрес», вероятно, означает, что кто-то пытался вызвать виртуальный метод для объекта, которого на самом деле там не было (т. Е. Было «ноль»). Например:

TStringList (ноль) .clear;

Первая часть очень загадочная. Я понятия не имею, как это может произойти.

Я думаю, вы должны попытаться поймать это исключение с помощью madExcept . Это никогда не подводило меня еще. (Отказ от ответственности: я не использую D7.)

7 голосов
/ 09 октября 2008

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

Если у вас переполнение буфера в буфере в стеке (например, статический массив как локальная переменная, но записан за ее конец), и перезаписана запись об исключении, то вы можете перезаписать указатель «next», который указывает следующая запись об исключении в стеке. Если указатель засоряется, ОС ничего не может сделать, чтобы найти следующий обработчик исключений и в конечном итоге достичь всеохватывающего.

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

2 голосов
/ 10 октября 2008

у вас есть много хороших ответов. самые дикие проблемы, которые мне приходилось преследовать, связаны с такими проблемами, как Барри. Я видел, как что-то происходило с разделом «Размеры памяти» проекта на странице линкера. я мог бы быть суеверным, но казалось, что больше не обязательно лучше. Вы можете рассмотреть возможность использования расширенного менеджера памяти FastMM4 - это бесплатно и очень полезно.

http://sourceforge.net/projects/fastmm/

Я использовал его с d7 и нашел некоторый доступ к устаревшим указателям и другим злым вещам.

Вы также можете захотеть создать способ отслеживания действительных объектов и / или инструментировать код другими способами, чтобы код сам проверял, как он работает.

когда я вижу доступ к адресам вроде 0x00001000 или меньше, я думаю о доступе к нулевому указателю. myStringList: = ноль; myStringList.Clear;

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

когда что-то странно нестабильно и следы стека оказываются бессмысленными и / или сильно меняющимися, я знаю, что у меня проблемы со стеком. один раз это в Controls.pas; в следующий раз это в mmsys.pas и т. д.

использование неверного соглашения о вызовах для DLL может также сильно испортить ваш стек. это связано с передачей / освобождением параметров при вызове / возврате из DLL.

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

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

Таким образом, я исправил довольно неприятные проблемы.

1 голос
/ 09 октября 2008

Я оставлю причины, почему исключение может не работать, Барри ...

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

try
  OutputDebugString('entering part abc');
  ... // part abc code here
except
  OutputDebugString('horror in part abc');
  raise;
end;
...   
try
  OutputDebugString('entering in part xyz');
  ... // part xyz code here
except
  OutputDebugString('horror in part xyz');
  raise;
end;

и запустите ваш код с DebugView на стороне ... (работает для приложений без графического интерфейса, а также для служб). Вы увидите, какая часть выполняется, и будут ли там обнаружены исключения.

1 голос
/ 09 октября 2008

Я имел обыкновение получать это странное поведение при вызове некоторого COM-объекта, который использовал соглашение о безопасном вызове. Этот объект / метод может вызвать исключение EOleException, не захваченное обычной попыткой / за исключением клиентского кода. Вы должны перехватить EOleException и правильно обработать его.

try
...
except
on E: EOleException do
...
end;

Я не знаю, является ли это проблемой, с которой вы сталкиваетесь. Но если это так, я рекомендую вам взглянуть на Реализовать обработку ошибок правильно , очень разъясняющий пост об обработке исключений в delphi.

Вы также можете включить опцию отладки IDE, чтобы останавливаться на исключениях в delhi, отслеживая трассировку стека.

0 голосов
/ 14 ноября 2008

Я получил исключения в блоках инициализации и финализации моего кода, которые madExcept даже не замечает. Это может произойти, если вы ссылаетесь на внешние DLL внутри этого блока try. Я не уверен в причине.

На самом деле (и спасибо @Gung за сообщение о бесполезности моего древнего ответа), я недавно прочитал это в древнем томе О'Рейли Дельфи. Вы должны поместить SysUtils в качестве первого (или второго после вашего нестандартного модуля диспетчера памяти) в DPR вашей основной формы, чтобы он постоянно находился в памяти со всей своей безупречной ловкостью. В противном случае, если он загружен из какого-либо другого модуля, он также будет выгружен с этим модулем, и вы можете поцеловать встроенную обработку исключений на прощание.

0 голосов
/ 13 октября 2008

Возможно, это DLL или COM-объект? Если это так, возможно, что хост-приложение устанавливает маску FPUExcpetion на что-то отличное от того, к которому привыкли Delphi. Переполнение, по умолчанию в Delphi, создает исключение, но маска FPUExcpetion может быть установлена ​​так, чтобы этого не происходило, а значение устанавливается в NAN. См. Раздел math.pas для получения дополнительной информации о FPUExceptionmask

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...