Skip to content

Static Analysis

Cisco edited this page Sep 26, 2025 · 4 revisions

Clangd

We have a .clangd file mirroring clang tidy check. On top of that, we use clangd on our IDE (vscode or nvim) as a linter.

We didn't manage to get reliable lints on vscode for unused headers. An alternative would be Include What You Use - IWYU

Clang tidy

  • clang-tidy is a static analysis tool which goes beyond a format linter and can help finding bugs and performance issue. The main check categories are

    • bugprone : suspicious casts, invalid/dangling pointers...
    • performance : unnecessary copy, ...
    • readability : naming, const correctness
    • best practices from C++ Core Guidelines
  • As for clang-format, it can be configured via a .clang-tidy file at the root of the project

  • Desactivate a check

    • globally by adding - prefix to the check in .clang-tidy
    • once inline by adding a // NOLINT(<rule>) in the code

clang-tidy is slower than cppcheck but is more accurate

Compilation database

clang-tidy and clangd need a compilation database compile_commands.json to trace back the flags and includes used at each file compilation

Using scan-build

pip install scan-build

# add PATH - update path with something like /home/<user>/.local/bin'
export PATH=$PATH:<path>

Generate the compilation database with intercept-build make <target>

Clang tidy checks

bugprone

  • bugprone-assignment-in-if-condition link

  • bugprone-bool-pointer-implicit-conversion link

  • bugprone-branch-clone link

  • bugprone-casting-through-void link

  • bugprone-chained-comparison link

  • !bugprone-copy-constructor-init link

  • !bugprone-dangling-handle link

  • !bugprone-derived-method-shadowing-base-method link

  • bugprone-dynamic-static-initializers link

  • ?bugprone-easily-swappable-parameters link

  • !bugprone-empty-catch link

  • !bugprone-exception-escape link

  • bugprone-fold-init-type link

  • bugprone-forward-declaration-namespace link

  • ??bugprone-forwarding-reference-overload link // c++ 11 probably

  • bugprone-implicit-widening-of-multiplication-result link

  • bugprone-inaccurate-erase link

  • ?bugprone-inc-dec-in-conditions link

  • bugprone-incorrect-roundings link

  • !bugprone-infinite-loop link

  • bugprone-integer-division link

  • bugprone-invalid-enum-default-initialization link

  • !bugprone-macro-parentheses link

  • !bugprone-misleading-setter-of-reference link

  • bugprone-misplaced-widening-cast link

  • bugprone-multi-level-implicit-pointer-conversion link

  • bugprone-multiple-new-in-one-expression link

  • bugprone-multiple-statement-macro link

  • !bugprone-narrowing-conversions link

  • https://clang.llvm.org/extra/clang-tidy/checks/bugprone/non-zero-enum-to-bool-conversion.html link

  • ??bugprone-nondeterministic-pointer-iteration-order link

  • !bugprone-not-null-terminated-result link

  • !bugprone-parent-virtual-call link

  • bugprone-pointer-arithmetic-on-polymorphic-object link

  • bugprone-redundant-branch-condition link

  • bugprone-reserved-identifier link

  • !bugprone-return-const-ref-from-parameter link

  • ??bugprone-signal-handler link

  • bugprone-signed-char-misuse link

  • bugprone-sizeof-container link

  • bugprone-sizeof-expression link

  • bugprone-standalone-empty link

  • !bugprone-string-constructor link

  • bugprone-string-literal-with-embedded-nul link

  • bugprone-suspicious-enum-usage link

  • bugprone-suspicious-include link

  • bugprone-suspicious-memset-usage link

  • bugprone-suspicious-missing-comma link

  • bugprone-suspicious-semicolon link

  • bugprone-suspicious-string-compare link

  • !bugprone-swapped-arguments link

  • bugprone-switch-missing-default-case link

  • bugprone-terminating-continue link

  • bugprone-throw-keyword-missing link

  • !bugprone-too-small-loop-variable link

  • bugprone-unchecked-string-to-number-conversion link

  • bugprone-undefined-memory-manipulation link

  • !bugprone-unhandled-self-assignment link

  • bugprone-unintended-char-ostream-output link

  • !bugprone-unsafe-functions link

  • !bugprone-unused-local-non-trivial-variable link

  • ??bugprone-unused-raii link

  • ?bugprone-unused-return-value link

  • bugprone-virtual-near-miss link

security

  • cert-err58-cpp link
  • cert-oop58-cpp link

guidelines

  • !cppcoreguidelines-avoid-const-or-ref-data-members link
  • !cppcoreguidelines-avoid-non-const-global-variables link
  • !cppcoreguidelines-init-variables link
  • !cppcoreguidelines-macro-usage link
  • !!cppcoreguidelines-no-malloc link
  • !cppcoreguidelines-prefer-member-initializer link
  • ?? cppcoreguidelines-pro-bounds-array-to-pointer-decay link
  • ?cppcoreguidelines-pro-bounds-avoid-unchecked-container-access link
  • cppcoreguidelines-pro-bounds-constant-array-index link
  • ?cppcoreguidelines-pro-bounds-pointer-arithmetic link
  • cppcoreguidelines-pro-type-const-cast link
  • !cppcoreguidelines-pro-type-cstyle-cast link
  • !cppcoreguidelines-pro-type-member-init link
  • ?cppcoreguidelines-pro-type-reinterpret-cast link
  • !cppcoreguidelines-pro-type-static-cast-downcast link
  • ??cppcoreguidelines-slicing link
  • ?cppcoreguidelines-special-member-functions link
  • ??cppcoreguidelines-use-enum-class link
  • cppcoreguidelines-virtual-class-destructor link

memory

  • dereferencing a possibly null pointer core.NullDereference
// wrong ❌
int* p = NULL;
int x = *p;
  • constructing from null pointer cpluplus.StringChecker link

  • leaks cplusplus.NewDelete link cplusplus.NewDeleteLeaks link cplusplus.ArrayDelete link ...

  • unitialized variables core.UndefinedBinaryOperatorResult core.UndefinedAssignment core.uninitialized.ArraySubscript link core.uninitialized.Assign link core.uninitialized.Branch link core.CallAndMessage link core.uninitialized.NewArraySize link ...

// wrong ❌
int x;
if (x > 0) {...}
  • using a variable after free cplusplus.NewDeleteLeaks link
// wrong ❌
int* p = new int(5);
delete p;
std::cout << *p;

resources

  • fd leaks unix.Stream

  • ignored return values ?? bugprone-ignored-return-value

// wrong ❌
write(fd, buf, len); // how do we know if all bytes are read ?
// good ✅

security and bound checks

  • bound errors core.VLASize link security.ArrayBound link

undefined behavior

  • division by zero core.DivideZero link
  • other operations core.UndefinedBinaryOperatorResult link
  • shifting too many bits
  • numeric types overflow
  • variable shadowing -> use namespaces
  • const correctness

performance

performance-unnecessary-copy-initialization

// wrong ❌
std::string msg = getMessage(); // copies result unnecessarily
// good ✅ = move if function returns by value
std::string msg = std::move(getMessage());

readability

  • unused functions, variable readability-container-size-empty
// wrong ❌
if (v.size() == 0) { /* ... */ }
// good ✅
if (v.empty()) { /* ... */ }
  • dead code deadCode.DeadStores link

readability-implicit-bool-conversion

// wrong ❌
if (x) { /* ... */ }
// good ✅
if (x != 0) { /* ... */ }

best practices

Clone this wiki locally