Пролог
В этом тексте я написал про две бесплатные утилиты для статического анализа Си кода: splint и Cpp-Check.
Статический анализатор - это такая консольная программа, которая проверяет Си исходники до компиляции. Своего рода автоматическая инспекция программ.
Суть этой короткой заметки в том, чтобы показать, как просто и лаконично происходит подключение разнообразных статических анализаторов к проекту, который собран скриптами сборки GNU Make.
SP-lint
Существует бесплатный статический анализатор. Называется splint (Secure Programming). Его можно скачать в составе CygWin. Tool(а) находит ошибки в коде. Вся документация 121 стр.

У SpLint много опций настройки. Каждое правило можно либо включать(по умолчанию включено всё) либо отключать(inhibit).
Вот приветствие утилиты:
C:\Users\U> C:\Users\U>where splint C:\cygwin64\bin\splint.exe C:\Users\U> C:\Users\U>splint Splint 3.1.2 --- 11 Sep 2013 Source files are .c, .h and .lcl files. If there is no suffix, Splint will look for <file>.c and <file>.lcl. Use splint -help <topic or flag name> for more information Topics: annotations (describes source-code annotations) comments (describes control comments) flags (describes flag categories) flags <category> (describes flags in category) flags all (short description of all flags) flags alpha (list all flags alphabetically) flags full (full description of all flags) mail (information on mailing lists) modes (show mode settings) parseerrors (help on handling parser errors) prefixcodes (character codes in namespace prefixes) references (sources for more information) vars (environment variables) version (information on compilation, maintainer) C:\Users\U>
Вот скрипт для запуска splint для каждого *.с файла из переменной окружения SOURCES_C
$(info static_analysis_code_base) MK_PATH_WIN := $(subst /cygdrive/c/,C:/, $(MK_PATH)) ARTEFACTS_DIR=$(MK_PATH_WIN)$(BUILD_DIR) REPORT_DIR=$(ARTEFACTS_DIR)/static_analysis/ INCDIR := $(subst /cygdrive/c/,C:/, $(INCDIR)) #$(info INCDIR=$(INCDIR)) WORKSPACE_LOC := $(subst /cygdrive/c/,C:/, $(WORKSPACE_LOC)) #$(info WORKSPACE_LOC=$(WORKSPACE_LOC)) STATIC_ANALYSIS_TOOL=splint.exe SPLINT_OPT += -noeffect SPLINT_OPT += -retvalbool SPLINT_OPT += -fullinitblock SPLINT_OPT += -exportlocal SPLINT_OPT += -type SPLINT_OPT += -retvalint SPLINT_OPT += -paramuse SPLINT_OPT += -nestcomment SPLINT_OPT += -nullassign #$(info SOURCES_C=$(SOURCES_C)) SOURCES_SA := $(subst .c,.sa, $(SOURCES_C)) static_analysis_code_base : $(SOURCES_SA) %.sa: %.c $(info StaticAnalysisStart) $(info ProcFile:$<) $(info FileDir:$(dir $<)) $(info SingleFile:$(notdir $<)) LOC_DIR_NAME=$(dir $<) $(info LocDir:$(LOC_DIR_NAME)) cd $(dir $<) && pwd && $(STATIC_ANALYSIS_TOOL) -preproc $(SPLINT_OPT) $(INCDIR) $(OPT) $(notdir $<)
В сущности этот скрипт определяет вот такой конвейер запуска утилит

Что касается впечатлений от использования splint анализатора, то splint мне помог найти использование локальных переменных до их инициализации. Это опция -usedef.

Достоинства splint
1--Splint бесплатный. Скачивается из CygWin

Недостатки splint
1--Иногда не может произвести синтаксический разбор некоторых участков кода.
2--Читает файл только при вызове из корня, где лежит файл. Надо командой cd переходить в папку которая содержит те файлы которые вы хотите проверять splint(ом)
3--Есть ложные срабатывания (Array element xxx[0] used before definition: -usedef)
Cpp-Check
Ещё есть статический анализатор Cpp-Check. Это скрипт для запуска cpp-check. Тут создается отдельная цель сборки специально для статического анализа кодовой базы, которая была избирательно проиндексирована make скриптами.
$(info static_analysis_code_base) MK_PATH_WIN := $(subst /cygdrive/c/,C:/, $(MK_PATH)) ARTEFACTS_DIR=$(MK_PATH_WIN)$(BUILD_DIR) REPORT_DIR=$(ARTEFACTS_DIR)/static_analysis/ INCDIR := $(subst /cygdrive/c/,C:/, $(INCDIR)) #$(info INCDIR=$(INCDIR)) $(info WORKSPACE_LOC=$(WORKSPACE_LOC)) WORKSPACE_LOC := $(subst /cygdrive/c/,C:/, $(WORKSPACE_LOC)) $(info WORKSPACE_LOC=$(WORKSPACE_LOC)) #$(error WORKSPACE_LOC=$(WORKSPACE_LOC)) INCDIR += -I$(WORKSPACE_LOC) STATIC_ANALYSIS_TOOL="C:/Program Files/Cppcheck/cppcheck.exe" #see https://habr.com/ru/articles/210256/ CPP_CHECK_OPT += -q CPP_CHECK_OPT += --enable=all CPP_CHECK_OPT += --suppress=sprintfOverlappingData CPP_CHECK_OPT += --suppress=preprocessorErrorDirective CPP_CHECK_OPT += --suppress=variableScope CPP_CHECK_OPT += --suppress=unreadVariable CPP_CHECK_OPT += --suppress=unmatchedSuppression CPP_CHECK_OPT += --suppress=missingIncludeSystem CPP_CHECK_OPT += --suppress=unusedFunction CPP_CHECK_OPT += --suppress=missingInclude CPP_CHECK_OPT += --suppress=redundantAssignment CPP_CHECK_OPT += --suppress=strdupCalled CPP_CHECK_OPT += --suppress=knownConditionTrueFalse CPP_CHECK_OPT += --suppress=constParameter #$(info SOURCES_C=$(SOURCES_C)) SOURCES_SA := $(subst .c,.sa, $(SOURCES_C)) static_analysis_cpp_check: $(SOURCES_SA) %.sa: %.c cd $(dir $<) && pwd && $(STATIC_ANALYSIS_TOOL) $(CPP_CHECK_OPT) $(INCDIR) $(OPT) $(notdir $<)
Запуск статического анализатора из make скриптов хорош тем, что тут Вы можете через аргументы командной строки утилиты cppcheck отключить проверку конкретных правил.
Итоги
Удалось научиться пользоваться бесплатными статическими анализаторами splint и cppcheck. Ожидания были выше чем результат. Максимум полезного, что находит анализатор splint это использование указателей, которые не были проверены на ноль.
Сppcheck оказался более полезным. CppCheck находит переменные в RAM, которые не меняются в коде.
Как можно заметить, если Вы собираете программу из самостоятельно написанных make скриптов , то Вы можете очень просто интегрировать статический анализ исходников. Буквань добавив 10-30 строчке в общий make скрипт сборки проекта.
В случае же сборки из IDE типа Keil или IAR Вам пришлось бы вручную писать циклопические *.bat скрипты с настройками для статического анализа, прописываю путь к каждому отдельному файлу.
Словарь
Акроним | Расшифровка |
SPLint | Secure Programming Lint |
IDE | integrated development environment |
RAM | random access memory |
URLs
