Как отследить нарушение прав доступа "по адресу 00000000"

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

но что, если сообщение об ошибке говорит

Access violation at address 00000000. Read of address 00000000.

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

9 ответов


нарушение доступа в любом месте рядом с адресом '00000000' указывает на доступ нулевого указателя. Скорее всего, вы используете что-то до того, как оно было создано, или после того, как оно было FreeAndNil()'d.

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

MadExcept делает его довольно легко отслеживать эти вещи вниз, и бесплатно для некоммерческого использования. (На самом деле лицензия на коммерческое использование также довольно недорогая и стоит денег.)


принятый ответ не говорит всей истории.

Да, когда вы видите нули, a указатель. Потому что NULL is по определению ноль. Так называя ноль NULL может быть, не так много.

что is интересным в сообщении, которое вы получаете, является тот факт, что NULL упоминается два раза. Фактически, сообщение, которое вы сообщаете, немного похоже на сообщения Windows-brand операционные системы показывают пользователя.

в сообщении говорится адрес NULL пытались читать NULL. Так что это значит? В частности, как адрес читается сам по себе?

мы обычно думаем о инструкциях при чтении и записи адреса из памяти по определенным адресам. Знание этого позволяет нам анализировать сообщение об ошибке. Сообщение пытается сформулировать, что - инструкции at адрес NULL пытались читать NULL.

конечно, нет никакой инструкции по адресу NULL, вот почему мы думаем о NULL как наш код. Но каждую инструкцию можно рассматривать как начинающуюся с попытки читать саму себя. Если процессоры EIP регистрация по адресу NULL, затем процессор попытается прочитать код для инструкции от адреса 0x00000000 (NULL). Эта попытка читать NULL произойдет сбой и сгенерирует полученное сообщение.

в отладчике обратите внимание, что EIP равно 0x00000000 при получении этого сообщения. Это подтверждает описание, которое я вам дал.

тогда возникает вопрос: "почему моя программа пытается выполнить NULL адрес.- На ум приходят три возможности:--23-->

  • у вас есть попытка сделать вызов функции с помощью указателя функции, который у вас есть объявлено, назначено NULL, никогда не инициализируется иначе, и разыменование.
  • аналогично, вы можете вызывать "абстрактный" метод C++, который имеет NULL запись в vtable объекта. Они создаются в коде с синтаксисом virtual function_name()=0.
  • в вашем коде буфер стека был переполнен при записи нулей. Нули записаны за пределами буфера стека, поверх сохраненного обратного адреса. Когда функция позже выполняет ret инструкция, значение 0x00000000 (NULL) загружается из области перезаписанной памяти. Этот тип ошибки, переполнение стека, является эпонимом нашего форума.

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

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


вы начинаете искать рядом с этим кодом, который вы знаю ran, и вы перестаете смотреть, когда достигаете кода Вы знаю не управлял.

то, что вы ищете, вероятно, какое-то место, где ваша программа вызывает функцию через указатель функции, но этот указатель равен null.

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

Это не обычный случай использования нулевого указателя, например ссылки на неназначенный объект или PChar. В этих случаях у вас будет ненулевое значение " at address x" стоимости. Поскольку инструкция произошла по нулевому адресу, вы знаете, что указатель инструкции CPU не указывал на какую-либо действительную инструкцию. Вот почему отладчик не могу показать вам, какая строка кода вызвала проблему-там is нет строчки кода. Вам нужно найти его, найдя код, который приведет к месту, где процессор перескочил на недопустимый адрес.

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


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

type
TTest = class(TForm);
protected
  procedure DoCustomEvent;
public
  property OnCustomEvent : TNotifyEvent read FOnCustomEvent  write FOnCustomEvent;
end;

procedure TTest.DoCustomEvent;
begin
  FOnCustomEvent(Self);  
end;

вместо

procedure TTest.DoCustomEvent;
begin
  if Assigned(FOnCustomEvent) then // need to check event handler is assigned!
    FOnCustomEvent(Self);  
end;

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


когда я наткнулся на эту проблему, я обычно начинаю смотреть на места, где я FreeAndNil() или просто xxx := NIL; переменные и код после этого.

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

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


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

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

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

посмотри Трассировщик Стека, что может помочь вам улучшить отладку.


Используйте MadExcept. Или JclDebug.


Я буду вторым madExcept и аналогичные инструменты, как Eurekalog, но я думаю, что вы можете прийти хороший путь с FastMM также. С включенным полным debugmode он должен дать вам некоторые подсказки о том, что не так.

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


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

  1. Ctl+Alt+Дель
  2. Откройте Диспетчер задач
  3. запишите имя программы, которая запрашивает доступ (вы не можете увидеть его во вкладке Приложения)
  4. нажмите на вкладку Процессы
  5. прокрутите, пока не найдете процесс, соответствующий имени программы и нажмите на него
  6. Нажмите End Процесс

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