Skip to content

Commit

Permalink
CI: Add extended lint job for cppcheck
Browse files Browse the repository at this point in the history
  • Loading branch information
Fuzzbawls committed Nov 13, 2024
1 parent 43b75ca commit 1cc9a80
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 0 deletions.
58 changes: 58 additions & 0 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,64 @@ jobs:
test/lint/commit-script-check.sh $COMMIT_RANGE
fi
# Extended lint using cppcheck. Other jobs do NOT require this to pass.
extended-lint:
env:
CPPCHECK_VERSION: 2.14.0
CPPCHECK_BIN_DIR: ${{ github.workspace }}/.cppcheck
CPPCHECK_BUILD_DIR: ${{ github.workspace }}/.ci-cppcheck
LC_ALL: C
runs-on: ubuntu-20.04
defaults:
run:
shell: bash
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Initialize Python
uses: actions/setup-python@v5
with:
python-version: '3.8'

- name: cppcheck cache files
uses: actions/cache@v4
with:
path: |
.cppcheck
.ci-cppcheck
key: ci-cppcheck
restore-keys: ci-cppcheck

- name: Install Dependencies
run: |
python -m pip install --upgrade pip
mkdir -p ${CPPCHECK_BIN_DIR}
curl -s https://codeload.github.com/danmar/cppcheck/tar.gz/${CPPCHECK_VERSION} | tar -zxf - --directory ${CPPCHECK_BIN_DIR}/
cd ${CPPCHECK_BIN_DIR}/cppcheck-${CPPCHECK_VERSION}/
make -j 3 MATCHCOMPILER=yes FILESDIR=${CPPCHECK_BIN_DIR}/cppcheck-${CPPCHECK_VERSION}/cfg/
- name: Set TRAVIS_BRANCH workaround env variable
if: github.event_name == 'pull_request'
run: echo "TRAVIS_BRANCH=${{ github.base_ref }}" >> $GITHUB_ENV

- name: Build cppcheck cache
run: |
export PATH="${CPPCHECK_BIN_DIR}/cppcheck-${CPPCHECK_VERSION}:${PATH}"
git checkout -qf -B master refs/remotes/origin/master
git checkout -qf $GITHUB_SHA
# Build or rebuild the cppcheck cache.
test/lint/cppcheck/lint-all.sh --setup
- name: Lint
run: |
# Run the remainder of lint tests in `test/lint/`.
test/lint/cppcheck/lint-all.sh
# CMake build jobs to ensure building with CMake remains viable.
# Currently this only supports native linux and macOS.
cmake:
Expand Down
30 changes: 30 additions & 0 deletions test/lint/cppcheck/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
This folder contains lint scripts intended for use with the cppcheck CLI program.

Lint script naming convention should be in the form of `lint-<cppcheckrule>.sh`

lint-noexplicitconstructor.sh
======

Checks for 1-argument (non-converting) class/struct constructors that are not
marked as `explicit`. Allowing implicit conversion can lead to difficult to
track down bugs and unintended behavior.

run-cppcheck.sh
======

This script is responsible for building/rebuilding the cppcheck cache that
all other lint scripts use. cppcheck is run in "project" mode, which creates
a build cache to speed up subsequent runs. The result is output to a named
`cppcheck.txt` file, used by other lint scripts.

lint-all.sh
======

This is the base script used to initialize or run any lint script contained
in this directory. It can take an optional argument of `--setup` to
build/rebuild a cppcheck cache then exit, or be run with no arguments
(provided a cppcache exists) to then run any lint script in this directory.

Standard usage is to first run `./test/lint/cppcheck/lint-all.sh --setup` to
create or rebuild the cppcheck cache, then run `./test/llint/cppcheck/lint-all.sh`
with no arguments to perform any actual lint tests.
46 changes: 46 additions & 0 deletions test/lint/cppcheck/lint-all.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/usr/bin/env bash
#
# Copyright (c) 2019 The Bitcoin Core developers
# Copyright (c) 2024 The PIVX Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
# This script runs all test/lint/extended-lint-*.sh files, and fails if
# any exit with a non-zero status code.

# This script is intentionally locale dependent by not setting "export LC_ALL=C"
# in order to allow for the executed lint scripts to opt in or opt out of locale
# dependence themselves.

set -u

print_usage() {
echo "Usage: $0 --setup to create/refresh cppcheck's cache and exit. No argument to run lint tests."
}

SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
LINTALL=$(basename "${BASH_SOURCE[0]}")

if [[ $# != 0 ]]; then
if [[ $1 == "--help" ]]; then
print_usage
exit 0
fi
if [[ $1 == "--setup" ]]; then
if ! "${SCRIPTDIR}"/run-cppcheck.sh; then
echo "cppcheck cache creation failed"
exit 1
fi
exit 0
fi
fi

for f in "${SCRIPTDIR}"/lint-*.sh; do
if [ "$(basename "$f")" != "$LINTALL" ]; then
echo "running $f"
if ! "$f"; then
echo "^---- failure generated from $f"
exit 1
fi
fi
done
85 changes: 85 additions & 0 deletions test/lint/cppcheck/lint-noexplicitconstructor.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/env bash
#
# Copyright (c) 2019 The Bitcoin Core developers
# Copyright (c) 2024 The PIVX Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#

export LC_ALL=C

ENABLED_CHECKS=(
"\[noExplicitConstructor\]"
)

IGNORED_WARNINGS=(
"src/immer/.*"
"src/chiabls/.*"
"src/arith_uint256.h:.* Class 'arith_uint160' has a constructor with 1 argument that is not explicit."
"src/arith_uint256.h:.* Class 'arith_uint256' has a constructor with 1 argument that is not explicit."
"src/arith_uint256.h:.* Class 'arith_uint512' has a constructor with 1 argument that is not explicit."
"src/arith_uint256.h:.* Class 'base_uint < 160 >' has a constructor with 1 argument that is not explicit."
"src/arith_uint256.h:.* Class 'base_uint < 256 >' has a constructor with 1 argument that is not explicit."
"src/arith_uint256.h:.* Class 'base_uint < 512 >' has a constructor with 1 argument that is not explicit."
"src/arith_uint256.h:.* Class 'base_uint' has a constructor with 1 argument that is not explicit."
"src/coins.h:.* Class 'CCoinsViewBacked' has a constructor with 1 argument that is not explicit."
"src/coins.h:.* Class 'CCoinsViewCache' has a constructor with 1 argument that is not explicit."
"src/bls/bls_wrapper.h:.* Struct 'CBLSIdImplicit' has a constructor with 1 argument that is not explicit."
"src/bls/bls_wrapper.h:.* Class 'CBLSId' has a constructor with 1 argument that is not explicit."
"src/bls/bls_wrapper.h:.* Class 'CBLSWrapper < CBLSIdImplicit , 32 , CBLSId >' has a constructor with 1 argument that is not explicit."
"src/bls/bls_wrapper.h:.* Class 'CBLSWrapper < bls :: G1Element , 48 , CBLSPublicKey >' has a constructor with 1 argument that is not explicit."
"src/bls/bls_wrapper.h:.* Class 'CBLSWrapper < bls :: G2Element , 96 , CBLSSignature >' has a constructor with 1 argument that is not explicit."
"src/bls/bls_wrapper.h:.* Class 'CBLSWrapper < bls :: PrivateKey , 32 , CBLSSecretKey >' has a constructor with 1 argument that is not explicit."
"src/operationresult.h:.* Class 'OperationResult' has a constructor with 1 argument that is not explicit."
"src/prevector.h:.* Class 'const_iterator' has a constructor with 1 argument that is not explicit."
"src/prevector.h:.* Class 'const_reverse_iterator' has a constructor with 1 argument that is not explicit."
"src/prevector.h:.* Class 'iterator' has a constructor with 1 argument that is not explicit."
"src/prevector.h:.* Class 'reverse_iterator' has a constructor with 1 argument that is not explicit."
"src/primitives/block.h:.* Class 'CBlock' has a constructor with 1 argument that is not explicit."
"src/primitives/transaction.h:.* Class 'CTransaction' has a constructor with 1 argument that is not explicit."
"src/primitives/transaction.h:.* Struct 'CMutableTransaction' has a constructor with 1 argument that is not explicit."
"src/libzerocoin/bignum.h:.* Class 'CBigNum' has a constructor with 1 argument that is not explicit."
"src/qt/walletmodel.h:.* Struct 'SendCoinsReturn' has a constructor with 1 argument that is not explicit."
"src/rpc/server.h:.* Struct 'UniValueType' has a constructor with 1 argument that is not explicit."
"src/sapling/incrementalmerkletree.h:.* Class 'PedersenHash' has a constructor with 1 argument that is not explicit."
"src/sapling/incrementalmerkletree.h:.* Class 'SHA256Compress' has a constructor with 1 argument that is not explicit."
"src/script/standard.h:.* Class 'CScriptID' has a constructor with 1 argument that is not explicit."
"src/span.h:.* Class 'Span' has a constructor with 1 argument that is not explicit."
"src/span.h:.* Class 'Span < const char >' has a constructor with 1 argument that is not explicit."
"src/span.h:.* Class 'Span < const uint8_t >' has a constructor with 1 argument that is not explicit."
"src/span.h:.* Class 'Span < const unsigned char >' has a constructor with 1 argument that is not explicit."
"src/span.h:.* Class 'Span < uint8_t >' has a constructor with 1 argument that is not explicit."
"src/span.h:.* Class 'Span < unsigned char >' has a constructor with 1 argument that is not explicit."
"src/support/allocators/secure.h:.* Struct 'secure_allocator < char >' has a constructor with 1 argument that is not explicit."
"src/support/allocators/secure.h:.* Struct 'secure_allocator < RNGState >' has a constructor with 1 argument that is not explicit."
"src/support/allocators/secure.h:.* Struct 'secure_allocator < unsigned char >' has a constructor with 1 argument that is not explicit."
"src/support/allocators/zeroafterfree.h:.* Struct 'zero_after_free_allocator < char >' has a constructor with 1 argument that is not explicit."
"src/wallet/wallet.h:.* Struct 'Confirmation' has a constructor with 1 argument that is not explicit."
)

if [ ! -f cppcheck.txt ]; then
echo "cppcheck.txt cache not found, skipping linting."
exit 1
fi

function join_array {
local IFS="$1"
shift
echo "$*"
}

ENABLED_CHECKS_REGEXP=$(join_array "|" "${ENABLED_CHECKS[@]}")
IGNORED_WARNINGS_REGEXP=$(join_array "|" "${IGNORED_WARNINGS[@]}")

WARNINGS=$(< cppcheck.txt grep -E "${ENABLED_CHECKS_REGEXP}" | grep -vE "${IGNORED_WARNINGS_REGEXP}")

if [[ ${WARNINGS} != "" ]]; then
echo "${WARNINGS}"
echo
echo "Advice not applicable in this specific case? Add an exception by updating"
echo "IGNORED_WARNINGS in $0"
# Set to 1 to enforce the developer note policy "By default, declare single-argument constructors `explicit`"
exit 0
fi
echo "All checks passed!"
exit 0
30 changes: 30 additions & 0 deletions test/lint/cppcheck/run-cppcheck.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
#
# Copyright (c) 2024 The PIVX Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#

export LC_ALL=C

CPPCHECK_BUILD_DIR=".ci-cppcheck"

if ! command -v cppcheck > /dev/null; then
echo "Skipping cppcheck linting since cppcheck is not installed. Install by running \"apt install cppcheck\""
exit 1
fi

echo "Building cppcheck cache..."
if [ ! -d "${CPPCHECK_BUILD_DIR}" ]; then
mkdir -p "${CPPCHECK_BUILD_DIR}"
fi

cppcheck --cppcheck-build-dir="${CPPCHECK_BUILD_DIR}" --enable=all -j "$(getconf _NPROCESSORS_ONLN)" \
--language=c++ --std=c++14 --template=gcc --check-level=exhaustive --file-filter=*.cpp --file-filter=*.h -isrc/chiabls \
-isrc/crc32c -isrc/immer -isrc/leveldb -isrc/secp256k1 -isrc/univalue -D__cplusplus -DCLIENT_VERSION_BUILD \
-DCLIENT_VERSION_IS_RELEASE -DCLIENT_VERSION_MAJOR -DCLIENT_VERSION_MINOR -DCLIENT_VERSION_REVISION -DCOPYRIGHT_YEAR \
-DDEBUG -DWITH_LOCK -DPACKAGE_NAME -DENABLE_MINING_RPC --library=boost --library=qt -I src/ -I src/qt/ src/ 2> >(sort -u > cppcheck.txt)

echo "cppcheck cache built."

exit 0

0 comments on commit 1cc9a80

Please sign in to comment.