Ошибка артмани access violation at address

Обновлено: 06.07.2024

. when altering one's mind becomes as easy as programming a computer, what does it mean to be human.

11 мая 2009 г.

Access Violation в деталях

Примечание для студентов/новичков, пишущих на Delphi/C++ Builder: эта статья написана для диагностики исключений в вашей программе. Если вместо этого вы получаете ошибки от самой IDE (а не от вашей программы), например, access violation в пакете dclite60.bpl, то эта статья - не для вас. Чтобы решить проблемы с IDE - идите сюда. Краткий ответ: не надо использовать динозавров (Delphi 5/6/7), используйте современные IDE (Delphi XE и выше). Если всё же хочется динозавров, то часто причиной является DEP. Т.е. нужно добавить Delphi/Builder в исключения DEP. Ну или на крайний случай - отключить/удалить конфликтующий пакет.

Итак, для всех прочих (а именно: разработчиков Delphi/C++ Builder, пытающихся решить проблему возникновения исключения Access Violation в своей программе) - приступим!

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

  • если вы совсем начинающий или студент/студентка и получили Access Violation - первым делом включите опцию Range Check Errors (Project/Options, вкладка Compiler) и сделайте Project/Build.
  • если вы плохо или совсем не понимаете, что такое указатели и/или объекты - рекомендую сначала прочитать эту статью.
  • если вы плохо или совсем не умеете работать с отладчиком IDE (или даже не знаете, что это такое) - прочитайте сначала эту статью.

Каждая программа использует при работе память (*). Память занимает любая переменная в вашей программе. Будь это форма, компонент, массив, запись, строка или же простой Integer . Под некоторые переменные память выделяется автоматически (например, под переменные типа Integer и статические массивы), под другие - вы должны выделять её сами, явно (например, динамические массивы). Собственно, с точки зрения операционной системы каждая переменная характеризуется адресом в памяти (местоположением) и размером. Понятно, что обычно данные разных переменных не пересекаются - за исключением случаев обращением к одной области памяти через разные имена с помощью указателей.

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

Память для глобальных переменных выделяется загрузчиком ОС при загрузке исполняемого модуля программы в память и освобождается при выгрузке модуля (выходе из программы). Глобальные переменные - это любые переменные, объявление которых располагается вне класса или процедуры. Стек используется для размещения локальных переменных (объявленных в процедуре/функции) и служебных данных (типа адресов возврата и адресов обработчиков исключений). Куча же используется для размещения динамических данных.

Заметим, что для переменных динамических типов данных (динамические массивы, строки, любые объекты, компоненты), хотя сама переменная может размещаться в области для глобальных переменных или в стеке (а, значит, память для неё выделяется автоматически), но данные, на которые она указывает, всегда размещаются в куче и, зачастую, должны управляться вручную.

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

Иногда из-за ошибок в коде программы происходит ситуация, когда программа при выполнении пытается получить доступ к памяти, которая не была выделена или уже была освобождена. Когда такое происходит, процессор возбуждает исключение класса EAccessViolation . Обычный текст ошибки в приложении Delphi - "Access violation at address XXX in module 'YYY'. Write/read of address ZZZ" ("Нарушение доступа по адресу XXX в модуле 'YYY'. Попытка записи/чтения в ZZZ"). Хотя причина этого исключения всего одна (попытка обращения к недействительной памяти), но эта ошибка может проявлять себя в весьма разном виде и коде.

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

Как, собственно, бороться с этими ошибками? Ну, если вы получили EAccessViolation под отладчиком:



То нужно просто нажать на "Break" ("Ok" в старых версиях Delphi) и отладчик сразу же ткнёт вас на строчку с ошибкой. Также можно посмотреть стек вызовов (в меню Delphi - View/Debug windows/Call Stack):



В этом окне будет показано, как же вы туда попали. Читается это дело сверху вниз (текущее место помечено стрелочкой). Можно дважды щёлкать по строкам в этом окне для перехода в код, соответствующий этой строке.

Иными словами, отладчик сразу же тыркает вас в строку с ошибкой.



Не имеет значения, столкнулись ли вы с проблемой во время отладки или получили баг-отчёт от EurekaLog для уже распространяемой программы - хорошо бы подготовиться к этой ситуации заранее и включить опции проекта, упрощающие отладку. Как правило, это опции "Use Debug DCUs" и "Stack frames".

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

Если ситуация возникла у вас в отладчике, то тут всё относительно просто: вам нужно установить точку останова на проблемную строчку и проверить значения всех переменных и выражений, участвующих в ней - вот вам и причина ошибки, находится сразу же. Я не буду подробно останавливаться на теме отладки здесь, более подробно об этом написано в моей статье, часть 2 (осторожно: большой размер).

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

1. Во-первых, это всевозможные ошибки выхода за границы массивов. Например, типичная ошибка новичка может выглядеть так:
Если в вашей проблемной строке есть скобочки типа [], то у вас есть хороший довод к проверке допустимости выражения в [].

Обычно такие ошибки нужно отлавливать на стадии отладки, включая опцию Range Check Errors. Дело в том, что подобные ошибки весьма опасны тем, что могут пройти незамеченными (и потом редко ловятся при эксплуатации программы), даже более того - они могут разрушить стек, так что нельзя будет получить место возникновения ошибки. Но об этом позже.

2. Различного рода неверные передачи параметров. Обычно эти ошибки отлавливаются во время разработки и тестирования, нежели во время эксплуатации программы. Чаще всего они возникают при использовании процедур с нетипизированными параметрами. Сюда же относятся различные варианты ошибок переполнения буфера, например:
Для избавления от таких ошибок нужно просто внимательно изучать документацию на функции: что они ожидают увидеть и что вы действительно им подсовываете.

3. Передачи данных между двумя менеджерами памяти. Обычно ошибки такого плана возникают при передаче данных из DLL в приложение или наоборот. а также между двумя DLL. Чаще всего новички любят передавать из/в DLL строки типа String .

Причины этого я рассматривал ранее. Эти ошибки обычно отлавливаются немедленно во время разработки программы и очень редко доживают до рабочей программы. Решаются эти проблемы правильным проектированием.

4. Неверное объявление функций, импортируемых из DLL. Наиболее часто путают модель вызова. Если у вас получается EAccessViolation при вызове функции из DLL - просто внимательно посмотрите на её объявление и убедитесь, что её сигнатура верна - чаще всего пропускают модель вызова, stdcall или cdecl .

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

5. Отсутствие синхронизации при работе с потоками. Если вы делаете программу с использованием нескольких потоков, то у вас могут быть проблемы, если вы не обеспечили необходимой синхронизации. Например, любые обращения к VCL запрещены из вторичных потоков - вам нужно использовать Synchronize . Собственно, проблемы тут возникают, когда один поток меняет данные с которыми работает второй поток - что для последнего становится полной неожиданностью.

К сожалению, ошибки с синхронизацией потоков наиболее тяжело диагностировать. Лучшее, что вы можете сделать - прогарантировать, что такие проблемы никогда не возникнут: используйте Synchronize и/или заключайте код в критические секции при работе с разделяемыми потоками переменными. Иногда проблемы возникают из-за использования CreateThread вместо BeginThread или TThread (из-за отсутствия установки IsMultiThreaded ).

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

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

Проблема в том, что при освобождении компонента, его ссылка-переменная не меняется, продолжая указывать на уже удалённую память. Кроме того, локальные переменные не инициализируются автоматически при входе в процедуру и содержат мусор. Вот пример подобного рода ошибок:
Как мы уже говорили ранее, в приложениях Delphi есть служебный код, называемый "менеджером памяти", который отвечает за выделение и освобождение памяти в вашей программе и служит прослойкой между низкоуровневыми функциями операционной системы и вашим кодом. При всей своей пользе менеджер памяти, однако, добавляет в программу одну проблему: из-за него в программе находится куски памяти, которые выделены с точки зрения операционной системы, но свободны с точки зрения программы. Например, удалили вы компонент, но менеджер памяти не отдаёт память системе немедленно, придерживая её для дальнейшего использования.

Поэтому все ошибки доступа к памяти опасны в первую очередь тем, что могут пройти незамеченными. Например, мы обращаемся к уже удалённому объекту, но поскольку менеджер памяти ещё не отдал эту память системе, то обращение может пройти успешно. Чуть ранее мы говорили, что для предотвращения таких ситуаций вам нужно использовать FreeAndNil и другие механизмы. Ситуация ещё хуже с локальными массивами: дело в том, что локальные массивы размещаются в стеке, в котором обычно есть довольно большие участки размещённой памяти по краям массива. Что ещё хуже, эта память обычно реально используется программой (в отличие от памяти, которую мы освободили при удалении объекта), так что вы можете, спокойно промахнувшись, записать что-то не туда, и в итоге, ошибка всплывёт в совершенно другом месте из-за испорченных данных. Чтобы сделать ситуацию ещё хуже: в стеке хранятся и служебные данные программы, необходимые для её выполнения - это адреса возврата и обработчики исключений.

Например:
Весьма коварные ситуации, не правда ли? В зависимости от того, как именно мы ошибёмся в индексе массива, мы можем получить (**):
а). Программу, выдающую правильные результаты.
б). Программу, выдающую неверные результаты.
в). Программу, возбуждающую исключение.
г). Программу, вылетающую вообще.
Причём одна и та же программа с таким багом может показывать любое из этих поведений, смотря по тому, на какой машине она запущена и в каких условиях/окружении выполняется.

Вот почему чрезвычайно важно использовать опцию Range Check Errors во время разработки и тестирования.
Ну, вы можете также включить её и для release-версии кода, если не уверены в качестве своей стадии тестирования.

Итак, что, собственно, нужно сделать, когда мы получили Access Violation? Ну, с помощью предыдущего пункта мы находим строку с ошибкой, а дальше пытаемся по пунктам подставить возможные причины:
- Есть в строке []? - подумаем, а не может ли у нас быть неверный индекс?
- Есть работа с объектами? Проследим, какова логика работы - не удаляется ли объект раньше времени?
- Используем DLL? А правильно ли объявлена функция? А уж не обмениваемся ли мы динамическими данными (строками, там, массивами)?
и т.д.

Существенную помощь в таком анализе нам поможет следующий пункт.

Access violation at address XXX in module 'YYY'. Write/read of address ZZZ.



На первой вкладке вы можете видеть ассемблерный листинг своей программы. Приводится он здесь только для удобства - чтобы не надо было лезть ещё куда-то, чтобы подсмотреть его. Никакой информации он не несёт. А вот на второй вкладке вы можете видеть состояние регистров, (части) стека и (части) памяти в момент исключения. В данном случае мы смотрим на ассемблерный листинг и видим, что в проблемной команде участвуют регистры eax и edx . По вкладке CPU мы находим, что eax равен 0 , что означает, что мы пытаемся присвоить значение по указателю, равному nil . Взглянув на строчку исходника, которую мы узнали из стека вызовов, мы узнаем имя переменной. Вот вам и причина: переменная оказалась равна nil .

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

В следующий раз мы поговорим о ситуациях, когда у вас в коде есть ошибка, но никакого исключения не возбуждается. Частично мы уже говорили об этом здесь (например, пункт "1" и пункты "а"-"б" в конце второго раздела). Но в следующий раз мы пойдём чуть дальше и посмотрим, что ещё можно сделать для отлова таких ситуаций. И, в любом случае, у вас всегда есть возможность переписать код ;)

Критическая ошибка, она же более известна как «синий экран смерти», всегда влечёт за собой определённые последствия, так как её возникновение свидетельствует о том, что в работе операционной системы возникли серьёзные неполадки. Каждый пользователь, являющийся оператором компьютера, так или иначе, но сталкивался с проявлением подобной проблемы и знает, что далеко не всегда её решение лежит на «поверхности». Порой для исправления возникшей ситуации приходится прибегать к крайним мерам – это фактическая переустановка операционной системы Windows. Стоит ли применять данный способ в решении рассматриваемой в настоящей статье ошибки, в чём заключаются причины её возникновения. Обо всём об этом вы сможете прочитать ниже.

Исправление ошибки Access violation.

Причины и решения

Ошибка Access violation

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

  1. Проведите полную проверку операционной системы на наличие вирусной активности. Не прибегайте исключительно к услугам штатного антивируса, а обратите своё внимание на сторонние утилиты, к примеру, «DoctorWeb Curelt», «Malwarebytes» и «Adwcleaner». Проверьте всё тесно связанное с работой компьютера, включая внешние устройства хранения информации, которые подключались ранее к компьютеру, так как не исключено, что основная «зараза» засела именно там.
  2. Проверьте операционную систему на целостность компонентов, для этого:
    • Вызовите окно поиска, нажав на клавиши «WIN+S».
    • Введите в строку поиска «cmd.exe».
    • Кликните правой кнопкой мышки по найденному варианту и выберите «Запуск от имени администратора».
    • В открывшуюся консоль командной строки введите команду «sfc/scannow», после чего дождитесь завершения сканирования и следуйте советам утилиты, в случае если будут найдены какие-либо важные проблемы.

Сканирование диска командой

Процесс сканирования и внесение правок может быть продолжительным, но прерывать функционирование утилиты не рекомендуется. Дополнительно после завершения работы «sfc/scannow» можно обратиться к помощи команды «dism.exe /online /cleanup-image / restorehealth», инициировать работу, которой можно с помощью той же командной строки.

Проверка утилитой диска

  1. Также будет не лишним проверить используемые жёсткие диски и/или твердотельные накопители и наличие битых секторов, ошибки. Для этого подойдёт хотя бы штатная утилита «CHKDSK».

Вышеизложенные рекомендации носят обобщённый характер, так как их применение обосновано не только при возникновении каких-либо проблем в работе операционной системы, но и как профилактические меры по поддержанию качества функционирования Windows. Если ошибка не нашла своего решения и продолжается «терзать» пользователя, то следует прибегнуть к более точечным проверкам, которые заключаются в следующем:

  1. «Проверка реестра»:
    • Нажмите «WIN+R» и введите «regedit» для открытия окна редактора реестра.
    • В открывшемся окне найдите «HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon ».
    • Среди имеющихся в выбранном каталоге ключей найдите «Shell».
    • Если операционная система не была подвержена воздействую вирусного программного обеспечения, то значение данного ключа должно быть «Explorer.exe».
    • Здесь же найдите ключ «Userinit» его значение должно быть «C:\Windows\System32\userinit.exe».
    • Если хотя бы в одном из вариантов установлены другие значения, пропищите вручную корректные данные и перезагрузите компьютер.

Также будет не лишним прибегнуть к функционалу программы «CCleaner» для проверки реестра на ошибки. Основную проблему это может не решить, но добиться улучшения общего состояния операционной системы вполне реально.

  1. «Проверка корректности используемого драйверного обеспечения». Откройте «Диспетчер устройств» и удостоверьтесь, что все компоненты полностью работоспособны и среди них нет неизвестного устройства, которое было бы помечено жёлтым треугольником с восклицательным знаком внутри. Дополнительно можно обратиться к специализированному софту и проверить актуальность всех используемых драйверов.
  2. «Проверка качества работы программного обеспечения». Если рассматриваемая проблема проявилась при открытии какой-либо программы или игры, то попробуйте полностью удалить их и установить заново, но удостоверившись в том, что возможности вашего компьютера, а также версия операционной системы соответствует техническим требованиям продукта. Если игра была получена не совсем «честным/законным» путём, то попробуйте скачать другой репак или сменить основной источник. Если вы уверены в том, что вирусного программного обеспечения нет и проблема проявляется в отдельно взятом программном обеспечении при любых манипуляциях с ним, то можно попробовать внести данное ПО в список исключения DEP, для этого:
    • Откройте «Этот компьютер» (Мой компьютер) и кликом правой кнопкой мышки откройте «Свойства».
    • Далее выберите раздел «Дополнительные параметры системы».
    • На вкладке «Дополнительно» обратите внимание на блок «Быстродействие» и нажмите на кнопку «Параметры».
    • В открывшемся окне разверните вкладку «Предотвращение потери данных» и отметьте параметр «Включить DEP для всех программ и служб, кроме выбранных ниже» и нажмите «Добавить»
    • Найдите исполняемый файл проблемного программного обеспечения и укажите путь до него, после чего сохраните внесённые изменения.

Перезагрузите компьютер и проверьте качество работы Windows и работоспособность нужной вам программы/игры.

Заключение

К сожалению, как видно из всего представленного выше, в рассматриваемой ошибке нет каких-то конкретных причин возникновения. «Access violation», как и её собратья, является лишь следствием каких-либо сбойных моментов в работе Windows, поэтому и все приведённые рекомендации направлены на восстановление штатной работы OS. Всё сказанное в начале про переустановку Windows таковым и остаётся и в завершении статьи.

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

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

Как избавиться от ошибки обращения к памяти

  1. Чтобы это сделать, найдите значок на панели задач (трее) в виде стрелочки, нажмите её и появятся скрыты значки.
  2. Здесь выберите значок антивируса ПКМ.
  3. В контекстном меню обычно находится пункт «Карантин».

Пункт Карантин

Выберите его и проверьте содержимое. Если найдете там файлы программ, которым вы доверяете — удалите их из карантина. Если ошибка Access violation at address продолжается, необходимо переустановить данную программу и внести в антивирусе в список доверенных.

После этого попробуйте перезапустить компьютер и войти в ОС через последнюю удачную конфигурацию.

  1. Для этого при появления начального экрана нажмите клавишу F8 и не отпускайте до тех пор, пока не появится окно с несколькими способами запуска.
  2. Выберите «Запуск последней удачной конфигурации».
  3. В этом случае будет использована система с конфигурацией драйверов и реестра, которые работали до этого стабильно.

Проверка запуска оболочки Windows

Следующим шагом в исправлении ошибки Access violation at address … in module будет проверка запуска оболочки операционной системы.

  1. Откройте окно ввода команд — WIN+R.
  2. Введите следующую команду «Regedit» и подтвердите, нажав Enter.
  3. Откроются ветки, здесь выберите HKEY_LOCAL_MACHINE.
  4. Далее найдите ниже SOFTWARE.
  5. Здесь отыщите ветку Microsoft, ниже выберите Windows NT и CurrentVersion.
  6. И наконец выберите Winlogon.

Реестр ОС Windows

Когда вы откроете последнюю ветку в правой части появится окно со списком ключей и параметров, найдите здесь Shell. Его необходимо открыть как обычную папку, дважды нажав мышью. В исправной системе здесь должно быть значение Explorer.exe. Если у вас стоит иное — исправьте его и сохраните изменение. Точно так же нужно проверить ключ Userinit. Здесь по умолчанию установлено C:\windows\system32\userinit.exe. Если здесь указано что-то другое — исправьте. Далее выйдите из редактора и закройте все окна. Перезагрузите компьютер и проверьте, появляется ли ошибка.

Чистка системного реестра Windows

В некоторых случаях при ошибке Ошибка Access violation at address in module помогает очистка системного реестра.

Программа CCleaner

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

Другие методы решения ошибки «Access violation at address …»

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

Команда sfc

  • выберите внизу рабочего стола «Пуск» и введите в поиске «Командная строка»;
  • в результатах выберите её ПКМ и нажмите «От имени администратора»;
  • в черном окне введите «sfc /scannow» без кавычек.

Окно восстановления системы

  1. Снова откройте меню «Пуск», выберите поисковую строку и введите «Восстановление».
  2. В результатах найдите «Восстановление системы» — выберите его.
  3. Выберите пункт, который запустит восстановление.
  4. В следующем окне нужно будет выбрать точку, которую система создала ранее.
  5. Выберите её и подтвердите свои действия.

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

Adobe Creative Cloud в списке программ

  1. Выберите кнопку «Пуск», затем найдите справа раздел «Панель управления».
  2. В следующем окне отыщите «Восстановление или удаление программ».
  3. В списке найдите проблемное ПО и выберите кнопку «Удалить» на панели инструментов или в самом блоке (в зависимости от версии ОС).
  4. Далее вам нужно снова установить ПО из дистрибутива.

Восстановление или переустановка системы

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

  1. Для этого вставьте в привод диск и перезагрузите компьютер.
  2. Войдите в настройки подсистемы BIOS и выберите загрузку с дисковода.
  3. Перезагрузите компьютер и активируйте загрузку с оптического диска.
  4. После того, как будут установлены временные файлы, вы увидите окно, где предлагается переустановить систему с несколькими вариантами. Выберите «Восстановление системы».
  5. Далее найдите необходимое восстановление и нажмите «Готово».

Когда будет выполнено восстановление, проверьте наличие ошибки на компьютере. В том случае, если она снова возникает, придется переустановить Windows. Это можно сделать, не затрагивая файловый раздел жесткого диска. Это значит, что вы можете переустановить только систему на диске C:\, а другие диски, где обычно хранятся файлы пользователя не трогать. После переустановки системы вы точно избавитесь от ошибки Access violation at address … in module.

Как можно узнать место, где возникает эта ошибка?

P.S. Среда - C++ Builder 2009



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



Дело в том, что программа уже довольно большая (исходники с библиотеками и пр. - 500 Мб).
программе уже 4 года и она постоянно модифицируется. Ошибка выскакивает не сразу, а через 5-6 часов работы. Явно растущих массивов в программе нет.

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

Вылетает у Заказчика. Установить там Builder не могу, так же, как ждать 5-6 часов. Но могу периодически ходить смотреть, как работает.
В офисе стоит Builder, но нет того оборудования, что у Заказчика - полноценно не проверишь.

veb

Дождаться крэша, подцепиться отладчиком и начать отладку.

PS. Это чудо (builder) дружит с Dr.Watson и [мини]дампами?




как подцепиться отладчиком, не устанавливая Builder? А установить его у Заказчика не получится.

не знаю. может и дружит. А что это такое? (Dr.Watson и [мини]дамп?) как подцепиться отладчиком, не устанавливая Builder? А установить его у Заказчика не получится.

У Embarcadero в поставке идет Remote Debugger (рис.), думаю это то, что нужно? Он и в старых версиях Builder шел.

Прикреплённая картинка

veb

неважно. подцепиться, найти поток выбросивший окно, раскрутить его.

как подцепиться отладчиком, не устанавливая Builder? А установить его у Заказчика не получится.

Надо выяснить, поддерживает ли буилдер возможность удалённой отладки. В Visual Studio для этого используется Remote Monitor не требующий инсталяции

А что это такое? (Dr.Watson и [мини]дамп?)



Поэтому переформулирую вопрос: что изменить в опциях трансляции или линковки, чтобы при возникновении любой ошибки программа вылетала?

При работе программы периодически вываливается окошко "Access violation at address XXXXXXXX. Read of address YYYYYYYY".

Как можно узнать место, где возникает эта ошибка?

1. Не понял..
А разве "address XXXXXXXX" не есть тот адрес
где возникла проблема ?
Надо узнать, какая процедура какого модуля расположена по этому
адресу.

2. не помню в точности как там у Борланда.
У Микрософта можно окружать участки блоками

__except(FilterFunction(GetExceptionInformation(),__LINE__))

В FilterFunction получаем контекст (содержимое регистров)
и спасаем его в лог.
Дальше возимся в кишках программы, пока не определим какая
процедура располагается по адресу где происходит сбой.
Не факт, что виновата именно она. А дальше творческий
процесс понимания "что происходит".



А разве "address XXXXXXXX" не есть тот адрес где возникла проблема ?
Все "стремные" места программы окружены блоками, там,где от операционной системы или сторонних библиотек надо что-то открыть или создать. Где идет работа с памятью по указателям - проверяется их неравенство нулю. Но или где-то не проверяется, или я чего-то недопонимаю. Потому и пытаюсь найти это место.
Кстати, на такие ошибки блок try/catch наверно не реагирует, поскольку после нескольких произошедших ошибках системный Dr.Watson ничего не отметил в таблице ошибок.



можно зная начальный адрес загрузки, но я не знаю как его узнать Он по умолчанию постоянный - 0x400000. Задается в настройках линкера в проекте.

И судя потому, что "at address 00000000" это, вероятнее всего, указатель на необнаруженную в библиотеке функцию.
Я бы первым делом поискал по проекту "GetProcAddress" и посмотрел, возможно где-то ее результат не проверен.



Он по умолчанию постоянный - 0x400000. Задается в настройках линкера в проекте.
И все программы грузятся и запускаются по одному адресу? Всегда считал, что менеджер памяти ОС выделяет свободный в данный момент сегмент памяти и загрузчик грузит туда программу, меняя в ней нек.адреса.
По крайней мере так работал DOC.

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



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

Узнать можно разными способами.
1. WinMain (HINSTANCE hThisInst.
hThisInst - это и есть адрес загрузки модуля.
2. GetModuleHandle(LPCTSTR lpModuleName);
3. GetWindowLong + GWL_HINSTANCE

"подскажете что из этого можно выудить"
Попробовать отладчик уровня ядра - поставить Break Point
на обращение к адресу 0.
Не знаю, можно ли на современном компе запустить SoftIce.
Наверное, можно попробовать OllyDbg. Но я с ним никогда не работал.
Глава 10


Вот что ещё можно попробовать:
1. Заменим ExceptionFilter -
::SetUnhandledExceptionFilter (UEFilter);
// После ее вызова необработанное исключение, возникшее в любом из потоков процесса,
// приведет к вызову Вашего фильтра исключений
// Адрес фильтра следует передать в единственном параметре функции
// SetUnhandledExceptionFilter.

2. Прототип фильтра исключений:
LONG WINAPI UEFilter (PEXCEPTION_POINTERS pExceptionInfo);

3. Из структуры ExceptionInfo, адрес на которую передаст система,
можно получить контекст (содержимое регистров) и некоторую информацию.
В том числе адрес программы, из которого производится попытка чтения адреса 0.

Читайте также: