Повреждение кучи под Win32; как найти?

голоса
54

Я работаю на многопоточных приложениях C ++ , который развращает кучу. Обычные инструменты , чтобы найти эту коррупцию кажутся неприменимыми. Старый строит (18 месяцев) из исходного кода демонстрируют то же поведение , как самый последний релиз, так что это была вокруг в течение долгого времени и просто не заметил; на нижней стороне источника дельт не могут быть использованы для определения , когда ошибка была введена - есть много изменений кода в репозитории.

Запрос на сбой behaviuor заключается в создании пропускной способности в этой системе - передачи сокета данных, который потеряются во внутреннее представление. У меня есть набор тестовых данных, которые будут периодически вызывать приложение для исключения (различные места, различные причины - в том числе кучного Alloc упущение, таким образом: повреждение кучи).

Поведение кажется связано с мощностью процессора или пропускной способности памяти; чем больше каждая машина имеет, тем легче врезаться. Отключение гиперпоточного ядра или двухъядерное ядра с снижает скорость (но не устраняет) коррупцию. Это наводит на мысль о проблеме, связанных с ГРМ.

Теперь вот загвоздка:
когда он работает под средой легких отладок (скажет Visual Studio 98 / AKA MSVC6) порча кучи достаточно легко воспроизвести - десять или пятнадцать минут пройти , прежде чем что - то не чудовищно и исключение, подобно alloc;при работе в сложной среде отладки (Rational Purify, VS2008/MSVC9или даже Microsoft Application Verifier) система становится память скорость связана и не сломается (Memory переплет: процессор не становится выше 50%, диск не горит, то программа будет , как быстро он может, коробка потребляя 1.3Gиз 2G ОЗУ) , Итак, у меня есть выбор между возможностью , чтобы воспроизвести проблему (но не выявить причину) или быть в состоянии idenify причины или проблемы , которую я не могу воспроизвести.

Мои нынешние лучшие догадки о том, где к следующему является:

  1. Получите безумно грунты коробки (чтобы заменить текущее окно Dev: 2Gb RAM в E6550 Core2 Duo); это сделает возможным Репрографические аварии , вызывая неправильное поведение при запуске под мощной отладкой среды; или
  2. Перепишите операторы newи deleteиспользовать VirtualAllocи VirtualProtectотмечать память , как только для чтения , как только это будет сделано с. Запуск под MSVC6и имеют ОС поймать плохой парень , который пишет на освобожденной памяти. Да, это признак отчаяния: кто ад переписывает newи delete?! Интересно , если это будет делать это так медленно , как под Purify и др.

И, не: Доставка с Purify приборами встроенной пока не вариант.

Коллега только что прошел мимо и спросил: «Stack Overflow ли мы получать стек переполняется сейчас?!?»

А теперь вопрос: Как найти кучу Corruptor?


Обновление: баланс new[]и , delete[]похоже, получил длинный путь к решению этой проблемы. Вместо 15mins, приложение теперь идет около двух часов , прежде чем врезаться. Не там еще. Любые дополнительные предложения? Повреждение кучи сохраняется.

Обновление: релиз сборки под Visual Studio 2008 значительно лучше , кажется, текущее подозрение основывается на STLреализации , которая поставляется с VS98.


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

Возьму к сведению, что, но я обеспокоен тем, что доктор Уотсон будет отключен только после того факта, не тогда, когда куча становится растоптали.

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

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

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

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

И вы уверены , что все компоненты проекта имеют правильные настройки библиотеки времени выполнения ( C/C++ tab, категория Генерация кода в настройках проекта VS 6.0)?

Нет, я не так, и я потрачу пару часов завтра проходит через рабочую область (58 проектов в нем) и проверять все они компиляцию и компоновку с соответствующими флагами.


Обновление: Это заняло 30 секунд. Выберите все проекты в Settingsдиалоге, отмените пока вы не найдете проект (ы) , которые не имеют правильные настройки (все они имели правильные настройки).

Задан 04/08/2008 в 08:30
источник пользователем
На других языках...                            


15 ответов

голоса
26

Мой первый выбор был бы специальный инструмент куча таких как pageheap.exe .

Переписывание новые и удалять может быть полезно, но не поймать ALLOCS совершенных код нижнего уровня. Если это то , что вы хотите, лучше объехать low-level alloc APIс с использованием Microsoft Detours.

Также здравомыслие проверки, такие как: проверить свой матч библиотеки времени выполнения (освобождение против отладки многопоточных против однопоточных, DLL против статического Lib), обратите внимание на плохие удалений (например, удалять, где удалять [] должны были б), убедитесь, что вы не смешиваясь и вашим ALLOCS.

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

Что делает стек вызовов и т.д. выглядеть во время первого исключения?

Ответил 04/08/2008 d 08:51
источник пользователем

голоса
11

У меня те же проблемы в моей работе (мы также используем VC6иногда). И нет никакого легкого решения для него. У меня есть только некоторые намеки:

  • Попробуйте с автоматической аварией отвалов на производственной машине (см Process Dumper ). Мой опыт говорит д - р Уотсон не совершенен для захоронения.
  • Удалить все улов (...) из вашего кода. Они часто скрываются серьезные исключения памяти.
  • Проверить Advanced Windows Debugging - есть много отличных советов для таких проблем , как у вас. Я рекомендую это все свое сердце.
  • Если вы используете STLпопытаться STLPortи проверены сборки. Invalid итератор это ад.

Удачи. Такие проблемы, как ваши взять нас месяцы, чтобы решить. Будьте готовы к этому ...

Ответил 06/08/2008 d 13:41
источник пользователем

голоса
8

Запустите исходное приложение с ADplus -crash -pn appnename.exe Когда проблема памяти всплывает вверх , вы получите хороший большой дамп.

Вы можете проанализировать дамп , чтобы выяснить , что ячейка памяти была повреждена. Если вам повезет , перезапись памяти уникальная строка , вы можете выяснить , откуда она взялась. Если вам не повезло, что вам нужно будет копаться в win32кучу и понять , что были Orignal характеристики памяти. (куча -x может помочь)

После того, как вы знаете , что перепутались вверх, вы можете сузить AppVerifier использования со специальными настройками кучи. то есть вы можете указать , что DLLвы контролировать, или какой размер распределения для мониторинга.

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

По моему опыту, я никогда не нуждался в режиме полного кучи верификатора, но я потратил много времени, анализируя дамп (ов) и источники просмотра.

PS: Вы можете использовать DebugDiag анализировать дампы. Он может указать на DLLвладеющую поврежденную кучу, и дать вам другие детали ПОЛЕЗНЫЕ.

Ответил 16/09/2008 d 08:33
источник пользователем

голоса
7

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

В книге Стива Магуайр в Writing Solid Code (настоятельно рекомендуется), есть примеры отладки вещи , которые вы можете сделать в этих подпрограммах, как:

  • Следите за ассигнованиями, чтобы найти утечки
  • Выделяют больше памяти, чем это необходимо и поставить маркеры в начале и в конце памяти - во время свободного рутина, вы можете обеспечить эти маркеры все еще там
  • MemSet памяти с маркером о выделении (найти использование неинициализированной памяти) и на свободном (найти использование free'd памяти)

Еще одна хорошая идея заключается в том , чтобы никогда не использовать такие вещи , как strcpy, strcatили sprintf- всегда использовать strncpy, strncatи snprintf. Мы написали наши собственные версии этих , а также, чтобы убедиться , что мы не списываем конец буфера, и они поймали много проблем тоже.

Ответил 22/08/2008 d 18:11
источник пользователем

голоса
4

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

Для статического анализа рассмотрит компиляцию с PREfast ( cl.exe /analyze). Он обнаруживает несоответствие deleteи delete[], переполнение буфера и множество других проблем. Будьте готовы, хотя, пробираться через много килобайта предупреждения L6, особенно если ваш проект до сих пор L4не исправлен.

PREfast доступен с визуальной системой Studio Team и, по- видимому , как часть Windows SDK.

Ответил 12/10/2008 d 22:55
источник пользователем

голоса
3

Является ли это в условиях низкой памяти? Если так , то может быть , что новое возвращение , NULLа не бросать зЬй :: bad_alloc. Старые VC++компиляторы не должным образом осуществить это. Существует статья о неудачах распределения памяти унаследованных сбой STLприложения , созданные с VC6.

Ответил 02/09/2008 d 07:03
источник пользователем

голоса
3

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

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

Ответил 25/08/2008 d 20:55
источник пользователем

голоса
1

Если вы решили переписать новые / удалить, я сделал это и есть простой исходный код по адресу:

http://gandolf.homelinux.org/~smhanov/blog/?id=10

Это ловит утечки памяти, а также вставляет данные охраны до и после того, как блок памяти для захвата кучи коррупции. Вы можете просто интегрировать с ним, поставив #include «Debug.h» в верхней части каждого файла CPP, и определения DEBUG и DEBUG_MEM.

Ответил 17/09/2008 d 14:40
источник пользователем

голоса
1

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

  • Плохое использование кучи, то есть двойной освобождает, прочитать после свободного, писать после того, как бесплатно, установив флаг HEAP_NO_SERIALIZE с выделенными и свободным от нескольких потоков на одной куче
  • Недостаточно памяти
  • Плохой код (то есть, переполнение буфера, буфер обнуляется, и т.д.)
  • вопросы «Timing»

Если это вообще первый два, но не последний, вы должны поймали его сейчас либо pageheap.exe.

Что, скорее всего, означает, что это происходит из-за того, как код доступа к разделяемой памяти. К сожалению, отслеживание, что вниз будет довольно болезненным. Рассинхронизация доступ к общей памяти часто проявляется как странные «временные» проблема. Такие вещи, как не используется приобретает / высвобождение семантики для синхронизации доступа к совместно используемой памяти с флагом, не используя замки надлежащим образом, и т.д.

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

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

Когда вы испытывали с VS2008, вы работать с HeapVerifier с Сбережение памяти установлено значение Да? Это может уменьшить влияние на производительность кучи распределителя. (Кроме того, вы должны работать с ним debug-> Начать с Application Verifier, но вы уже знаете, что.)

Вы также можете попробовать отладки с Windbg и различными видами использования команды кучи!.

MSN

Ответил 22/08/2008 d 17:51
источник пользователем

голоса
0

Несколько предложений. Вы упоминаете обильные предупреждения в W4 - Я хотел бы предложить, что нашел время, чтобы исправить код для компиляции чисто на уровне предупреждения 4 - это будет пройти долгий путь к предотвращению тонким трудно найти ошибки.

Во-вторых - для / анализа переключатель - это действительно вызвало обильное предупреждения. Чтобы использовать этот параметр в своем собственном проекте, что я сделал, чтобы создать новый файл заголовок, который используется #pragma предупреждения, чтобы отключить все дополнительные предупреждения, генерируемые / анализ. Затем дальше вниз в файле, я включаю только те предупреждения, я забочусь. Затем с помощью переключателя / FI компилятор, чтобы заставить этот заголовочный файл будет включен первым во всех ваших единицах компиляции. Это позволит вам использовать / анализировать переключатель, приободрить выход

Ответил 03/10/2009 d 17:48
источник пользователем

голоса
0

Как вы думаете, что это состояние гонки? Делитесь несколько потоков одну кучу? Вы можете дать каждому поток личную кучу с HeapCreate, то они могут быстро бегать с HEAP_NO_SERIALIZE. В противном случае, куча должна быть поточно, если вы используете многопоточную версию системных библиотек.

Ответил 30/07/2009 d 14:48
источник пользователем

голоса
0

Мало времени я должен был решить подобную проблему. Если проблема все еще существует, я предлагаю вам сделать это: Контролировать все вызовы к новому / удалить и таНос / calloc / перераспределить / бесплатно. Я делаю единственный DLL экспортирует функцию для регистра всех вызовов. Эта функция приема параметр для определения исходного кода, указатель на выделенную область и тип сохранения этой информации в таблице вызова. Все выделено / освободила пара устраняется. В конце или после того, как вам нужно вы сделать вызов к другой функции для создания отчета для левых данных. При этом вы можете определить неправильные вызовы (новый / бесплатно или таНос / удалить) или пропали без вести. Если есть какой-либо случай буфер перезаписывается в коде информация, хранящаяся может быть неправильной, но каждый тест может обнаружить / открыть / включать решение отказа идентифицированное. Многие пробеги, чтобы помочь идентифицировать ошибки. Удачи.

Ответил 19/12/2008 d 12:52
источник пользователем

голоса
0

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

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

Это предположить, что количество размещенных кусков 64 байт только умеренное или у вас есть много памяти для записи в поле!

Ответил 02/09/2008 d 05:23
источник пользователем

голоса
0

Мое первое действие будет выглядеть следующим образом:

  1. Сборка бинарных файлов в версии «Release», но создание отладочной информации файла (вы найдете эту возможность в настройках проекта).
  2. Используйте Dr Watson как DEFUALT отладчик (drwtsn32 -I) на машине, на которой вы хотите, чтобы воспроизвести проблему.
  3. Repdroduce проблемы. Доктор Уотсон будет производить дамп, которые могут быть полезны для дальнейшего анализа.

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

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

И вы уверены, что все компоненты проекта имеют правильные настройки библиотеки времени выполнения (C / C ++ Вкладка, категория Генерация кода в VS настройки 6,0 проекта)?

Ответил 04/08/2008 d 09:26
источник пользователем

голоса
0

Вы пытались старые версии, но есть причина, вы не можете продолжать идти дальше в истории хранилища и увидеть точно, когда ошибка была введена?

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

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

Ответил 04/08/2008 d 08:48
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more