Пролог

В этом тексте я написал про две бесплатные утилиты для статического анализа Си кода: splint и Cpp-Check.

Статический анализатор это такая консольная программа, которая проверяет Си исходники до компиляции. Своего рода автоматическая инспекция программ.

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, которые не меняются в коде. Это позволяет уменьшить нагрузку на RAM память.

Акроним

Расшифровка

SPLint

Secure Programming Lint


URLs

Splint Manual

Splint

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

Безопасность встраиваемых систем Linux

Комментарии (1)


  1. NutsUnderline
    12.05.2025 06:20

    найти использование локальных переменных до их инициализации

    так более менее новые gcc на это дело вопят warning