![]() | ||||||||||||||||||||||||||||||
![]() |
![]() |
|
|
|||||||||||||||||||||||||||
![]() |
|
Расширенные возможности IBM Rational Purify: настройка отчетов и инструментов PurifyИсточник: IBM Developerworks Россия Сатиш Чандра Гупта & Ананд Гаурав
IBM Rational Purify - это инструмент для точного обнаружения ошибок, связанных с нарушением целостности информации в памяти, которые очень трудно проанализировать и исправить другим способом. В этой статье мы расскажем о том, как использовать опции и директивы Purify, чтобы приспособить этот инструмент для нужд вашего приложения. IBM Rational Purify - это улучшенное средство обнаружения ошибок памяти, которое помогает быстро и точно локализовать проблемы, связанные с нарушением целостности информации. После оснащения приложения средствами Purify и его запуска Purify тщательно исследует каждое обращение к памяти и уведомляет о любой ошибке целостности данных еще до ее возникновения. Вы можете узнать о различных типах ошибок памяти и том, как использовать Purify для их обнаружения, из предыдущей статьи: Navigating "C" in a "leaky" boat? Try Purify ("Плывете по языку С в дырявой лодке? Попробуйте Purify."). В дополнение к созданию отчета об ошибках памяти, Purify включает несколько расширенных функций. Они позволяют настроить использование Purify в сложной среде для разработки программного обеспечения. В этой статье мы сначала дадим общий обзор опций и директив Purify. Затем вы узнаете, как использовать их для настройки следующих аспектов Purify.
Purify предоставляет широкий набор опций. Они предоставляют вам возможности точного управления использованием Purify. Опции делятся на два типа:
Опции периода сборки необходимо использовать во время оснащения средствами Purify. Например, если вы не хотите производить в своей программе проверку переполнения буфера, то при оснащении средствами Purify можно использовать опцию -static-checking.
Опции периода исполнения влияют, как следует из названия, на поведение программы в период ее исполнения. Например, можно указать средствам Purify показывать в отчетах об ошибках более длинные цепочки вызовов стека:
В дополнение к флагам, в строке вызова опции периода исполнения и сборки можно указать с помощью переменных окружения PUREOPTIONS и PURIFYOPTIONS.
Ранее указанные опции можно установить в оболочках sh, ksh или bash следующим образом:
В оболочках csh или tcsh можно использовать следующую опцию:
Для опций сборки указанные в строке вызова значения переопределяют значения той же опции, указанные в переменной окружения. Все опции периода исполнения (указанные с помощью строки вызова или переменной окружения), используемые при запуске оснащенной средствами Purify программы, хранятся в самой программе. Во время выполнения любая опция периода исполнения, указанная в переменной окружения, переопределяет значение той же опции, которая хранится в оснащенной программе (если только не использована опция периода сборки -ignore-runtime-environment ). Если вы предпочитаете другой способ, то в качестве альтернативы можно указать опции периода исполнения с помощью графического интерфейса пользователя Purify. В этом случае эти значения переопределяют значения тех же опций, указанных с помощью переменных окружения и строки вызова. Purify предлагает несколько опций периода сборки, чтобы получить доступ к справке и информации о версии:
Другой полезной опцией сборки является -print-home-dir . Она печатает имя каталога, где установлен пакет Purify. Ее можно использовать, например, чтобы запустить сценарий purify_what_options . Он позволяет узнать, какие опции были использованы во время оснащения:
Другим интересным вариантом использования этой опции является компилирование программы, которая включает файл purify.h для доступа к Purify API. Файл заголовков появляется в домашнем каталоге Purify, и эта команда будет содержать этот каталог в пути поиска подключаемых файлов, который указывается для компилятора:
Кроме опций командной строки, Purify позволяет указать различные директивы для тонкой настройки оснащения и отчетов об ошибках. Директивы помогают настроить использование Purify для конкретного проекта. Например, рассмотрим ситуацию, когда возникает ошибка памяти (скажем, неинициализированное чтение памяти, или UMR) в одной из функций (foo, например) в библиотеке стороннего разработчика (например, libfoo), которая используется в проекте. Эту ошибку вы исправить не можете. Вероятно, все, что вам остается, - это отправить отчет об ошибке производителю библиотеки и ждать исправления. Если вы не хотите видеть эту ошибку в отчете Purify, поскольку исправить ее невозможно, можно указать директиву suppress:
Это указывает Purify не показывать ошибки UMR в функции foo. Чтобы увидеть ошибки, скрытые директивами suppress, нужно в графической оболочке Purify из меню View выбрать пункт Suppressed. Purify позволяет точно указывать, что вы хотите видеть. Вот несколько примеров.
Purify обрабатывает директивы, указанные в файлах с названием .purify в следующих каталогах и в следующем порядке: 1. <purify-installation-home>/.purify 2. <users-home-dir>/.purify 3. <current-working-directory>/.purify В зависимости от того, для чего предназначена ваша настройка (для всех пользователей Purify, для всех ваших проектов или только для одного из проектов), можно редактировать одно из этих полей и добавлять туда директивы. Либо можно выбрать в графической оболочке Purify одну из тех ошибок, которые нужно подавлять, щелкнуть на ней правой кнопкой мыши. В появившемся контекстном меню выберите пункт Suppress. Появится диалоговое окно, показанное на рис. 1. В нем можно указать тип ошибки, цепочку вызова и т.д. Можно сделать подавление постоянным, указав местоположение соответствующего файла .purify и нажав кнопку Make permanent. Рисунок 1. Диалоговое окно Purify Suppression.
Другая директива, kill, работает в точности аналогично директиве suppress. Отличие состоит в том, что в первом случае сообщения недоступны в графическом интерфейсе, даже если использовать меню View > Suppressed Messages. Если ошибка происходит многократно (тысячи или десятки тысяч раз), то программа будет работать быстрее, если вместо подавления примените директиву kill. При оснащении программы средствами Purify также оснащаются все библиотеки, от которых прямо или косвенно зависит программа (например, libc), а программа привязывается к этим измененным библиотекам вместо оригинальных. Если каталог, содержащий библиотеку, доступен на запись, Purify создает оснащенную версию библиотеки в том же каталоге. В противном случае она создается в области установки Purify, в каталоге для кэширования, используемом по умолчанию. Есть несколько опций сборки, имеющих отношение к кэшу. Например, если вы не хотите, чтобы оснащенные библиотеки были разбросаны по разным каталогам, где располагались их исходные версии, а, наоборот, вы хотите хранить их в каталоге кэширования, то можно использовать опцию -always-use-cache-dir . Также можно указать выбранный каталог для кэширования вместо того, чтобы использовать каталог, заданный по умолчанию. Для этого используется следующая опция: -cache-dir=<dir-name> . С помощью этих опций можно удалить все оснащенные библиотеки из кэша, просто удалив указанный каталог для кэширования. При оснащении программы Purify оснащает библиотеку только в том случае, если она была изменена с момента последнего оснащения, либо если невозможно найти оснащенную версию библиотеки. Это помогает сэкономить время. Если вы не хотите использовать уже оснащенные версии библиотек, то можно использовать опцию сборки -force-rebuild , и Purify заново обработает все нужные библиотеки. Это полезно, если вы решили использовать расширенные опции оснащения (например, -static-checking-guardzone ), и хотите повторно принудительно провести обработку библиотек. Как правило, нельзя оснастить программу на одном компьютере, а затем запускать ее на другом. Причина очень проста. Программа зависит обычно от системных библиотек (например, libc). Эти библиотеки могут на разных компьютерах отличаться, в частности, из-за версии пакетов исправлений в различных операционных системах. Чтобы гарантировать, что каждая программа получает доступ к оснащенным библиотекам, соответствующим исходным библиотекам в той же самой системе, механизм кэширования в Purify организует оснащенные библиотеки на основе имени хоста. Кроме того, ваша программа может также зависеть от некоторых библиотек, написанных вами или сторонними производителями, которые одинаковы на всех компьютерах или даже совместно используются из одного сетевого ресурса. В подобной ситуации вы можете не захотеть, чтобы в кэше находилось несколько оснащенных версий этих библиотек для каждого имени хоста, поскольку эти копии будут идентичны, и их хранение - это просто трата дискового пространства. Этого можно избежать, используя механизм repure в Purify на платформах IBM® AIX®, Linux® и Solaris® UNIX®. При этом нужно во время оснащения позаботиться о нескольких вещах. 1. Во-первых, выберите путь, который существует на всех машинах. Причем реальное место, на которое указывает этот путь, должно быть для каждой машины локальным. Например, каталог /tmp существует на всех компьютерах с системой UNIX®, но он всегда локальный и совместно двумя машинами никогда не используется. Совет. Не используйте пути (например, свой домашний каталог или другие подобные места), которые видны другим компьютерам через сетевую информационную службу (Network Information Service, NIS) или сетевую файловую систему (Network File System, NFS). 2. Опция -local-cache-dir укажет Purify хранить оснащенные библиотеки, специфичные для системы, в месте, на которое указывает, например, следующий путь:
3. Вы можете запустить оснащенную программу на том же компьютере:
4. Если вы хотите запустить оснащенную программу на другом компьютере, просто "переочистите" ее на другой машине с помощью команды repure:
5. После использования команды repure можно запустить программу также и на другой машине:
6. Повторите этап с командой repure (шаг 4) для каждого компьютера, на котором вы хотите запускать оснащенную программу. Старые оснащенные файлы можно вычистить с помощью сценария pure_remove_old_files , расположенного в домашнем каталоге установленного пакета Purify:
Эта команда лишь удаляет оснащенные копии библиотек: файлы, чьи имена содержат _pure_ , и которые заканчиваются специфичными для совместно используемых библиотек расширениями, например, .so или .sl . Например, можно вычистить все оснащенные файлы, которые старше 14 дней и хранятся в любом месте файловой системы. Это делается следующей командой:
Работа Purify заключается в оснащении кода и вставке новых инструкций в нужные места программы для проверки правильности доступа к памяти. Проверка и сопровождение данных, необходимых для проверки, приводит к падению скорости работы. Иногда может потребоваться проверка ошибок памяти только в отдельных компонентах приложения. Например, в библиотеке стороннего разработчика, которую использует приложение, проверка ошибок памяти может не требоваться. В подобных случаях можно оснастить приложение средствами проверки лишь выборочно, исключив ненужные совместно используемые библиотеки. Этот механизм позволяет оснастить важные компоненты кода даже очень большого приложения, одновременно повысив скорость работы оснащенного приложения. Примечание: При исключении совместно используемой библиотеки Purify по-прежнему проверяет в выделяемой нее памяти ошибки управления динамическим распределением, например, утечки памяти. Вот как можно исключить библиотеку с помощью опции selective:
Можно использовать опцию -exclude-libs и предоставить список библиотек (разделенный двоеточиями), которые нужно исключить. В качестве альтернативы можно использовать директиву exclude в файле директив .purify :
Как уже объяснялось, в директивах звездочка (*) интерпретируется как любое количество вхождений любого символа Опция -selective заставляет Purify использовать более надежные алгоритмы для обнаружения и исключения ложных ошибок. Они могут возникать из-за исключения некоторых библиотек. Например:
Эти два примера характеризуют баланс между сокращением времени выполнения при запуске оснащенной версии программы и охватом обнаруживаемых ошибок. Поэтому нужно все тщательно взвесить и решить, какие совместно используемые библиотеки исключить. Для этого нужно подробно изучить роль, которая библиотека играет в приложении, и характер ее взаимодействия с приложением, в котором задействована память. Purify может определить ошибки переполнения буфера даже в коде, не оснащенном средствами проверки. Но это произойдет не тогда, когда ошибка, собственно, происходит, а позже, при освобождении буфера. Purify выдает сообщения об ошибках при их возникновении. Но поскольку у Purify нет возможности вставить команды проверки в неоснащенный код, в отчет не попадают никакие ошибки, связанные с этим кодом. Если использовать опцию -late-detect-logic , то Purify будет выполнять дополнительные проверки при освобождении блока динамически распределяемой памяти. При обнаружении переполнения буфера Purify выдаст сообщение об ошибке, связанной с попыткой записи вне выделенного блока памяти (Array Bound Write Late, ABWL). Ошибки управления динамически распределяемой памятью Purify предлагает несколько опций для контроля использования памяти и времени выполнения оснащенной программы. Когда программа освобождает блок памяти, Purify не освобождает эту память немедленно. Вместо этого освобожденный блок ставится в очередь типа "первый вошел - первый вышел" (First In-First Out, FIFO). Это позволяет Purify обнаруживать "повисшие" (т.е. указывающие на несуществующие объекты) указатели. Они возникают, когда программа пытается получить доступ к памяти уже после ее освобождения. Это так называемые ошибки чтения-записи освобожденной памяти (Free Memory Read/Write, FMR/FMW). Если бы мы позволили освободить блок сразу обратно в "кучу", то память бы можно было сразу после этого повторно использовать. Тогда у Purify не было бы возможности различить неправильный доступ к старому блоку и правильный доступ к новому блоку. По умолчанию длина очереди составляет 100. Когда очередь заполняется, Purify освобождает первый блок в очереди и добавляет в нее вновь освобожденный блок. Длину очереди можно поменять с помощью опции -free-queue-length=<value> . Более длинная очередь увеличивает время, в течение которого будут надежно обнаружены "повисшие" указатели на освобожденную память. Однако увеличение длины очереди также заставляет программу использовать больше памяти (реальной или виртуальной), поскольку действия со свободной памятью откладываются. Таким образом, увеличение длины очереди повышает вероятность обнаружения "повисших" указателей, но это достигается ценой большего расхода памяти. Свободная очередь используется только для маленьких блоков. Под маленькими понимаются блоки, не превышающие определенного размера. Большие блоки освобождаются сразу обратно в "кучу", чтобы избежать риска перерасхода памяти. Можно с помощью опции -free-queue-threshold=<value> указать граничное значение для помещения блока памяти в очередь. По умолчанию это значение составляет 10000 байт. Любой блок памяти, превышающий это значение, освобождается немедленно. В конце программы Purify сообщает обо всех утечках памяти. Если вы также хотите видеть все используемые блоки памяти, это можно указать с помощью опции -inuse-at-exit=yes . Аналогично, чтобы найти в конце программы используемые дескрипторы файлов, можно использовать опцию -fds-inuse-at-exit=yes . В системе AIX, если вам интересны лишь утечки памяти, можно использовать опцию -memory-leaks-only. Тогда Purify произведет лишь очень незначительное оснащение, предназначенное только для обнаружения утечек памяти и других ошибок управления динамической памятью, например, ошибок Freeing Memory Mismatch (FMM). В этом случае программа будет работать гораздо быстрее, поскольку Purify не будет делать своей обычной проверки при каждом доступе к памяти. В этой статье вы узнали об опциях и директивах Purify, об их использовании для управления кэшем Purify, об увеличении времени работы и используемой динамической памяти оснащаемой программы. Это поможет вам наилучшим образом настроить Purify для определенного приложения.
|
|