2014-09-18 3 views
-4

У меня возникла странная проблема. Версия моего приложения Release работает нормально, но недавно, когда я переключился на версию Debug, я сразу же получил право на нарушение при запуске. Нарушение доступа происходит, когда освобожден блок выделенной памяти. Все это происходит в конструкторе для статической переменной.Очень странное поведение в новом/бесплатном

Я считаю, что проблема не возникает в версии Release просто потому, что я определил NDEBUG там, что, я считаю, отключает утверждения в среде выполнения C.

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

int *temp = new int[3]; 
delete[] temp; 

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

Любая помощь была бы принята с благодарностью. Я использую Visual Studio 2010 для компиляции приложения и запуска Windows 7.

Большое спасибо!

+5

Две строки кода, который вы написали, являются законными и совершенно точными. Должно быть что-то конкретное для вашего кода. Если он достаточно мал, чтобы сделать это, вы могли бы опубликовать [mcve] (https://stackoverflow.com/help/mcve)? – CoryKramer

+1

Глобальные статические переменные со сложными конструкторами задают проблемы. Посмотрите на одиночные игры. –

+1

Возможно, вы захотите попробовать использовать pageheap, чтобы узнать, возникают ли проблемы в вашей версии сборки. –

ответ

2

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

Отладка проблемы с поврежденной памятью на C/C++ очень сложна, потому что ошибка может быть вызвана любой другой инструкцией, влияющей на память. Например, если у вас есть два массива, которые следуют друг за другом в выделенной памяти, а первый массив переполнен, тогда он повредит заголовок, поставленный перед вторым массивом (каждое выделение памяти имеет префикс заголовка, этот заголовок используется операторы удаляют и удаляют [] при освобождении памяти). Однако, только когда вы попытаетесь освободить второй массив, который будет иметь нарушение доступа, и это, даже если это с первым массивом, есть ошибка в коде.

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

+0

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

+0

Я добавил немного больше информации в комментарии выше, но думал, что воспроизведу его здесь. Я исключил переменную, которая вызывала проблемы раньше, поскольку она не используется до тех пор, пока приложение не начнет работать. Теперь та же проблема возникает при первом вызове do '' 'delete []' '' в функции '' 'InitInstance''' во время запуска. Теперь я думаю, что вызов '' 'delete []' '' каким-то образом не приводит к действительному вызову в среде выполнения C, но я не уверен, как это произойдет. –

+1

Возможно, но если память уже повреждена, все, что с ней происходит после этого, может привести к нарушению доступа, и это, даже если следующие вызовы совершенно верны. Вы сами сказали, что не можете воспроизвести проблему в небольшом тестовом приложении.Вы должны изучить способ тестирования и/или проверки использования указателей и распределения/освобождения памяти в вашем приложении; например, путем подсчета их при запуске программы; добавив маркер в конец любого массива; убедившись, что операторы удаляют и удаляют [], никогда не смешиваются и т. д. и т. д. – SylvainL

0

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

BOOL CTempApp::InitInstance() 
{ 
    int *temp = new int[3] ; 
    delete[] temp ; 

    return FALSE ; 
} 

Даже со всеми моим кода приложений отбрасываются, проблема сохраняется. После этого я создал новый проект в Visual Studio 2010, снова заменил InitInstance своей минимальной версией, а затем добавил все Additional Dependencies из моего оригинального проекта в вариантах компоновщика. С этой конфигурацией проблема была воспроизведена.

Далее я начал удалять библиотеки из списка зависимостей. Мне удалось укоротить список вниз к одной библиотеке третьей стороны, которая вызывала следующее предупреждение компоновщика, несмотря на маркировку, как отладочная версия:

LINK : warning LNK4098: defaultlib 'msvcrtd.lib' conflicts with use of other libs; use /NODEFAULTLIB:library 

Я думаю, что здесь происходит, что продавец связал свою отладочную библиотеку против времени отладки. Предположительно, когда мое приложение вызывает delete[], возникает некоторая путаница в отношении того, что параметры для вызова, и пытается удалить часть памяти, которую я не выделил.

Я попытался добавить следующее к моему Ignore Specific Default Libraries списку:

libc.lib, libcmt.lib, msvcrt.lib, libcd.lib, libcmtd.lib 

как предложено here. Однако проблема сохраняется. Я думаю, что решение будет заключаться в том, чтобы связаться с продавцом и разрешить конфликт.

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

+1

Поиск в msvcrtd.lib показывает множество проблем с этой библиотекой и, в частности, следующее уведомление из https://qt-project.org/faq/answer/msvcrtd.libcinitexe.obj_warning_lnk4098_defaultlib_msvcrt.lib_conflicts_wit: «Это происходит потому, что Qt связан с версия выпуска C runtime , и ваше приложение построено с использованием символов отладки. Вам необходимо перестроить Qt в режиме отладки или в приложении в режиме выпуска ». – SylvainL

+0

Вот что я думаю ... Поставщик предлагает отдельные версии релизов и отладки своей библиотеки, но похоже, что зависимость от релиза пробилась в свою библиотеку отладки. Я сказал поставщику, что они скорее всего скомпилировали свою библиотеку или одну из ее зависимых библиотек, используя флаг '' '/ MD''' вместо' ''/MDd'''. –

Смежные вопросы