Покрытие кода OpenBSD

Как-то я написал заметку про обеспечение качества в проекте OpenBSD и написал, что в дереве исходного кода проекта есть регресионные тесты. Судя по статистике коммитов в 2014 году набор тестов увеличивается, но сами тесты запускались нерегулярно, а время от времени и из-за этого часть из них была сломана. В конце прошлого кода один из разработчиков взял себя в руки и настроил ежедневный запуск тестов на последнем снапшоте OpenBSD:

  On 15:35 Thu 08 Dec , Alexander Bluhm wrote:
  > Hi,
  > 
  > We are doing some regression and performance testing with OpenBSD
  > -currrent.  The daily results are published on this web site.
  > 
  > http://bluhm.genua.de/
  > 
  > bluhm

И сразу стало понятно состояние тестов - только 72% тестов из них были рабочими. Постепенно это количество Александр увеличил до 91%.

Мне стало интересно узнать какой процент кода OpenBSD покрывается этими тестами. До сих пор никто этого не делал (а если и делал, то не публиковал результаты).

Как известно, некоторые компоненты проекта популярны гораздо больше, чем сама ОС и используются отдельно от неё. Например это OpenSSH, LibreSSL и некоторые другие компоненты. По видимому вследствие популярности первых двух компонентов покрытие для них регулярно измеряет компания Froglogic - http://www.opencoverage.net/ и выкладывает результаты в публичный доступ, так в OpenSSH покрыто 30%, а в LibreSSL 27% кода. А вот для всех остальных компонентов процент покрытия неизвестен. Поэтому я решил это измерить его сам.

Вообще измерение покрытия для приложений, написанных на компилируемых языках, происходит так:

  • нужно инструментировать код приложения с помощью компилятора
  • скомпилировать приложение
  • запустить тесты для этого приложения
  • собрать результаты и сделать отчёт

В моём случае все оказалось чуть сложнее. Во-первых из-за системного вызова pledge(), во-вторых из-за отсутствия нужных функций в ядре. Дальше будут детали. Если вы хотите посмотреть на результаты измерений без деталей, то листайте в самый низ.

Коварный pledge()

В версии 5.9 добавили системный вызов pledge.2. Эта функция и одноименный системный вызов нужны для контроля разрешённых классов системных вызовов в модифицированном приложении. Если приложение нарушает правила и пытается вызвать системный вызов, не описанный в аннотации, то ядро принудительно завершит приложение сигналом SIGABRT. То есть для измерения покрытия приложению нужны системные вызовы, которые вовсе не обязательно описаны в коде этого приложения. Понять это получилось не сразу и тестирование приложений с поддержкой gcov сопровождались такими сообщениями:

Testing suffix "/usr/bin/gcc" "xx"
===> bc
rm -f *.log t19
t1
Abort trap (core dumped)
*** Error 134 in target 'regress' (ignored)
Abort trap (core dumped)
*** Error 134 in bc (<bsd.regress.mk>:106 'regress': @echo usr.bin/bc/t1 | tee -a /dev/null /dev/null 2>&1 > /dev/null)
*** Error 1 in /usr/src/regress/usr.bin (<bsd.subdir.mk>:48 'all')
# dmesg | tail -2
tee(5031): syscall 5 "rpath"
tee(79812): syscall 5 "rpath"
Abort trap (core dumped)
#

Решил проблему просто - сделал скрипт, который проверяет классы системных вызовов в каждом приложении и добавляет “wpath”, “cpath” и “rpath”, если они отсутствуют.

Покрытие кода ядра

С покрытием кода, работающего в пространстве пользователя, всё понятно. С ядром ситуация немного сложнее. Чтобы во время работы ядро генерировало информацию о покрытии нужно:

  • добавить в ядро дополнительные функции для сбора статистики об использовании функций ядра
  • изменить ldscript для ядра
  • написать утилиту, которая будет из памяти извлекать данные о покрытии

В 2004 году для FreeBSD эту работу уже делали, но насколько это сейчас работоспособно я не знаю.

Кстати ни одна ОС семейства BSD не измеряет покрытие кода. Интересно с чем это связано? Если доведу работу до конца, то буду первопроходцем :)

Результаты

Стандарт де-факто для создания отчётов это утилиты gcov и lcov проекта Linux Testing Project. Для меня удобнее gcovr, поэтому я сделал для утилиты порт, чтобы проще было устанавливать.

Чтобы сделать HTML отчёт нужно запустить её с такими опциями: gcovr --html --html-details --output=coverage.html --verbose --keep --print-summary --root `pwd` .

В результате у меня получился отчёт для всего кода, за исключением нескольких директорий: lib, libexec, gnu, regress, games, sys. Общий результат покрытия составил 10% - https://ligurio.github.io/openbsd-tests/6.0/coverage.html

Теги: softwareopenbsdtestingopensourcefeed