В некоторых случаях при возникновении ошибок, во время отладки, компилятор показывает строчку дельфовых библиотек, где именно возникло исключение. Например обращение к несуществующему индексу массивов и прочих контейнеров, как здесь:
List1 := TList.Create;
List1.Add(P);
P := List1.Items[1];
Получим указание на строку: Error(@SListIndexError, Index);
в System.Classes
В больших многопоточных проектах отловить подобные ошибки через трассировку бывает крайне сложно, записывать лог после каждой строки — тоже не вариант. А хотелось бы знать строку своего проекта от куда это все началось. Как нибудь можно выявить искомую строку в режиме отладки?
Zam
1873 серебряных знака12 бронзовых знаков
задан 28 мар 2017 в 21:02
7
Для этого нужно:
- Текущее состояние стека. В нем хранится последовательность вызовов функций/процедур (Call Stack), которая привела нас в место возникновения исключения, а также значения всех локальных переменных и входных параметров всех этих функций/процедур.
- map-файл — информация о том по каким адресам в памяти расположены все наши глобальные переменные, функции/процедуры и их локальные переменные. Он генерируется компилятором.
На основании этих данных можно точно найти то что вам нужно.
Получить всю эту информацию в удобном виде можно либо в процессе отладки встроенным в delphi дебагером, либо с помощью компонентов типа EurekaLog, MadExcept, JclDebug и т.п. получать и сохранять в файл отчета об ошибках самой программой, работающей у клиента.
ответ дан 30 мар 2017 в 9:34
Герман БорисовГерман Борисов
10.2k13 серебряных знаков37 бронзовых знаков
Допустим, сделана опечатка и неправильно написано какое-нибудь ключевое слово. В этом случае при попытке запуска программы внизу появляется окно, в котором отображены сообщения об ошибках. При этом программа не запустится. Благодаря подсказке такую ошибку легко найти и исправить.
Частой ошибкой начинающих является пропуск конструкции begin – end в цикле. При
этом имеется в виду, что в цикле должны выполняться, например, обе команды, но на самом-то деле в цикле, конечно, будет выполняться только первая, а вторая выполнится только один раз – потом, когда программа выйдет из цикла. При попытке запуска появляется сообщение. Но это не ошибка, а предупреждение. В нем обращается внимание на то, что параметр цикла после выполнения цикла может быть неопределенным (он присутствует во второй команде).
Однако, несмотря на предупреждение, программа может запуститься. Если вводятся
дкакие-либо данные, то появляется сообщение об исключительной ситуации – exception. При этом программа приостанавливается, переходя из режима исполнения в режим отладки. Чтобы перейти к обычному редактированию кода, лучше остановить программу. Это можно сделать с помощью команды Program Reset. Затем можно поправить ошибку и вновь запустить программу.
В большие программы всегда закрадываются ошибки. Их надо быстро и квалифицированно найти и исправить.
Механизм исключительных ситуаций (exception)
одно из больших достоинств Delphi. С их помощью вы можете контролировать
возникновение ошибок и создавать в результате устойчивые к ошибкам программы.
По мере знакомства с языком и средой программист проходит несколько этапов. На
первом этапе он, по незнанию, путает типы, забывает ставить знаки препинания (например, точку с запятой в конце строки), некорректно использует операторы и т.п. В результате написанный им код в принципе невозможно исполнить. И это хорошо – 15 поскольку допущенные им ошибки оказываются автоматически выявленными на этапе компиляции, более того, часто среда программирования сама подсказывает, какая ошибка допущена, и, что важно, указывает строку, которую нужно поправить. По мере изучения языка и борьбы с синтаксическими ошибками программист плавно переходит к следующему этапу. Теперь он уже не делает таких простейших ошибок, но, поскольку сложность его программ возрастает, возрастает и вероятность совершения им ошибки, при которой программа все равно запустится. Поскольку, с точки зрения компилятора, явной ошибки нет, а некоторые странности кода, по-видимому, являются замыслом программиста. Однако компилятор все-таки сообщает об этих странностях с помощью предупреждений (Warning).
Советуем всегда обращать на них внимание, проверять при их появлении, нет ли ошибки, и вообще стараться писать код так, чтобы не было предупреждений.
Опасность таких скрытых ошибок состоит:
1) в том, что они таятся в той части кода, которую программист написал и уверен, что
она правильная (программа запустилась), а значит, и не очень внимательно будет
искать ошибку;
2) в том, что проявляется эта ошибка совсем в другом месте кода – не в том, в котором
допущена. А это приводит к долгим поискам ее по всей программе.
При возникновении исключительной ситуации можно проигнорировать ее и запустить
исполнение программы дальше, нажав F9. В этом случае программа выдает сообщение об ошибке. Необходимо найти ошибку – понять, в какой строке и почему происходит сбой. Для этого можно воспользоваться трассировкой. Для того чтобы определить первую строчку, начиная с которой будет проводиться трассировка, нужно поставить Breakpoint – точку останова.
Когда исполняемый код доходит до точки останова, исполнение программы
приостанавливается, и надо перейти в режим отладки. В режиме отладки можно исполнять последовательно программу по шагам, контролировать и изменять значения переменных и т.п. Этот режим служит для обнаружения и ликвидации ошибок. В этом случае появляется возможность просмотреть или изменить текущие значения переменных, однако изменение кода во время отладки невозможно. Измененный текст заработает только после перезапуска программы.
Чтобы выполнить текущую строку, на которой стоит курсор отладки, нажмите F7 или
F8. Строка выполнилась, и курсор сместился. Если необходимо перейти к следующей строке, то можно нажать F8, если нужно зайти в какую-либо функцию, то нажимают клавишу F7 и продолжают трассировку.
Для того чтобы в ходе отладки узнать значение той или иной переменной, нужно просто подвести к ней курсор. Появится hint со значением этой переменной. Это, однако, работает не со всеми переменными, а только с доступными в данный момент. Если нужно постоянно контролировать значение переменной, то еще проще добавить ее в список Watch.
Для более основательного слежения за значениями можете воспользоваться Списком Наблюдения (Watch List, Ctrl+F5).
Таким образом, при программировании среда Delphi может находиться в различных
режимах:
• Режим редактирования – режим, в котором редактируется код проекта,
модифицируется форма, добавляя на нее компоненты и настраивая их свойства. Это
основной режим.
• Режим исполнения программы – режим, в который среда переходит, как только
нажата клавиша F9 и был построен exe-файл. Фактически, в этом режиме происходиткак раз исполнение получившегося exe-файла проекта. Программа исполняется так,
как если бы ее вызвали не из Delphi, а просто из Windows.
• Режим отладки – в этот режим можно перейти из режима исполнения программы.
При этом программа будет приостановлена (но не остановлена совсем).
Чтобы продолжить трассировку (последовательный переход от команды к команде),
можете воспользоваться клавишами:
• F9 (Run) – продолжить программу, не трассируя ее.
• F8 (Step over) – выполняется текущая строка кода, и переходят к следующей строке.
• F7 (Trace Into) – то же, что и F8, с тем отличием, что если в текущей строчке
содержится вызов какой-либо функции или процедуры, то попадают внутрь этой
процедуры и трассируют ее до конца, затем из нее возвращаетс и переходят к
следующей строке (на которую перешли бы сразу, если бы нажали F8).
• F4 (Run to Cursor) – переход в режим исполнения программы до тех пор, пока не
должна будет выполнена строка, на которой стоит текстовый курсор (аналогично
тому, как если бы была установлена точка останова)
• Shift+F8 (Run Until Return) – процедура выполняется до конца.
• Ctrl+F2 (Program Reset) – остановка трассировки и переход в режим редактирования
кода. (Иногда целесообразнее, если это не грозит ошибками, продолжить исполнение
программы (F9) и выйти из нее нормальным образом, закрыв главную форму).
При работе в Delphi сообщение об ошибке фактически появляется дважды: сначала
выводится окно об исключительной ситуации и программа приостанавливается, а потом,
если нажать F9 (F8, F7 и т.п.), – возникает стандартное сообщение об ошибке Windows.
Итак:
1. Произошла ошибка.
2. Программа приостанавливается.
3. Выводится сообщение об exception. Это сообщение для программиста. Среда Delphi
сообщает, что программа не в состоянии выполнить какую-то свою команду.
Программист не предусмотрел возможность исключительной ситуации. Среда Delphi
приостанавливает программу, чтобы программист разобрался, где и в чем ошибка.
Отключить приостановку (2)–(3) можно, сняв флажок Menu => Tools => Debugger
Options => Language Exceptions => Stop on Delphi Exceptions.
4. Нажатие клавиши F9 (F8, F7 или др.).
5. Выводится сообщение об ошибке. Это сообщение для пользователя программы
(ситуация запуска приложения не из Delphi, а через exe-файл из Windows, т.е. не
существовует пунктов 2, 3, 4).
6. Программа продолжается (при этом она не сумела выполнить ту часть, в которой
произошла ошибка, и значит, если эта часть важная, продолжение может
сопровождаться дальнейшими ошибками).
Механизм обработки исключительных ситуаций заключается в том, что если
произошла ошибка (1) и не надо выводить (5), предпринимаются действия, чтобы (6) исполнялось корректно.
Для этого «опасная» команда (или целый блок) помещается внутрь конструкции try..except..end или try..finally..end.
Блок try..finally..end используется аналогично try..except.., но с тем отличием, что блок
команд между finally и end выполняется в любом случае, вне зависимости от того, было исключение между try и finally или нет.
|
|
|
Пожалуйста, выделяйте текст программы тегом [сode=pas] … [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как «свернуть» программу в трей.
3. Как «скрыться» от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
… (продолжение следует) …
Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.
Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка — 60 дней. Последующие попытки бан.
Мат в разделе — бан на три месяца…
Узнать где произошла ошибка по имеющемуся адресу
- Подписаться на тему
- Сообщить другу
- Скачать/распечатать тему
|
|
Junior Рейтинг (т): нет |
Здравствуйте. Сообщение отредактировано: IDontBelieveInSilence — 08.10.10, 19:35 |
CodeMonkey |
|
Пока висит окно — ставьте программу на паузу (вы ведь запускали под отладчиком?), потом Search/Go to address, вводите $05B47A7. |
IDontBelieveInSilence |
|
Junior Рейтинг (т): нет |
>Пока висит окно — ставьте программу на паузу (вы ведь запускали под отладчиком?), потом Search/Go to address, вводите $05B47A7. |
Rouse_ |
|
Moderator Рейтинг (т): 320 |
Обычно достаточно расрутить стек SEH фреймов. Достаточно грамотный пример идет в составе JEDY библиотеки, там как раз помимо этого показано как работать с линкуемой отладочной информацией и MAP файлом. |
Romtek |
|
пропагандист Рейтинг (т): 188 |
Адрес ошибки имеет значение только на машине клиента. Так что эта информация, на мой взгляд, пользы не несёт. Попробуйте скомпилировать тот модуль (если знаете какой именно или даже все, когда выбора нет) с отладочным журналом (log), ведя учёт времени входа и выхода критических участков кода. Затем попросите клиента прислать вам этот журнал. Нужно знать сначала как воспроизвести ту ошибку, а остальное — дело техники. |
northener |
|
Цитата IDontBelieveInSilence @ 08.10.10, 19:59 Нет, речь идет о баграпортах которые приходят от пользователей. Рекомендую http://www.eurekalog.com/index_delphi.php |
CodeMonkey |
|
Цитата IDontBelieveInSilence @ 08.10.10, 19:59 И вот, как мне узнать где именно там произошла ошибка, имея на руках только адрес? Никак. Чтобы это узнать, нужно знать актуальный базовый адрес blabla.dll на машине клиента в момент ошибки. Например, адрес ошибки — $05B47A7. blabla.dll была загружена по $0500000. Значит, смещение инструкции кода, вызывавшей ошибку, от начала DLL: $05B47A7 — $0500000 = $B47A7. Вы запустили программу у себя, поставили на паузу. На вашей машине blabla.dll имеет базовый адрес $0610000. Тогда вас интересует адрес $0610000 + $B47A7 = $06C47A7. К таким ситуациям нужно себя готовить заранее. EurekaLog, madExcept, JCL (JclDebug + JclHookExcept). |
IDontBelieveInSilence |
|
Junior Рейтинг (т): нет |
>К таким ситуациям нужно себя готовить заранее. EurekaLog, madExcept, JCL (JclDebug + JclHookExcept). |
northener |
|
Цитата IDontBelieveInSilence @ 09.10.10, 00:14
>К таким ситуациям нужно себя готовить заранее. EurekaLog, madExcept, JCL (JclDebug + JclHookExcept). Тогда не понятно почему вы задаёте свой вопрос именно тут? |
CodeMonkey |
|
Ответ на этот вопрос зависит от того, кто обрабатывает исключение в DLL. Если исключение передаётся вам — его должна поймать EurekaLog. Понятно, что вразумительное сообщение об ошибке при этом будет далеко не всегда. Но у вас будет хотя бы стек вызовов. Только вот сам стек вызовов будет нечитабелен — ведь в DLL, написанной на C++, нет никакой отладочной информации в любом «формате Borland» (map, TD и т.п.). Как правило, передавать исключения через границы модулей — плохая идея. Потому что обычно в языке исключение представлено объектом. Программа Delphi не знает, как обращаться с объектами C++, как их читать, как их освобождать (после обработки исключения). Поэтому, DLL обязана обрабатывать все исключения внутри себя, передавая во вне только индикацию ошибки. |
0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
0 пользователей:
- Предыдущая тема
- Delphi: Общие вопросы
- Следующая тема
[ Script execution time: 0,0356 ] [ 16 queries used ] [ Generated: 4.06.23, 21:03 GMT ]
0 / 0 / 0 Регистрация: 24.10.2009 Сообщений: 6 |
|
1 |
|
09.10.2013, 18:51. Показов 8431. Ответов 4
Привет всем! Есть код на Delphi 7, программа парсит в инете выбирает информацию. Код довольно большой. Вопрос в следующем как сопоставить адрес ошибки Access violation at address 0048AEC4 in module … read of address 00000000, с конкретной строкой в программе? Теоретически понятно, что где то программа обращается например к элементу массива, за его пределами, но при этом программа не ломается а продолжает выполняться. Так как запросы в инет на получение данных, она шлет по таймеру. Отловить ошибку не представляется возможным, т.к. модуль может работать часами и не сбоить, а может вывалиться, через пару минут. Отсюда вопрос как сопоставить адрес 0048AEC4 с конкретной строкой кода. Если кто в теме откликнетесь, перечитал кучу советов, бьюсь уже кучу времени и отдачи нет. Заранее спасибо!!!
0 |
пофигист широкого профиля 4658 / 3093 / 854 Регистрация: 15.07.2013 Сообщений: 17,841 |
|
09.10.2013, 20:57 |
2 |
Запустить программу под отладчиком, поставив точку останова там, куда процесс обязательно попадет (например на нажатие какой-нибудь кнопки, если в программе есть хотя бы одна кнопка). Когда процесс остановится, открыть меню Делфи -> Search -> Goto Address. В окошко ввести адрес указанный в сообщении об ошибке ($0048AEC4). Ну а затем попытаться развернуть стек вызовов глядя в окошко Call Stack (Меню Делфи -> View -> Debug Windows -> Call Stack. Если это для вас слишком сложно, то есть готовые средства. Например Эврика
2 |
Ivanjulai 0 / 0 / 0 Регистрация: 24.10.2009 Сообщений: 6 |
||||
09.10.2013, 21:20 [ТС] |
3 |
|||
Спасибо! Да чего я и боялся случилось… Предложенным методом нашел, что ошибка возникает в строке:
Которая в свою очередь находится в ComObj.pas из soursertlcommon вот и приехали… Я так понимаю исправить это сложно… Самое странное, что ни к каким видимым ошибкам она не приводит, кроме того, что программа встает колом и если сказать ОК и стартануть программу снова, она продолжает работать…
0 |
пофигист широкого профиля 4658 / 3093 / 854 Регистрация: 15.07.2013 Сообщений: 17,841 |
|
09.10.2013, 21:58 |
4 |
Так как запросы в инет на получение данных, она шлет по таймеру Вот кстати узкое место. Периодический процесс по таймеру с непредсказуемым временем окончания. Проверьте внимательно не может ли где что-то не успевать создаваться или уничтожаться? Или наоборот что-то уже уничтожено а к нему поступает задержавшееся обращение.
1 |
0 / 0 / 0 Регистрация: 24.10.2009 Сообщений: 6 |
|
10.10.2013, 18:42 [ТС] |
5 |
Спасибо, ясно где собака порылась… Хотя вроде логика там верная, таймер запускается, через определенное время, по завершению события DocumentComplit… Ладно главное теперь знаю как найти место ошибки, чего и добивался, еще раз спасибо!!!
0 |
← →
jen_bond
(2003-05-11 22:55)
[0]
При закрытие приложения возникает ошибка Access Valiation по адресу ….. Каким образом можно отладить, и найти место где возикает эта ошибка!!!!
← →
default
(2003-05-11 22:56)
[1]
напиши код
и всё будет тип-топ
← →
Vasiliy
(2003-05-11 23:09)
[2]
Гдето выполняешь Object.Free когда Object = nil
← →
evvcom
(2003-05-12 03:07)
[3]
> Vasiliy (11.05.03 23:09)
> Гдето выполняешь Object.Free когда Object = nil
Вовсе нет. На такие ошибки обычно Delphi сама выкидывает в отладчик. В данном случае ошибка выскакивает во время финализации юнитов/проекта. Я недавно такую искал. Оказалось, забыл в деструкторе написать MyComponent.Free; (в конструкторе было MyComponent := TMyComponent.Create(nil);) Т.е. компонент создавался, но за автоматическое уничтожение его никто не отвечал. Аналогично с TObject.
← →
Morfein
(2003-05-12 03:54)
[4]
>>jen_bond
Обычно ошибка при закрытии программы выскакивает при
неправильной работе с массивами… т.е. Вы где-то вышли за верхнюю границу массива в каком-то объекте(TMemo, TStringList, TList,…). Из-за резервирования памяти блоками, перезапись этой области отзывается ошибкой не сразу, а при уничтожении объекта.
>>Vasiliy
>>Гдето выполняешь Object.Free когда Object = nil
Это не запрещено. Метод Free производит проверку существования объекта.
← →
Anatoly Podgoretsky
(2003-05-12 08:07)
[5]
Метод Free не производит проверку существования объекта, только назначено что либо переменной или нет, точно такой же источник для ошибки.
Obj := TObj.Create;
Obj.Free;
Obj.Free; имеем ошибку, а по твоей логике не должно быть, так как Free проверил, что объекта нет.
← →
Morfein
(2003-05-12 10:29)
[6]
procedure Free;
Description
Use Free to destroy an object. Free automatically calls the destructor if the object reference is not
nil. Any object instantiated at runtime that does not have an Owner should be destroyed by a call to Free, so that can be properly destroyed and the memory released. Unlike Destroy, Free is successful even if the object is
nil, so if the object was never initialized, Free won’t result in an error.
© Delphi Help
Интересно получается… если объект никогда не был создан, то Free можно вызывать, а если создан и уже уничтожен, то нельзя…
← →
Palladin
(2003-05-12 10:34)
[7]
> Morfein © (12.05.03 10:29)
если создан и просто уничтожен то можно, но если он еще при уничтожении выставлен в Nil (например FreeAndNil(Obj)), то конечно же нельзя
← →
han_malign
(2003-05-12 10:35)
[8]
>Access Valiation по адресу …..
— вообще есть мизерный шанс локализовать строку где возникает ошибка по Map файлу, но в это место отладчик обычно и сам приходит…
← →
Anatoly Podgoretsky
(2003-05-12 10:39)
[9]
Morfein © (12.05.03 10:29)
Это у тебя интересно получается, если объект не создан, то точно также нельзя вызывать Free, тем более что в качестве доказательства ты сам же привел выписку из хелпа. Free
безопасно вызвать если переменная имеет значение
NIL, вне зависимости был создан объект или нет. И ничего другого.
Palladin © (12.05.03 10:34)
Ты чего то не то сказал
← →
Mikelson
(2003-05-12 10:50)
[10]
Почему бы не скомпилировать проект с debug dcu и по шагам посмотреть весь процесс завершения работы приложения?
← →
default
(2003-05-12 14:23)
[11]
заглянули бы в исходник Free и вопросов бы не было…
← →
Palladin
(2003-05-12 14:40)
[12]
звиняйте…
реализация free меня все время с толку сбивает, отождествление с Destroy…
Ошибки — неизбежное зло программирования. Видимо пока трудно даже представить средство с помощью которого можно избавится от них. Человеку, которые выдумает это чудодейственное лекарство, благодарные потомки-программисты, несомненно, воздвигнут памятник. Пока же остается лишь заниматься обычным делом: ловлей багов.
«Нарушение Доступа» — фраза, которую пользователи видят, когда приложение делает попытки обратиться к памяти, которая не обозначена для их использования — и как следствие происходит сбой в работе программы:
Access violation at address
in module .
Read of address
Ситуация при которой Windows давала бы полную свободу программам — записывай данные куда хочешь, скорее всего бы привела к разноголосице программ и полной потери управления над компьютером. Но этого не происходит — Windows стоит на страже «границ памяти» и отслеживает недопустимые операции. Если сама она справиться с ними не в силах — происходит запуск утилиты Dr. Watson, которая записывает данные о возникшей ошибки, а сама программа закрывается.
Известно что, при программирование, особенно крупных программных продуктов, уследить за всеми процессами в коде невозможно, да и нет необходимости. Использование сторонних компонентов и библиотек только усложняет дело. Именно поэтому программисты Delphi, порой и сталкиваются со «своенравными» программами, которые то и дело норовят «сбросить пользователя». Итак, давайте рассмотрим некоторые вопросы, связанные с корректной среды программирования, так и непосредственно проблемы написания кода, которые ведут к возникновению ошибок типа «ошибка доступа» (AVS) и очертим наиболее известные пути их исправления.
Мы можем поделить AVS, с которыми сталкиваются при разработке в Delphi на два основных типах: ошибки при выполнения и некорректная разработка проекта, что вызывает ошибки при работе программы.
Ошибки возникают при старте и закрытии Delphi или формировании проекта. Причиной могут являться сбои в «железе» компьютера.
Эти ошибки могут быть вызваны различными источниками, включая систему BIOS, операционную систему или аппаратные подпрограммы драйверов. Некоторые видео-, звуковые или сетевые платы могут фактически вызывать подобного рода ошибки в Delphi. Для решения подобных аппаратных проблем можно предпринять последовательность неких «стандартных» ходов:
проверить, что не имеется никаких конфликтов между установленными устройствами, устранить обнаруженные конфликты;
попробовать слегка уменьшить «аппетита» видеодрайвера — поставить меньшее разрешение;
в случае если у вас двухпроцесорная система обеспечить равное изменение шага для каждого процессора;
И в конце концов просто попытаться заменить драйвера на более свежие.
Но помимо чисто железных проблем — большую головную боль могут вызвать ошибки в работе программного обеспечения. Особенно это касается непосредственно операционной системы. Зачастую Windows терпит крах спонтанно. Вот рекомендации которые помогут вам создать более устойчивую среду программирования:
Хотя Windows 9X популярная система, разработку лучше проводить в Windows NT или Windows 2000 — это более устойчивые операционные системы. Естественно при переходе на них придется отказаться от некоторых благ семейства Windows 95/98/Me — в частности не все программы адоптированы для Windows NT/2000. Зато вы получите более надежную и стабильную систему.
Не забывайте о том, как важно всегда иметь под рукой свежие версии компонентов для Delphi и дополнительных библиотек. В отличие от Windows создатели данных пакетов стараются от версии к версии уменьшать количество ошибок.
Следите за тем, что бы устанавливаемые компоненты были предназначены непосредственно для вашей версии Delphi. Попробуйте деинсталлировать чужеродные компоненты один за другим (или пакет за пакетом) пока проблема не будет устранена.
Контролируйте все программные продукты установленные на вашей машине и деинсталлируйте те из них, которые сбоят. Фаворитами AV среди них являются шароварные утилиты и программы и бета версии программных продуктов.
Все вышеперечисленное в основном не касалось самого процесса программирования и в малой степени зависит от разработчика. Теперь же обратимся к теме, как не допустить при разработки программного продукта ситуации при которой, он сам будет являться причиной ошибки.
Вы могли бы рассмотреть компилирование вашего приложения с директивой {$D}, данная директива компилятора может создавать файлы карты (файлы с расширением map, которые можно найти в том же каталоге, что и файлы проекта), которые могут послужить большой справкой в локализации источника подобных ошибок. Для лучшего «контроля» за своим приложением, компилируйте его с директивой {$D}. Таким образом, вы заставите Delphi генерировать информацию для отладки, которая может послужить подспорьем при выявление возникающих ошибок.
Следующая позиция в Project Options — Linker & Compiler позволяет вам, определить все для последующей отладки. Лучше всего, если помимо самого выполняемого кода будет доступна и отладочная информация — это поможет при поиске ошибок. Отладочная информация увеличивает размер файла и занимает дополнительную память при компилировании программ, но непосредственно на размер или быстродействие выполняемой программы не влияет. Включение опций отладочной информации и файла карты дают детальную информацию только, если вы компилируете программу с директивой {$D+}.
Эта информация состоит из таблицы номеров строк для каждой процедуры, которая отображает адреса объектных кодов в номера строк исходного текста. Директива $D обычно используется совместно с другой директивой — $L, что позволяет или запрещает генерацию информации о локальных символах для отладки.
Таким образом вы без труда сможете найти точный адрес той подпрограммы, которая была ответственна за ошибку. Одна из наиболее общих причин ошибок выполнения — использование объекта, который еще не был создан. Если второй адрес при выдачи ошибки — FFFFFFF (или 0000000) Вы можете почти утверждать, что было обращение к объекту, который еще не был создан. Например, вызов метода формы, которая не была создана.
procedure TfrMain.OnCreate(Sender: TObject); var BadForm: TBadForm; begin BadForm.Refresh; // причина ошибки end;
Попытаемся разобратся в этой ситуации. Предположим, что BadForm есть в списке «Available forms » в окне Project Options|Forms. В этом списке находятся формы, которые должны быть созданы и уничтожены вручную. В коде выше происходит вызов метода Refresh формы BadForm, что вызывает нарушение доступа, так как форма еще не была создана, т.е. для объекта формы не было выделено памяти.
Если вы установите «Stop on Delphi Exceptions » в Language Exceptions tab в окне Debugger Options, возможно возникновения сообщение об ошибке, которое покажет, что произошло ошибка типа EACCESSVIOLATION. EACCESSVIOLATION — класс исключение для недопустимых ошибок доступа к памяти. Вы будете видеть это сообщение при разработке вашего приложения, т.е. при работе приложения, которое было запущено из среды Delphi.
Следующее окно сообщения будет видеть пользователь — и программа будет закрыта при совершение недопустимой операции:
Access violation at address 0043F193 in module 'Project1.exe' Read of address 000000.
Первое шестнадцатиричное число (‘0043F193’) — адрес ошибки во время выполнения программы в программе. Выберите, опцию меню ‘Search|Find Error’, введите адрес, в котором произошла ошибка (‘0043F193’) в диалоге и нажмите OK. Теперь Delphi перетранслирует ваш проект и покажет вам, строку исходного текста, где произошла ошибка во время выполнения программы, то есть BadForm.Refresh.
Естественно, что списка наиболее общих причин ошибок, вызывающих аварийное завершение работы программы, написанной в Delphi в чистом виде нет. Есть несколько общих «узких мест» в коде и структуре программы, когда подобная ошибка может произойти. Перечислим наиболее распространенные.
Недопустимый параметр API
Если вы пытаетесь передать недопустимый параметр в процедуру Win API, может произойти ошибка. Необходимо отслеживать все нововведения в API при выходе новых версий операционных систем и их обновлений.
Уничтожение исключения
Никогда не уничтожайте временный объект исключения. Обработка исключения автоматически уничтожает объект исключения. Если вы уничтожите объект самостоятельно, то приложение попытается уничтожать объект снова, и произойдет ошибка.
Zero:=0; try dummy:= 10 / Zero; except on E: EZeroDivide do MessageDlg('Can not divide by zero!', mtError, [mbOK], 0); E.free. // причина ошибки end;
Индексация пустой строки
Пустая строка не имеет никаких достоверных данных. Следовательно, попытка индексировать пустую строку — подобно попытке обратиться к нулю, что приведет также к ошибке:
var s: string; begin s:=''; s[1]:='a'; // причина ошибки end;
Обращение к динамической переменной
Вы должны строить обращение к динамической переменной корректно, иначе вы перемещаете адреса указателей и возможно разрушаете другие выделенные ячейки памяти.
procedure TForm1.Button1Click(Sender: TObject); var p1 : pointer; p2 : pointer; begin GetMem(p1, 128); GetMem(p2, 128); {эта строка может быть причиной ошибки} Move(p1, p2, 128); {данная строка корректна } Move(p1^, p2^, 128); FreeMem(p1, 128); FreeMem(p2, 128); end;
Вот и всё, Удачи!