Сбой сборки /MT и /MD, но только тогда, когда отладчик не подключен:как отладить?[дубликат]

StackOverflow https://stackoverflow.com/questions/811951

Вопрос

На этот вопрос уже есть ответ здесь:

У меня есть небольшое однопоточное приложение на C++, скомпилированное и связанное с использованием Visual Studio 2005, которое использует boost (crc, program_options и tokenizer), немного STL и различные другие системные заголовки.

(Основная цель — прочитать файл .csv и создать собственный двоичный файл .dat и парный файл .h, объявляющий структуры, которые «объясняют» формат .dat.)

Инструмент дает сбой (нарушение прав доступа на NULL) при запуске вне отладчика, только в выпуске.Например.нажатие F5 не приводит к сбою инструмента, а сочетание Ctrl-F5.Когда я повторно подключаю отладчик, я получаю этот стек:

ntdll.dll!_RtlAllocateHeap@12()  + 0x26916 bytes    
csv2bin.exe!malloc(unsigned int size=0x00000014)  Line 163 + 0x63 bytes C
csv2bin.exe!operator new(unsigned int size=0x00000014)  Line 59 + 0x8 bytes C++
>csv2bin.exe!Record::addField(const char * string=0x0034aac8)  Line 62 + 0x7 bytes  C++
csv2bin.exe!main(int argc=0x00000007, char * * argv=0x00343998)  Line 253   C++
csv2bin.exe!__tmainCRTStartup()  Line 327 + 0x12 bytes  C

Строка, на которой происходит сбой, выглядит несколько безобидно:

pField = new NumberField(this, static_cast<NumberFieldInfo*>(pFieldInfo));

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

Проблема исчезает при компиляции с /MTd или /MDd (время выполнения отладки) и возвращается при использовании /MT или /MD.

NULL загружается из стека, и я вижу его в представлении памяти._RtlAllocateHeap@12 + 0x26916 байт кажется огромный смещение, как будто был сделан неправильный прыжок.

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

Удаление HeapValidate в начале и конце Record::addField показывает кучу OK вплоть до момента ее сбоя.

Раньше это работало - я не совсем уверен, что изменилось с момента последней компиляции инструмента (вероятно, много лет назад, возможно, в более старой VS).Мы попробовали более старую версию Boost (1,36 против 1,38).

Прежде чем вернуться к ручному исследованию кода или передать его в PC-Lint и прочесать его вывод, есть ли какие-нибудь предложения о том, как эффективно это отладить?

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

Это было полезно?

Решение

Одна небольшая разница между запуском с подключенным отладчиком и без него — это куча отладки ОС (см. также Почему мой код работает медленно, когда у меня подключен отладчик?).Вы можете отключить кучу отладки, используя переменную среды _NO_DEBUG_HEAP.Вы можете указать это либо в свойствах вашего компьютера, либо в настройках проекта в Visual Studio.

После отключения кучи отладки вы должны увидеть тот же сбой, даже если подключен отладчик.

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

Другие советы

Верификатор приложений было очень полезно для решения этой проблемы, когда у меня было _NO_DEBUG_HEAP=1 в среде, см. принятый ответ здесь: Как найти место, где память была освобождена в последний раз?

Наверное, стоит также упомянуть куча страниц, который я нашел, просматривая Application Verifier.Похоже, здесь речь идет о чем-то похожем.

(К вашему сведению, это было односимвольное переполнение буфера:

m_pEnumName = (char*)malloc(strlen(data) /* missing +1 here */);
strcpy(m_pEnumName, data);

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

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

Проверьте, можете ли вы перезаписать любое ранее выделенное пространство.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top