компиляция с флагом o2 заставляет программу нарушать права доступа - PullRequest
2 голосов
/ 27 мая 2011

Я знаю, что это может быть один раз в жизни вопрос, но я застрял с ним, и я не могу думать ни о какой возможной проблеме, которая решает эту проблему, я написал код на C ++ (где-то около 500 строк в отдельностиклассы и файлы), используя Visual Studio, и хотя я компилирую его без флага оптимизации (/ od), он работает нормально, но когда я пытаюсь скомпилировать его, используя конфигурацию выпуска (флаг / o2 для оптимизации), программа выдает нарушение доступа и вылетает.после некоторой отладки я обнаружил, что значение this изменяется внутри одной из функций-членов, но я не вижу прямого использования указателя в стеке вызовов, если указатель изменяется, может ли кто-нибудь дать какое-либо предположение, что делает это возможнымтолько когда включена оптимизация?

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

что-то новое, что я обнаружил при попытке отладки с использованием дизассемблера, есть 13 push инструкций итолько 10 pop инструкций в функции, которая вызывает проблему (проблема вызвана последним всплыванием непосредственно перед ret инструкцией), это нормально или нет?(Я считаю все команды push, pop в вызываемых функциях.)

Ответы [ 2 ]

3 голосов
/ 27 мая 2011

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

Другими словами, у вас есть ошибка.

Это может быть в вашем уже проверенном коде или в том, как вы используете этот код.В любом случае, как сказал @Nim в комментариях, проверьте, где бы вы ни выделяли, и освобождайте память.Убедитесь, что ваши занятия следуют правилу трех.Убедитесь, что у вас нет переполнения буфера где-либо.И, возможно, попробуйте скомпилировать его с разными компиляторами.Используйте инструменты статического анализа (MSVC имеет / анализ, Clang имеет --analyze. В Linux может быть хорошей ставкой Valgrind).

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

3 голосов
/ 27 мая 2011

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

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

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

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

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

...