Исключение нарушения прав доступа при вызове метода

У меня есть странная проблема здесь. Предположите, что у меня есть класс с некоторыми виртуальными методами. Под определенные обстоятельства экземпляр этого класса должен назвать один из тех методов. Большую часть времени никакие проблемы не происходят на том этапе, но иногда оказывается, что виртуальный метод нельзя назвать, потому что указатель на тот метод является НУЛЕВЫМ (как показано в VS), таким образом, исключение нарушения доступа к памяти происходит. Как это могло произойти?

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

UPD: хорошо, я вижу, что моя презентация проблемы довольно неопределенна, таким образом, схематично кодируют, похож

void MyClass::FirstMethod() const { /* Do stuff */ }
void MyClass::SecondMethod() const
{
    // This is where exception occurs, 
    // description of this method during runtime in VS looks like 0x000000
    FirstMethod(); 
}

Никакие конструкторы или деструкторы не вовлечены.

5
задан Lightness Races with Monica 29 July 2011 в 13:40
поделиться

7 ответов

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

Другой классический случай - неправильный указатель this, обычно NULL или низкое значение. Это происходит, когда ссылка на объект, для которой вы вызываете метод, неверна. Метод будет работать как обычно, но сработает, как только попытается получить доступ к члену класса. Опять же, это может быть вызвано повреждением кучи или использованием удаленного указателя. Удачи в отладке; это никогда не бывает легко.

5
ответ дан 14 December 2019 в 01:07
поделиться

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

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

Возможно (но маловероятно), вы каким-то образом уничтожили таблицу vtable.

Является ли указатель на функцию нулевым только для этого объекта или для всех других объектов того же типа? Если первый, то указатель vtable сломан, и вы смотрите не туда. Если последний, то разбивается сам vtable.

2
ответ дан 14 December 2019 в 01:07
поделиться

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

1
ответ дан 14 December 2019 в 01:07
поделиться

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

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

0
ответ дан 14 December 2019 в 01:07
поделиться

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

Попробуйте включить отладочную информацию в свойствах C++ проекта, пересобрать и перезапустить отладчик. Если это поможет, вы увидите все нормальные отслеживаемые вещи, такие как стек, переменные и т.д.

0
ответ дан 14 December 2019 в 01:07
поделиться

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

Вы не сказали, отлаживаете ли вы отладочную (не оптимизированную) или выпускную (оптимизированную) сборку. Обычно оптимизатор сборки Release удаляет этот указатель, если он не нужен. Итак, если вы отлаживаете оптимизированную сборку, отображение этого указателя как 0 ничего не значит. Вы должны полагаться на разборку, чтобы рассказать вам, что происходит. Попробуйте отключить оптимизацию в сборке Release, если вы не можете воспроизвести проблему в сборке Debug. При отладке оптимизированной сборки вы отлаживаете сборку, а не C ++.

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

0
ответ дан 14 December 2019 в 01:07
поделиться

Возможно ли, что указатель «this» удаляется во время обработки SecondMethod?

Другая возможность заключается в том, что SecondMethod фактически вызывается с недопустимым указателем прямо впереди, и что он просто работает (из-за неопределенного поведения) вплоть до вызова вложенной функции, которая затем завершается ошибкой. Если вы можете добавить код печати, проверьте, используются ли «this» и / или другие указатели на что-то вроде 0xcdcdcdcd или 0xfdfdfdfd в различные моменты выполнения этих методов. Эти значения (я считаю) используются VS при выделении / освобождении памяти, что может быть поэтому оно работает при компиляции в режиме отладки.

1
ответ дан 14 December 2019 в 01:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: