Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some static analysis to the code base. #60

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft

Conversation

ericonr
Copy link
Member

@ericonr ericonr commented Jan 8, 2025

Testing at least two options: clang-tidy+analyzer, and cppcheck

Could try and use https://github.com/SonarSource/sonarqube-scan-action , but requires creating an account and stuff, even if supposedly free for open source (does seem to be free: https://www.sonarsource.com/solutions/commitment-to-open-source/)

Would like to use GCC -fanalyzer, but so far it's not recommended for C++

https://github.com/cpplint/cpplint?tab=readme-ov-file is google-specific, but could try it at least locally to see where it complains and if it's compatible

There's also https://github.com/verateam/vera

Might be best to have a separate job for this, since I don't need to run it for every build. And separate jobs for each tool would also speed up things. Perhaps add flags to fail if errors are found?

Another nice addition would be running the testsuite under sanitizers

.github/workflows/build.yml Outdated Show resolved Hide resolved
@ericonr ericonr force-pushed the static-analysis branch 21 times, most recently from 1042934 to 3ed0ad5 Compare January 15, 2025 22:59
The test groups that were added were the ones considered relevant for
this project. Test groups used to enforce code style for specific
projects and platforms were omitted.

The specific tests from the groups in use that had to be removed are
explained below:

- cppcoreguidelines-avoid-do-while: we use do-while for actual logic,
  there's no reason to remove it;
- cppcoreguidelines-pro-bounds-pointer-arithmetic: pointer arithmetic is
  necessary in quite a few places. One of those is manipulating
  argv/argc, where using std::span doesn't add any safety (.at() member
  function is C++26), and std::vector requires copying;
- cppcoreguidelines-pro-type-vararg: we use cstdio extensively;
- modernize-use-trailing-return-type: though more modern, this function
  declaration style isn't widespread, and would conflict with the style
  used in other projects this one interacts with. It would also increase
  the barrier to entry for this project;
- readability-braces-around-statements: braces are skipped for single
  statements, which should always be indented (this will be guaranteed
  by clang-format in the future);
- readability-identifier-length: short names for iterator variables and
  throwaway values, as well as known shorthand (f for FILEs, v for
  verbose) should be used;
- readability-implicit-bool-conversion: treating pointers as bools is a
  common idiom.

We want clang-tidy to verify our own headers, which are under
include/modules/ and utils/.

We also want clang-tidy-diff, when used, to exit with an error.
Without this change, cppcheck would accuse that target_reg was
uninitialized when used, even though a reference had been captured, and
the lambda was only called after it was initialized.

We can reorder the code so this false-positive isn't triggered, and
without accidentally suppresing any warnings from other tools (as might
have happened if we had initialized target_reg to nullptr).
Use a matrix with jobs in order to parallelize running different tools.

The check for GITHUB_HEAD_REF is used so the same workflow works for PRs
and for branches.

We ignore some files with cppcheck due to issues with Catch2. An example
of an error generated by cppcheck with Catch2:

  util/tests/bits-test.cc:36:5: error: There is an unknown macro here
  somewhere. Configuration is required. If _catch_sr is a macro then
  please configure it. [unknownMacro]
    CHECK_THROWS_AS(clear_and_insert(reg, 1000U, range_mask), std::runtime_error);

The issue causing git-config(1) to be necessary is tracked in [1].

Meson supports a clang-tidy target of its own, but it's not really
usable for our purposes [2].

[1] actions/checkout#1169
[2] mesonbuild/meson#2383
@gustavosr8
Copy link

gustavosr8 commented Jan 16, 2025

Some checks that could be omitted (imo) in clang-tidy:

  • readability-isolate-declaration
  • modernize-type-traits
  • cppcoreguidelines-no-malloc
  • readability-function-cognitive-complexity (maybe just set IgnoreMacros to true could be enough )
  • readability-math-missing-parentheses
  • modernize-avoid-c-arrays
  • performance-avoid-endl
  • bugprone-suspicious-string-compare
  • bugprone-easily-swappable-parameters
  • modernize-use-auto

@gustavosr8
Copy link

With a regex-based python script, could find each occurrence and how many times it happens. Hope it's helpful.

cppcoreguidelines-avoid-magic-numbers: 158                                                                                                                                                                      
readability-magic-numbers: 158                                                                                                                                                                                  
cppcoreguidelines-non-private-member-variables-in-classes: 101                                                                                                                                                  
readability-named-parameter: 97                                                                                                                                                                                 
bugprone-narrowing-conversions: 97                                                                                                                                                                              
cppcoreguidelines-narrowing-conversions: 97                                                                                                                                                                     
cppcoreguidelines-special-member-functions: 74                                                                                                                                                                  
bugprone-chained-comparison: 56                                                                                                                                                                                 
cppcoreguidelines-pro-bounds-constant-array-index: 40                                                                                                                                                           
cppcoreguidelines-pro-bounds-array-to-pointer-decay: 35                                                                                                                                                         
cppcoreguidelines-avoid-c-arrays: 28                                                                                                                                                                            
modernize-avoid-c-arrays: 28                                                                                                                                                                                    
cppcoreguidelines-init-variables: 27
cppcoreguidelines-virtual-class-destructor: 21
cppcoreguidelines-avoid-non-const-global-variables: 19
readability-math-missing-parentheses: 18
cppcoreguidelines-macro-to-enum: 16
modernize-macro-to-enum: 16
cppcoreguidelines-pro-type-member-init: 13
readability-isolate-declaration: 10
cppcoreguidelines-pro-type-cstyle-cast: 10
readability-function-cognitive-complexity: 9
cppcoreguidelines-explicit-virtual-functions: 7
modernize-use-override: 7
cppcoreguidelines-macro-usage: 7
cppcoreguidelines-owning-memory: 6
modernize-use-auto: 6
bugprone-implicit-widening-of-multiplication-result: 6
readability-else-after-return: 6
bugprone-easily-swappable-parameters: 6
modernize-deprecated-headers: 5
performance-enum-size: 5
performance-unnecessary-value-param: 5
cppcoreguidelines-no-malloc: 4
readability-qualified-auto: 4
bugprone-switch-missing-default-case: 4
modernize-use-designated-initializers: 4
readability-redundant-inline-specifier: 4
bugprone-macro-parentheses: 4
modernize-use-using: 4
performance-avoid-endl: 3
concurrency-mt-unsafe: 3
bugprone-unchecked-optional-access: 3
readability-convert-member-functions-to-static: 3
bugprone-exception-escape: 2
modernize-use-ranges: 2
readability-redundant-casting: 2
readability-static-definition-in-anonymous-namespace: 2
modernize-pass-by-value: 2
nodiscard: 2
cppcoreguidelines-avoid-const-or-ref-data-members: 2 
readability-avoid-return-with-void-value: 2
modernize-type-traits: 2
bugprone-infinite-loop: 1
cppcoreguidelines-use-default-member-init: 1
modernize-use-default-member-init: 1
modernize-use-equals-default: 1
readability-simplify-boolean-expr: 1
readability-non-const-parameter: 1
bugprone-empty-catch: 1
modernize-use-nullptr: 1
bugprone-casting-through-void: 1
readability-make-member-function-const: 1
cppcoreguidelines-pro-type-reinterpret-cast: 1
cppcoreguidelines-pro-type-const-cast: 1
bugprone-suspicious-string-compare: 1

@gustavosr8
Copy link

The script, if want to reproduce the results:

import re
from collections import Counter

with open('static-analysis.txt', 'r') as file:
    log_data = file.read()

pattern = re.compile(r'warning:.*?\[([a-zA-Z\-]+(?:,[a-zA-Z\-]+)*)\]')
matches = pattern.findall(log_data)

all_warnings = []
for match in matches:
    all_warnings.extend(match.split(','))

counter = Counter([warning.strip() for warning in all_warnings])

for warning, count in counter.most_common():
    print(f"{warning}: {count}")

@ericonr
Copy link
Member Author

ericonr commented Jan 17, 2025

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants