вторник, 6 октября 2009 г.

Статический анализ кода

 Недавно, в моем проекте возникла проблема. Суть ее заключалась в не стабильных крэшах приложения, которые было очень трудно воспроизвести и редко повторялись, но тем не менее они присутстовали, чем сильно раздражали. Главая из версий, объясняющая их была до банальности проста – не коректная работа с памятью. На поиски освобожденных / не освобожденных объектов было потрачено не один день. Было найдено и справленно несколько других багов связанных с памятью, но это не привело к ожидаемому результату.
 Буквально недавно, я узнал, что в Xcode 3.2 есть возможность статического анализа кода. Статический анализ – это анализ выполняемый над версией кода, с целью выявления мест содержащих ошибки. Встроеный в Xcode 3.2 анализатор, основан на консольном анализаторе clang. Если вы щасливый обладатель OS X Snow Leopard и Xcode 3.2, то советую вам прочитать статью из эпловской документации:
иначе читаем далее.

Для начала нам предстоит установить анализтор clang. Для этого мы должны скачать архив checker-0.223.tar.bz2 с сайта:




и распаковать его, скажем, на рабочий стол. В итоге, на вашем рабочем столе, у вас окажется папка checker-0.223. Теперь переместим папку checker-0.223 в дирректорию /usr/bin. Запустите Терминал, перейдите на Рабочий стол и выполните команду:

sudo mv checker-0.223 /usr/bin/

Теперь перейдите в папку /usr/bin/ и создайте символьные ссылки на статический анализатор и просмотрщик результатов:

sudo ln -s checker-0.223/scan-build scan-build
sudo ln -s checker-0.223/scan-view scan-view

На этом установка анализатора завершена. Перейдем непосредственно к настройке проэкта. Настраивать особо много не прийдется, только Code sign и Base SDK. Для настройки Code sign, зайдите в настройки таргета, на вкладку Build, перейдите в секцию Code signing и для ключа Any iPhone Device выберете Don't Code Sign:





Теперь зайдите в настройки проэкта, на вкладку General и выберите iPhone Simulator 2.1 для Base SDK for All Configurations.



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

При установке Xcod'а, по умолчанию установливается замечательная консольная утилита xcodebuild. Она позволяет собирать ваш проект из под консоли. Именно связка xcodebuild + scan-build, даст нам возможность найти баги в нашем коде.

Создадим новый Window Based проект с названием TestProject и добавим в метод applicationDidFinishLaunching код:

NSString *testString;
NSString *testString2;
testString2 = [testString copy];


Сразу предупрежу вас, что код заведомо содержит ошибки. Они созданы с целью показать возможности статического анализатора.

Теперь сохраним проект, запустим консоль и перейдем в папку проекта. Остается только выполнить статический анализ. Очень хорошо, перед каждым анализом очистить проект. Для этого вызовете команду:


scan-build xcodebuild -configuration Debug clean

ну и после ее выполнения, запустите сам статический анализатор:

scan-build -k -V xcodebuild -configuration Debug

В результате, после билда и анализа у вас в консоль напишется что то типа того:





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

cd /var/folders/qE/qEWzPoglGVWOVJJ2d-amzU+++TI/-Tmp-/scan-build-2009-10-05-1
open index.html

В результате у вас загрузится браузер, в котором будет html отчет отображающий результат анализа:




Сам отчет разделен на 3 части:
  1. информация о билде (пользователь, дата путь);
  2. количество найденных багов, разбитые на категории;
  3. список файлов, в которых найдены баги.
Для удобства вы можете выбрать определенный тип ошибок, убрав или проставив галочки. Наибольший же интерес для нас представляет раздел Reports, в котором, как сказанно выше, отображается список файлов в которых найдены баги. Нажав на ссылку View Report, вы можете просмотреть подробный отчет по определенной ошибке в файле. В подробном отчете отображается линия в которой найдено уязвимое место и примерное описание что не так. Вам остается хорошенько проанализировать код, ведь анализатор не искуственный интеллект, и если уязвимость подтверждается, исправить ее.

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




четверг, 1 октября 2009 г.

Борьба с утечками памяти

Наверное 90% крэшей приложения связанно с некоректной работой с памятью. Иногда, в большом проэкте, чтоб отловить такой крэш может затратиться значительное время. И хорошо, когда по внешним признакам падения приложения(то есть на каком экране или при каких действия пользователя) можно определить из за чего именно оно упало. Но к сожалению не всегда так. Какие же первые меры необходимо принять, после крэша? На мой взгляд самое логичное и простое – это посмотреть, что вывелось в консоль дебагера. Чаще всего в консоли можно увидеть такое сообщение:

Первая фраза, из сообщения:
-[NewObject show]: unrecognized selector sent to instance 0x12179b0
указывает на то, что у объекта NewObject был вызван не существующий метод show. Здесь, все просто – возможны 2 варианта:
  • вы просто ошиблись с именем метода или со списком передваемых параметров;
  • NewObject не NewObject, а что то другое. Такой вариант возможен, когда вы используете авторелизные объекты. Вы посылаете сообщение объекту, который был уже освобожден и в итоге в переменной хранятся некоректные данные (к примеру указатель на другой объект). Так что вам предстоит кропотливый поиск освобожденного объекта.
Но за частую консоль не предоставляет никакой отладочной информации. Для такого случая в Xcode предоставляется средство позволяющее ускорить процесс поиска освобожденного объекта. Для активации этого средства необходимо прописать переменную окружения NSZombieEnabled и установить ее значение в YES. Для этого в группе Executables вызовте свойства для вашего executable: В появившемся окне перейдите на вкладку Arguments добавте перменную окружения NSZombieEnabled и установите ее значение YES. В итоге у вас должно быть нечто вроде этого: Теперь можете опять попробовать запустить приложение. В этом случае сообщение будет посодержательней: Ну а далее – знание проекта и ваша интуиция... Эти способы хорошо применять на часто повторяющихся крэшах, которые удается воспроизвести при определенных действиях. Но иногда возникает такое ощущние, что программа начала жить своей жизнью. То работает, работает при определенных действиях, а потом ни с того ни с его падает. В такой ситуации следует вводить “тяжелую артилерию”. Под тяжелой артилерией я понимаю интсрумент Leaks и статический анализатор кода, о котором я расскажу в следующей статье. Leaks – утилита, которая в реалтайме анализирует выделяемую и освобождаемую память и на основе полученных данных отображает объекты, которые утекают. Для того, чтоб запустить Leaks, выберете в меню Run – Start with Performance Tools – Leaks. Приложение установится в телефон/симулятор и запустится на выполнение. При этом у вас появится окно инструмента Leaks: Верхняя часть, ObjectAlloc, говорит нам о размере потребляемой памяти приложением. Нижняя часть – утечки памяти в прогамме. Если Leaks обнаруживает лики, они сразу же отобажаются в виде оранжевых пик и в виде записи процент – размер – адрес – объект. Более детальную ифнормацию вы можете посмотртеть в строке адреса, нажав на кружочек со стрелочкой: В появившемся окне наибольший инетерес вызывает столбец Responsible Caller, в который заносится метод и имя класса, у которого был вызван метод, произвевший утечку памяти. Остается только найти этот метод и исправить утекаемый объект.