diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000000..0bd90b6e8fc
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,18 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
+
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ commit-message:
+ prefix: "actions"
+ schedule:
+ interval: "daily"
+ groups:
+ actions-dependencies:
+ applies-to: version-updates
+ patterns:
+ - "*"
diff --git a/.github/workflows/CI-cygwin.yml b/.github/workflows/CI-cygwin.yml
index 445c0953eb5..852202bafde 100644
--- a/.github/workflows/CI-cygwin.yml
+++ b/.github/workflows/CI-cygwin.yml
@@ -37,12 +37,12 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Set up Cygwin
- uses: cygwin/cygwin-install-action@master
+ uses: cygwin/cygwin-install-action@f2009323764960f80959895c7bc3bb30210afe4d # v6
with:
platform: ${{ matrix.platform }}
packages: ${{ matrix.packages }}
diff --git a/.github/workflows/CI-mingw.yml b/.github/workflows/CI-mingw.yml
index 1b0cf3e5672..53adb127234 100644
--- a/.github/workflows/CI-mingw.yml
+++ b/.github/workflows/CI-mingw.yml
@@ -33,12 +33,12 @@ jobs:
timeout-minutes: 19 # max + 3*std of the last 7K runs
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Set up MSYS2
- uses: msys2/setup-msys2@v2
+ uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # v2.29.0
with:
release: false # use pre-installed
# TODO: install mingw-w64-x86_64-make and use mingw32.make instead - currently fails with "Windows Subsystem for Linux has no installed distributions."
@@ -49,7 +49,7 @@ jobs:
mingw-w64-x86_64-gcc
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
with:
key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }}
diff --git a/.github/workflows/CI-unixish-docker.yml b/.github/workflows/CI-unixish-docker.yml
index 4df9b4e9340..4c7a7530fd7 100644
--- a/.github/workflows/CI-unixish-docker.yml
+++ b/.github/workflows/CI-unixish-docker.yml
@@ -38,7 +38,7 @@ jobs:
image: ${{ matrix.image }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
@@ -56,7 +56,7 @@ jobs:
# needs to be called after the package installation since
# - it doesn't call "apt-get update"
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
with:
key: ${{ github.workflow }}-${{ matrix.image }}
@@ -91,7 +91,7 @@ jobs:
image: ${{ matrix.image }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
@@ -104,7 +104,7 @@ jobs:
# needs to be called after the package installation since
# - it doesn't call "apt-get update"
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
with:
key: ${{ github.workflow }}-${{ matrix.image }}
diff --git a/.github/workflows/CI-unixish.yml b/.github/workflows/CI-unixish.yml
index 4478f1b762d..8585e51a836 100644
--- a/.github/workflows/CI-unixish.yml
+++ b/.github/workflows/CI-unixish.yml
@@ -30,12 +30,12 @@ jobs:
CCACHE_SLOPPINESS: pch_defines,time_macros
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
with:
key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }}
@@ -85,19 +85,19 @@ jobs:
CCACHE_SLOPPINESS: pch_defines,time_macros
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
with:
key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }}
# TODO: move latest compiler to separate step
# TODO: bail out on warnings with latest GCC
- name: Set up GCC
- uses: egor-tensin/setup-gcc@v1
+ uses: egor-tensin/setup-gcc@eaa888eb19115a521fa72b65cd94fe1f25bbcaac # v1.3
if: false # matrix.os == 'ubuntu-22.04'
with:
version: 13
@@ -201,12 +201,12 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
with:
key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }}
@@ -235,12 +235,12 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
with:
key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }}
@@ -269,7 +269,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
@@ -297,12 +297,12 @@ jobs:
CCACHE_SLOPPINESS: pch_defines,time_macros
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
with:
key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }}
@@ -359,12 +359,12 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
with:
key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }}
@@ -597,12 +597,12 @@ jobs:
runs-on: ubuntu-22.04 # run on the latest image only
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
with:
key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }}
diff --git a/.github/workflows/CI-windows.yml b/.github/workflows/CI-windows.yml
index 55be78ee06e..9e32e1cc514 100644
--- a/.github/workflows/CI-windows.yml
+++ b/.github/workflows/CI-windows.yml
@@ -33,17 +33,17 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Set up Visual Studio environment
- uses: ilammy/msvc-dev-cmd@v1
+ uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
with:
arch: x64
- name: Install Qt ${{ matrix.qt_ver }}
- uses: jurplel/install-qt-action@v4
+ uses: jurplel/install-qt-action@d325aaf2a8baeeda41ad0b5d39f84a6af9bcf005 # v4.3.0
with:
version: ${{ matrix.qt_ver }}
modules: 'qtcharts'
@@ -87,25 +87,25 @@ jobs:
PCRE_VERSION: 8.45
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Set up Python
if: matrix.config == 'release'
- uses: actions/setup-python@v5
+ uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: '3.14'
check-latest: true
- name: Set up Visual Studio environment
- uses: ilammy/msvc-dev-cmd@v1
+ uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
with:
arch: x64
- name: Cache PCRE
id: cache-pcre
- uses: actions/cache@v4
+ uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: |
externals\pcre.h
diff --git a/.github/workflows/asan.yml b/.github/workflows/asan.yml
index 70b3a30f0ae..9981a9a55e1 100644
--- a/.github/workflows/asan.yml
+++ b/.github/workflows/asan.yml
@@ -28,17 +28,17 @@ jobs:
CCACHE_SLOPPINESS: pch_defines,time_macros
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
with:
key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }}
- name: Set up Python
- uses: actions/setup-python@v5
+ uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: '3.14'
check-latest: true
@@ -57,7 +57,7 @@ jobs:
sudo ./llvm.sh 21
- name: Install Qt ${{ env.QT_VERSION }}
- uses: jurplel/install-qt-action@v4
+ uses: jurplel/install-qt-action@d325aaf2a8baeeda41ad0b5d39f84a6af9bcf005 # v4.3.0
with:
version: ${{ env.QT_VERSION }}
modules: 'qtcharts'
diff --git a/.github/workflows/buildman.yml b/.github/workflows/buildman.yml
index b0b399dd851..e010d8af4a8 100644
--- a/.github/workflows/buildman.yml
+++ b/.github/workflows/buildman.yml
@@ -19,26 +19,26 @@ jobs:
convert_via_pandoc:
runs-on: ubuntu-24.04
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- run: |
mkdir output
- - uses: docker://pandoc/latex:3.6.3
+ - uses: docker://pandoc/latex:3.6.3@sha256:48831aabd0a24e180a34c0bc5dd09792af43dbd7c2a2d394fbc6b10f9c48fe50
with:
args: --output=output/manual.html man/manual.md
- - uses: docker://pandoc/latex:3.6.3
+ - uses: docker://pandoc/latex:3.6.3@sha256:48831aabd0a24e180a34c0bc5dd09792af43dbd7c2a2d394fbc6b10f9c48fe50
with:
args: --output=output/manual.pdf man/manual.md
- - uses: docker://pandoc/latex:3.6.3
+ - uses: docker://pandoc/latex:3.6.3@sha256:48831aabd0a24e180a34c0bc5dd09792af43dbd7c2a2d394fbc6b10f9c48fe50
with:
args: --output=output/manual-premium.pdf man/manual-premium.md
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: output
path: output
@@ -46,7 +46,7 @@ jobs:
manpage:
runs-on: ubuntu-22.04
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
@@ -59,7 +59,7 @@ jobs:
run: |
make man
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: cppcheck.1
path: cppcheck.1
diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml
index 7b462c688f0..96464e53aeb 100644
--- a/.github/workflows/cifuzz.yml
+++ b/.github/workflows/cifuzz.yml
@@ -14,20 +14,20 @@ jobs:
steps:
- name: Build Fuzzers
id: build
- uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
+ uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@6f5791d8b0ca004e5d35f8d75407347c7848f3b0 # master
with:
oss-fuzz-project-name: 'cppcheck'
dry-run: false
language: c++
- name: Run Fuzzers
- uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
+ uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@6f5791d8b0ca004e5d35f8d75407347c7848f3b0 # master
with:
oss-fuzz-project-name: 'cppcheck'
fuzz-seconds: 300
dry-run: false
language: c++
- name: Upload Crash
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml
index 7b2c4f4e2c7..cf1631845aa 100644
--- a/.github/workflows/clang-tidy.yml
+++ b/.github/workflows/clang-tidy.yml
@@ -27,7 +27,7 @@ jobs:
QT_VERSION: 6.10.0
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
@@ -47,7 +47,7 @@ jobs:
sudo apt-get install -y clang-tidy-21
- name: Install Qt ${{ env.QT_VERSION }}
- uses: jurplel/install-qt-action@v4
+ uses: jurplel/install-qt-action@d325aaf2a8baeeda41ad0b5d39f84a6af9bcf005 # v4.3.0
with:
version: ${{ env.QT_VERSION }}
modules: 'qtcharts'
@@ -86,7 +86,7 @@ jobs:
run: |
cmake --build cmake.output --target run-clang-tidy-csa 2> /dev/null
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
if: success() || failure()
with:
name: Compilation Database
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 12e758d2c9e..30c9fa45d19 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -33,13 +33,13 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v4
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v3
+ uses: github/codeql-action/init@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4.31.8
with:
languages: ${{ matrix.language }}
@@ -49,4 +49,4 @@ jobs:
make -j$(nproc) CXXOPTS="-Werror" HAVE_RULES=yes CPPCHK_GLIBCXX_DEBUG= cppcheck
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v3
+ uses: github/codeql-action/analyze@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4.31.8
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
index 13f56172a80..52b4539c529 100644
--- a/.github/workflows/coverage.yml
+++ b/.github/workflows/coverage.yml
@@ -21,12 +21,12 @@ jobs:
runs-on: ubuntu-22.04
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
with:
key: ${{ github.workflow }}-${{ runner.os }}
@@ -57,12 +57,12 @@ jobs:
lcov --extract lcov_tmp.info "$(pwd)/*" --output-file lcov.info
genhtml lcov.info -o coverage_report --frame --legend --demangle-cpp
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: Coverage results
path: coverage_report
- - uses: codecov/codecov-action@v4
+ - uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
token: ${{ secrets.CODECOV_TOKEN }}
# file: ./coverage.xml # optional
diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml
index 3c07b61d7c7..109f08875b2 100644
--- a/.github/workflows/coverity.yml
+++ b/.github/workflows/coverity.yml
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'danmar' }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Install missing software on ubuntu
diff --git a/.github/workflows/cppcheck-premium.yml b/.github/workflows/cppcheck-premium.yml
index 42bca8a6ebb..34d9ada691f 100644
--- a/.github/workflows/cppcheck-premium.yml
+++ b/.github/workflows/cppcheck-premium.yml
@@ -25,7 +25,7 @@ jobs:
build:
runs-on: ubuntu-24.04 # run on the latest image only
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
@@ -60,13 +60,13 @@ jobs:
#sed -i 's|"security-severity":.*||' results.sarif
cat results.sarif
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: results
path: results.sarif
- name: Upload report
- uses: github/codeql-action/upload-sarif@v3
+ uses: github/codeql-action/upload-sarif@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4.31.8
with:
sarif_file: results.sarif
category: cppcheckpremium
diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml
index fd491c0ec0e..f5259d771e1 100644
--- a/.github/workflows/format.yml
+++ b/.github/workflows/format.yml
@@ -24,12 +24,12 @@ jobs:
UNCRUSTIFY_VERSION: 0.80.1
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Cache uncrustify
- uses: actions/cache@v4
+ uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
id: cache-uncrustify
with:
path: |
diff --git a/.github/workflows/iwyu.yml b/.github/workflows/iwyu.yml
index 649991f9373..d0d82f872e8 100644
--- a/.github/workflows/iwyu.yml
+++ b/.github/workflows/iwyu.yml
@@ -42,7 +42,7 @@ jobs:
QT_VERSION: 6.10.0
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
@@ -107,7 +107,7 @@ jobs:
# Also the shell is broken afterwards:
# OCI runtime exec failed: exec failed: unable to start container process: exec: "sh": executable file not found in $PATH: unknown
- name: Install Qt ${{ env.QT_VERSION }}
- uses: jurplel/install-qt-action@v4
+ uses: jurplel/install-qt-action@d325aaf2a8baeeda41ad0b5d39f84a6af9bcf005 # v4.3.0
with:
version: ${{ env.QT_VERSION }}
modules: 'qtcharts'
@@ -160,13 +160,13 @@ jobs:
IWYU: include-what-you-use
IWYU_CLANG_INC: ${{ matrix.clang_inc }}
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
if: success() || failure()
with:
name: Compilation Database (include-what-you-use - ${{ matrix.os }} ${{ matrix.stdlib }})
path: ./cmake.output/compile_commands.json
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
if: ${{ contains(matrix.os, 'macos') && (success() || failure()) }}
with:
name: macOS Mappings
@@ -174,7 +174,7 @@ jobs:
./iwyu-mapgen-apple-libc.py
./macos.imp
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
if: success() || failure()
with:
name: Logs (include-what-you-use - ${{ matrix.os }} ${{ matrix.stdlib }})
@@ -199,7 +199,7 @@ jobs:
QT_VERSION: 6.10.0
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
@@ -223,7 +223,7 @@ jobs:
sudo apt-get install -y libc++-21-dev
- name: Install Qt ${{ env.QT_VERSION }}
- uses: jurplel/install-qt-action@v4
+ uses: jurplel/install-qt-action@d325aaf2a8baeeda41ad0b5d39f84a6af9bcf005 # v4.3.0
with:
version: ${{ env.QT_VERSION }}
modules: 'qtcharts'
@@ -255,13 +255,13 @@ jobs:
# TODO: run multi-threaded
find $PWD/cli $PWD/lib $PWD/test $PWD/gui -maxdepth 1 -name "*.cpp" | xargs -t -n 1 clang-include-cleaner-21 --print=changes --extra-arg=-w --extra-arg=-stdlib=${{ matrix.stdlib }} -p cmake.output > clang-include-cleaner.log 2>&1
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
if: success() || failure()
with:
name: Compilation Database (clang-include-cleaner - ${{ matrix.stdlib }})
path: ./cmake.output/compile_commands.json
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
if: success() || failure()
with:
name: Logs (clang-include-cleaner - ${{ matrix.stdlib }})
diff --git a/.github/workflows/release-windows-mingw.yml b/.github/workflows/release-windows-mingw.yml
index 3b9b836347f..d4989f1d986 100644
--- a/.github/workflows/release-windows-mingw.yml
+++ b/.github/workflows/release-windows-mingw.yml
@@ -33,12 +33,12 @@ jobs:
timeout-minutes: 19 # max + 3*std of the last 7K runs
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Set up MSYS2
- uses: msys2/setup-msys2@v2
+ uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 # v2.29.0
with:
release: false # use pre-installed
# TODO: install mingw-w64-x86_64-make and use mingw32.make instead - currently fails with "Windows Subsystem for Linux has no installed distributions."
@@ -63,7 +63,7 @@ jobs:
cp /mingw64/bin/libstdc*.dll cppcheck-mingw/
cp /mingw64/bin/libwinpthread-1.dll cppcheck-mingw/
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: cppcheck-mingw
path: cppcheck-mingw
diff --git a/.github/workflows/release-windows.yml b/.github/workflows/release-windows.yml
index 2836000acc5..d1af31c5fcc 100644
--- a/.github/workflows/release-windows.yml
+++ b/.github/workflows/release-windows.yml
@@ -31,12 +31,12 @@ jobs:
BOOST_MINOR_VERSION: 89
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: Set up Visual Studio environment
- uses: ilammy/msvc-dev-cmd@v1
+ uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
- name: Download PCRE
run: |
@@ -66,7 +66,7 @@ jobs:
# available modules: https://github.com/miurahr/aqtinstall/blob/master/docs/getting_started.rst#installing-modules
# available tools: https://github.com/miurahr/aqtinstall/blob/master/docs/getting_started.rst#installing-tools
- name: Install Qt ${{ env.QT_VERSION }}
- uses: jurplel/install-qt-action@v4
+ uses: jurplel/install-qt-action@d325aaf2a8baeeda41ad0b5d39f84a6af9bcf005 # v4.3.0
with:
version: ${{ env.QT_VERSION }}
modules: 'qtcharts'
@@ -89,7 +89,7 @@ jobs:
del build\bin\Release\cppcheck-gui.ilk || exit /b !errorlevel!
del build\bin\Release\cppcheck-gui.pdb || exit /b !errorlevel!
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: deploy
path: build\bin\Release
@@ -103,7 +103,7 @@ jobs:
env:
_CL_: /WX
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: bin
path: bin
@@ -152,7 +152,7 @@ jobs:
:: copy libcrypto-3-x64.dll and libssl-3-x64.dll
copy %RUNNER_WORKSPACE%\Qt\Tools\OpenSSLv3\Win_x64\bin\lib*.dll win_installer\files || exit /b !errorlevel!
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: collect
path: win_installer\files
@@ -167,7 +167,7 @@ jobs:
@echo ProductVersion="%PRODUCTVER%" || exit /b !errorlevel!
msbuild -m cppcheck.wixproj -p:Platform=x64,ProductVersion=%PRODUCTVER%.${{ github.run_number }} || exit /b !errorlevel!
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: installer
path: win_installer/Build/
@@ -203,7 +203,7 @@ jobs:
del win_installer\files\Qt6Svg.dll || exit /b !errorlevel!
del win_installer\files\vc_redist.x64.exe || exit /b !errorlevel!
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: portable
path: win_installer\files
diff --git a/.github/workflows/scriptcheck.yml b/.github/workflows/scriptcheck.yml
index 66e54ddff98..eed164344c5 100644
--- a/.github/workflows/scriptcheck.yml
+++ b/.github/workflows/scriptcheck.yml
@@ -21,17 +21,17 @@ jobs:
runs-on: ubuntu-22.04
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
with:
key: ${{ github.workflow }}-${{ runner.os }}
- name: Cache Cppcheck
- uses: actions/cache@v4
+ uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: cppcheck
key: ${{ runner.os }}-scriptcheck-cppcheck-${{ github.sha }}
@@ -56,19 +56,19 @@ jobs:
fail-fast: false
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
# TODO: bailout on error
- name: Restore Cppcheck
- uses: actions/cache@v4
+ uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: cppcheck
key: ${{ runner.os }}-scriptcheck-cppcheck-${{ github.sha }}
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v5
+ uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: ${{ matrix.python-version }}
check-latest: true
@@ -209,7 +209,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
diff --git a/.github/workflows/selfcheck.yml b/.github/workflows/selfcheck.yml
index 61cc1463274..ae67f01a3aa 100644
--- a/.github/workflows/selfcheck.yml
+++ b/.github/workflows/selfcheck.yml
@@ -24,12 +24,12 @@ jobs:
QT_VERSION: 6.10.0
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
with:
key: ${{ github.workflow }}-${{ runner.os }}
@@ -42,7 +42,7 @@ jobs:
sudo apt-get install -y libgl-dev # fixes missing dependency for Qt in CMake
- name: Install Qt ${{ env.QT_VERSION }}
- uses: jurplel/install-qt-action@v4
+ uses: jurplel/install-qt-action@d325aaf2a8baeeda41ad0b5d39f84a6af9bcf005 # v4.3.0
with:
version: ${{ env.QT_VERSION }}
modules: 'qtcharts'
@@ -198,7 +198,7 @@ jobs:
env:
DISABLE_VALUEFLOW: 1
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: Callgrind Output
path: ./callgrind.*
diff --git a/.github/workflows/tsan.yml b/.github/workflows/tsan.yml
index 27ed6606386..ec748ad6276 100644
--- a/.github/workflows/tsan.yml
+++ b/.github/workflows/tsan.yml
@@ -27,17 +27,17 @@ jobs:
CCACHE_SLOPPINESS: pch_defines,time_macros
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
with:
key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }}
- name: Set up Python
- uses: actions/setup-python@v5
+ uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: '3.14'
check-latest: true
@@ -56,7 +56,7 @@ jobs:
sudo ./llvm.sh 21
- name: Install Qt ${{ env.QT_VERSION }}
- uses: jurplel/install-qt-action@v4
+ uses: jurplel/install-qt-action@d325aaf2a8baeeda41ad0b5d39f84a6af9bcf005 # v4.3.0
with:
version: ${{ env.QT_VERSION }}
modules: 'qtcharts'
diff --git a/.github/workflows/ubsan.yml b/.github/workflows/ubsan.yml
index 64eb02a4b25..886ab66b935 100644
--- a/.github/workflows/ubsan.yml
+++ b/.github/workflows/ubsan.yml
@@ -27,17 +27,17 @@ jobs:
CCACHE_SLOPPINESS: pch_defines,time_macros
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
with:
key: ${{ github.workflow }}-${{ github.job }}-${{ matrix.os }}
- name: Set up Python
- uses: actions/setup-python@v5
+ uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: '3.14'
check-latest: true
@@ -56,7 +56,7 @@ jobs:
sudo ./llvm.sh 21
- name: Install Qt ${{ env.QT_VERSION }}
- uses: jurplel/install-qt-action@v4
+ uses: jurplel/install-qt-action@d325aaf2a8baeeda41ad0b5d39f84a6af9bcf005 # v4.3.0
with:
version: ${{ env.QT_VERSION }}
modules: 'qtcharts'
diff --git a/.github/workflows/valgrind.yml b/.github/workflows/valgrind.yml
index 9a6026aa25b..5429b1ffc7e 100644
--- a/.github/workflows/valgrind.yml
+++ b/.github/workflows/valgrind.yml
@@ -21,12 +21,12 @@ jobs:
runs-on: ubuntu-22.04
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
- name: ccache
- uses: hendrikmuhs/ccache-action@v1.2
+ uses: hendrikmuhs/ccache-action@5ebbd400eff9e74630f759d94ddd7b6c26299639 # v1.2.20
with:
key: ${{ github.workflow }}-${{ runner.os }}
@@ -58,7 +58,7 @@ jobs:
#env:
# DEBUGINFOD_URLS: https://debuginfod.ubuntu.com
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
if: success() || failure()
with:
name: Logs
diff --git a/htmlreport/cppcheck-htmlreport b/htmlreport/cppcheck-htmlreport
index 915fda97300..5044443a0a9 100755
--- a/htmlreport/cppcheck-htmlreport
+++ b/htmlreport/cppcheck-htmlreport
@@ -356,6 +356,57 @@ HTML_HEAD = """
}
}
+ function reapplyFilters() {
+ // Reapply ID filters
+ var idToggles = document.querySelectorAll(".idToggle");
+ for (var i = 1; i < idToggles.length; i++) {
+ var cb = idToggles[i];
+ var elements = document.querySelectorAll("." + cb.id);
+ for (var j = 0; j < elements.length; j++) {
+ elements[j].classList.toggle("id-filtered", !cb.checked);
+ }
+ }
+
+ // Reapply severity filters
+ var sevToggles = document.querySelectorAll(".sev_toggle");
+ for (var i = 0; i < sevToggles.length; i++) {
+ var cb = sevToggles[i];
+ var elements = document.querySelectorAll(".sev_" + cb.id);
+ for (var j = 0; j < elements.length; j++) {
+ elements[j].classList.toggle("severity-filtered", !cb.checked);
+ }
+ }
+
+ // Reapply classification filters
+ var classToggles = document.querySelectorAll(".class_toggle");
+ for (var i = 0; i < classToggles.length; i++) {
+ var cb = classToggles[i];
+ var elements = document.querySelectorAll(".class_" + cb.id);
+ for (var j = 0; j < elements.length; j++) {
+ elements[j].classList.toggle("classification-filtered", !cb.checked);
+ }
+ }
+
+ // Reapply tool filters
+ var toolToggles = document.querySelectorAll(".tool_toggle");
+ for (var i = 0; i < toolToggles.length; i++) {
+ var cb = toolToggles[i];
+ var elements;
+ if (cb.id == "clang-tidy")
+ elements = document.querySelectorAll("[class^=clang-tidy-]");
+ else
+ elements = document.querySelectorAll(".issue:not([class^=clang-tidy-])");
+
+ for (var j = 0; j < elements.length; j++) {
+ elements[j].classList.toggle("tool-filtered", !cb.checked);
+ }
+ }
+
+ // Update file rows
+ updateFileRows();
+ }
+
+ window.addEventListener("pageshow", reapplyFilters);
window.addEventListener("load", initExpandables);
@@ -494,9 +545,20 @@ def tr_str(td_th, line, id, cwe, severity, classification, guideline, message, t
if classification:
items.extend([classification, guideline])
if htmlfile:
- ret += '<%s>%d%s>' % (td_th, htmlfile, line, line, td_th)
+ if htmlfile.startswith("http://") or htmlfile.startswith("https://"):
+ # GitHub/GitLab style line anchor
+ href = f"{htmlfile.rstrip('#L1')}#L{line}"
+ # Emit **line number with link**
+ ret += f'<{td_th}>{line}{td_th}>'
+ else:
+ # local HTML annotated
+ href = f"{htmlfile}#line-{line}"
+ # Emit **line number with link**
+ ret += f'<{td_th}>{line}{td_th}>'
+
+ # Emit id, cwe, severity, classification, ...
for item in items:
- ret += '<%s>%s%s>' % (td_th, item, td_th)
+ ret += f'<{td_th}>{item}{td_th}>'
else:
items.insert(0,line)
for item in items:
@@ -675,7 +737,9 @@ def main() -> None:
'written.')
parser.add_argument('--source-dir', dest='source_dir',
help='Base directory where source code files can be '
- 'found.')
+ 'found, or a URL to a remote GitHub/GitLab '
+ 'repository including a branch, e.g. '
+ '--source-dir=https://github.com///blob//')
parser.add_argument('--add-author-information', dest='add_author_information',
help='Blame information to include. '
'Adds specified author information. '
@@ -705,6 +769,10 @@ def main() -> None:
if options.source_dir:
source_dir = options.source_dir
+ is_remote = False
+ if source_dir.startswith("http://") or source_dir.startswith("https://"):
+ is_remote = True
+
add_author_information = []
if options.add_author_information:
fields = [x.strip() for x in options.add_author_information.split(',')]
@@ -753,9 +821,14 @@ def main() -> None:
for error in contentHandler.errors:
filename = error['file']
if filename not in files:
- files[filename] = {
- 'errors': [], 'htmlfile': str(file_no) + '.html'}
- file_no = file_no + 1
+ if is_remote:
+ # Construct remote URL for GitHub/GitLab
+ # tr_str() will use the actual line number, so we can just start with line 1
+ remote_url = source_dir.rstrip('/') + '/' + filename + '#L1'
+ files[filename] = {'errors': [], 'htmlfile': remote_url}
+ else:
+ files[filename] = {'errors': [], 'htmlfile': str(file_no) + '.html'}
+ file_no += 1
files[filename]['errors'].append(error)
# Make sure that the report directory is created if it doesn't exist.
@@ -795,6 +868,11 @@ def main() -> None:
if filename == '':
continue
+ if is_remote:
+ # Remote source: do NOT generate local annotated HTML files.
+ # The index will still point directly to GitHub/GitLab URLs.
+ continue
+
source_filename = os.path.join(source_dir, filename)
try:
with io.open(source_filename, 'r', encoding=options.source_encoding) as input_file:
diff --git a/lib/astutils.cpp b/lib/astutils.cpp
index 68218b4402d..d5d38bc3453 100644
--- a/lib/astutils.cpp
+++ b/lib/astutils.cpp
@@ -3678,7 +3678,7 @@ bool isGlobalData(const Token *expr)
// TODO check if pointer points at local data
const Variable *lhsvar = tok->astOperand1()->variable();
const ValueType *lhstype = tok->astOperand1()->valueType();
- if (lhsvar->isPointer()) {
+ if (lhsvar->isPointer() || !lhstype || lhstype->type == ValueType::Type::ITERATOR) {
globalData = true;
return ChildrenToVisit::none;
}
@@ -3686,7 +3686,7 @@ bool isGlobalData(const Token *expr)
globalData = true;
return ChildrenToVisit::none;
}
- if (lhsvar->isArgument() && (!lhstype || (lhstype->type <= ValueType::Type::VOID && !lhstype->container))) {
+ if (lhsvar->isArgument() && lhstype->type <= ValueType::Type::VOID && !lhstype->container) {
globalData = true;
return ChildrenToVisit::none;
}
diff --git a/lib/check64bit.cpp b/lib/check64bit.cpp
index eeda1c93648..aa8a9bcb18a 100644
--- a/lib/check64bit.cpp
+++ b/lib/check64bit.cpp
@@ -45,7 +45,14 @@ static bool is32BitIntegerReturn(const Function* func, const Settings* settings)
if (settings->platform.sizeof_pointer != 8)
return false;
const ValueType* vt = func->arg->valueType();
- return vt && vt->pointer == 0 && vt->isIntegral() && vt->typeSize(settings->platform) == 4;
+ return vt && vt->pointer == 0 && vt->isIntegral() && vt->getSizeOf(*settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer) == 4;
+}
+
+static bool isFunctionPointer(const Token* tok)
+{
+ if (!tok || !tok->variable())
+ return false;
+ return Tokenizer::isFunctionPointer(tok->variable()->nameToken());
}
void Check64BitPortability::pointerassignment()
@@ -120,7 +127,8 @@ void Check64BitPortability::pointerassignment()
!tok->astOperand2()->isNumber() &&
rhstype->pointer == 0U &&
rhstype->originalTypeName.empty() &&
- rhstype->type == ValueType::Type::INT)
+ rhstype->type == ValueType::Type::INT &&
+ !isFunctionPointer(tok->astOperand1()))
assignmentIntegerToAddressError(tok);
// Assign pointer to integer..
diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp
index 337f2b1de3f..57c46492bc0 100644
--- a/lib/checkbufferoverrun.cpp
+++ b/lib/checkbufferoverrun.cpp
@@ -96,7 +96,7 @@ static int getMinFormatStringOutputLength(const std::vector ¶m
std::string digits_string;
bool i_d_x_f_found = false;
int parameterLength = 0;
- int inputArgNr = formatStringArgNr;
+ nonneg int inputArgNr = formatStringArgNr;
for (std::size_t i = 1; i + 1 < formatString.length(); ++i) {
if (formatString[i] == '\\') {
if (i < formatString.length() - 1 && formatString[i + 1] == '0')
@@ -229,7 +229,8 @@ static bool getDimensionsEtc(const Token * const arrayToken, const Settings &set
Dimension dim;
dim.known = value->isKnown();
dim.tok = nullptr;
- const MathLib::bigint typeSize = array->valueType()->typeSize(settings.platform, array->valueType()->pointer > 1);
+ const auto sizeOf = array->valueType()->pointer > 1 ? ValueType::SizeOf::Pointer : ValueType::SizeOf::Pointee;
+ const size_t typeSize = array->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, sizeOf);
if (typeSize == 0)
return false;
dim.num = value->intvalue / typeSize;
@@ -585,7 +586,7 @@ ValueFlow::Value CheckBufferOverrun::getBufferSize(const Token *bufTok) const
if (var->isPointerArray())
v.intvalue = dim * mSettings->platform.sizeof_pointer;
else {
- const MathLib::bigint typeSize = bufTok->valueType()->typeSize(mSettings->platform);
+ const size_t typeSize = bufTok->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee);
v.intvalue = dim * typeSize;
}
@@ -929,7 +930,7 @@ bool CheckBufferOverrun::isCtuUnsafeBufferUsage(const Settings &settings, const
{
if (!offset)
return false;
- if (!argtok->valueType() || argtok->valueType()->typeSize(settings.platform) == 0)
+ if (!argtok->valueType() || argtok->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee) == 0)
return false;
const Token *indexTok = nullptr;
if (type == 1 && Token::Match(argtok, "%name% [") && argtok->astParent() == argtok->next() && !Token::simpleMatch(argtok->linkAt(1), "] ["))
@@ -942,7 +943,7 @@ bool CheckBufferOverrun::isCtuUnsafeBufferUsage(const Settings &settings, const
return false;
if (!indexTok->hasKnownIntValue())
return false;
- offset->value = indexTok->getKnownIntValue() * argtok->valueType()->typeSize(settings.platform);
+ offset->value = indexTok->getKnownIntValue() * argtok->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee);
return true;
}
@@ -1102,7 +1103,7 @@ void CheckBufferOverrun::objectIndex()
continue;
}
if (obj->valueType() && var->valueType() && (obj->isCast() || (obj->isCpp() && isCPPCast(obj)) || obj->valueType()->pointer)) { // allow cast to a different type
- const auto varSize = var->valueType()->typeSize(mSettings->platform);
+ const auto varSize = var->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee);
if (varSize == 0)
continue;
if (obj->valueType()->type != var->valueType()->type) {
diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp
index 03aa85f0a3c..34a734fecaa 100644
--- a/lib/checkclass.cpp
+++ b/lib/checkclass.cpp
@@ -3459,9 +3459,7 @@ void CheckClass::checkReturnByReference()
const bool isView = isContainer && var->valueType()->container->view;
bool warn = isContainer && !isView;
if (!warn && !isView) {
- const std::size_t size = ValueFlow::getSizeOf(*var->valueType(),
- *mSettings,
- ValueFlow::Accuracy::LowerBound);
+ const std::size_t size = var->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer);
if (size > 2 * mSettings->platform.sizeof_pointer)
warn = true;
}
diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp
index 5953dce4c96..83f7227091c 100644
--- a/lib/checkleakautovar.cpp
+++ b/lib/checkleakautovar.cpp
@@ -1149,6 +1149,12 @@ void CheckLeakAutoVar::leakIfAllocated(const Token *vartok,
}
}
+static bool isSafeCast(const ValueType* vt, const Settings& settings)
+{
+ const size_t sizeOf = vt->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee);
+ return sizeOf == 0 || sizeOf >= settings.platform.sizeof_pointer;
+}
+
void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndOfScope)
{
const std::map &alloctype = varInfo.alloctype;
@@ -1182,8 +1188,7 @@ void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndO
while (tok3 && tok3->isCast() &&
(!tok3->valueType() ||
tok3->valueType()->pointer ||
- (tok3->valueType()->typeSize(mSettings->platform) == 0) ||
- (tok3->valueType()->typeSize(mSettings->platform) >= mSettings->platform.sizeof_pointer)))
+ isSafeCast(tok3->valueType(), *mSettings)))
tok3 = tok3->astOperand2() ? tok3->astOperand2() : tok3->astOperand1();
if (tok3 && tok3->varId() == varid)
tok2 = tok3->next();
diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp
index 355b0d809d7..7f49257d1a3 100644
--- a/lib/checkmemoryleak.cpp
+++ b/lib/checkmemoryleak.cpp
@@ -1071,8 +1071,8 @@ void CheckMemoryLeakNoVar::checkForUnreleasedInputArgument(const Scope *scope)
const Variable* argvar = tok->function()->getArgumentVar(argnr);
if (!argvar || !argvar->valueType())
continue;
- const MathLib::bigint argSize = argvar->valueType()->typeSize(mSettings->platform, /*p*/ true);
- if (argSize <= 0 || argSize >= mSettings->platform.sizeof_pointer)
+ const size_t argSize = argvar->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee);
+ if (argSize == 0 || argSize >= mSettings->platform.sizeof_pointer)
continue;
}
functionCallLeak(arg, arg->str(), functionName);
diff --git a/lib/checkother.cpp b/lib/checkother.cpp
index eed6dfe0bf1..e1728788ecb 100644
--- a/lib/checkother.cpp
+++ b/lib/checkother.cpp
@@ -1524,7 +1524,7 @@ static bool isLargeContainer(const Variable* var, const Settings& settings)
return false;
}
const ValueType vtElem = ValueType::parseDecl(vt->containerTypeToken, settings);
- const auto elemSize = std::max(ValueFlow::getSizeOf(vtElem, settings, ValueFlow::Accuracy::LowerBound), 1);
+ const auto elemSize = std::max(vtElem.getSizeOf(settings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer), 1);
const auto arraySize = var->dimension(0) * elemSize;
return arraySize > maxByValueSize;
}
@@ -1564,7 +1564,7 @@ void CheckOther::checkPassByReference()
// Ensure that it is a large object.
if (!var->type()->classScope)
inconclusive = true;
- else if (!var->valueType() || ValueFlow::getSizeOf(*var->valueType(), *mSettings, ValueFlow::Accuracy::LowerBound) <= 2 * mSettings->platform.sizeof_pointer)
+ else if (!var->valueType() || var->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer) <= 2 * mSettings->platform.sizeof_pointer)
continue;
}
else
@@ -3327,7 +3327,8 @@ void CheckOther::checkRedundantCopy()
const Token* varTok = fScope->bodyEnd->tokAt(-2);
if (varTok->variable() && !varTok->variable()->isGlobal() &&
(!varTok->variable()->type() || !varTok->variable()->type()->classScope ||
- (varTok->variable()->valueType() && ValueFlow::getSizeOf(*varTok->variable()->valueType(), *mSettings, ValueFlow::Accuracy::LowerBound) > 2 * mSettings->platform.sizeof_pointer)))
+ (varTok->variable()->valueType() &&
+ varTok->variable()->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer) > 2 * mSettings->platform.sizeof_pointer)))
redundantCopyError(startTok, startTok->str());
}
}
@@ -3447,7 +3448,7 @@ void CheckOther::checkIncompleteArrayFill()
if (size == 0 && var->valueType()->pointer)
size = mSettings->platform.sizeof_pointer;
else if (size == 0 && var->valueType())
- size = ValueFlow::getSizeOf(*var->valueType(), *mSettings, ValueFlow::Accuracy::LowerBound);
+ size = var->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer);
const Token* tok3 = tok->next()->astOperand2()->astOperand1()->astOperand1();
if ((size != 1 && size != 100 && size != 0) || var->isPointer()) {
if (printWarning)
@@ -4430,8 +4431,7 @@ static UnionMember parseUnionMember(const Variable &var,
if (var.isArray()) {
size = var.dimension(0);
} else if (vt != nullptr) {
- size = ValueFlow::getSizeOf(*vt, settings,
- ValueFlow::Accuracy::ExactOrZero);
+ size = vt->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer);
}
return UnionMember(nameToken->str(), size);
}
@@ -4523,7 +4523,7 @@ static bool getBufAndOffset(const Token *expr, const Token *&buf, MathLib::bigin
bufToken = expr->astOperand1()->astOperand1();
offsetToken = expr->astOperand1()->astOperand2();
if (expr->astOperand1()->valueType())
- elementSize = ValueFlow::getSizeOf(*expr->astOperand1()->valueType(), settings, ValueFlow::Accuracy::LowerBound);
+ elementSize = expr->astOperand1()->valueType()->getSizeOf(settings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer);
} else if (Token::Match(expr, "+|-") && expr->isBinaryOp()) {
const bool pointer1 = (expr->astOperand1()->valueType() && expr->astOperand1()->valueType()->pointer > 0);
const bool pointer2 = (expr->astOperand2()->valueType() && expr->astOperand2()->valueType()->pointer > 0);
@@ -4532,13 +4532,13 @@ static bool getBufAndOffset(const Token *expr, const Token *&buf, MathLib::bigin
offsetToken = expr->astOperand2();
auto vt = *expr->astOperand1()->valueType();
--vt.pointer;
- elementSize = ValueFlow::getSizeOf(vt, settings, ValueFlow::Accuracy::LowerBound);
+ elementSize = vt.getSizeOf(settings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer);
} else if (!pointer1 && pointer2) {
bufToken = expr->astOperand2();
offsetToken = expr->astOperand1();
auto vt = *expr->astOperand2()->valueType();
--vt.pointer;
- elementSize = ValueFlow::getSizeOf(vt, settings, ValueFlow::Accuracy::LowerBound);
+ elementSize = vt.getSizeOf(settings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer);
} else {
return false;
}
@@ -4547,7 +4547,7 @@ static bool getBufAndOffset(const Token *expr, const Token *&buf, MathLib::bigin
*offset = 0;
auto vt = *expr->valueType();
--vt.pointer;
- elementSize = ValueFlow::getSizeOf(vt, settings, ValueFlow::Accuracy::LowerBound);
+ elementSize = vt.getSizeOf(settings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer);
if (elementSize > 0) {
*offset *= elementSize;
if (sizeValue)
diff --git a/lib/checktype.cpp b/lib/checktype.cpp
index 92d19c1e794..68b6580d270 100644
--- a/lib/checktype.cpp
+++ b/lib/checktype.cpp
@@ -322,12 +322,8 @@ static bool checkTypeCombination(ValueType src, ValueType tgt, const Settings& s
src.reference = Reference::None;
tgt.reference = Reference::None;
- const std::size_t sizeSrc = ValueFlow::getSizeOf(src,
- settings,
- ValueFlow::Accuracy::ExactOrZero);
- const std::size_t sizeTgt = ValueFlow::getSizeOf(tgt,
- settings,
- ValueFlow::Accuracy::ExactOrZero);
+ const std::size_t sizeSrc = src.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer);
+ const std::size_t sizeTgt = tgt.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer);
if (!(sizeSrc > 0 && sizeTgt > 0 && sizeSrc < sizeTgt))
return false;
diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp
index b807199ca30..ddaffa0f817 100644
--- a/lib/checkunusedvar.cpp
+++ b/lib/checkunusedvar.cpp
@@ -1283,12 +1283,6 @@ void CheckUnusedVar::checkFunctionVariableUsage()
if (!tok->astOperand1())
continue;
- const Token *iteratorToken = tok->astOperand1();
- while (Token::Match(iteratorToken, "[.*]"))
- iteratorToken = iteratorToken->astOperand1();
- if (iteratorToken && iteratorToken->variable() && iteratorToken->variable()->typeEndToken()->str().find("iterator") != std::string::npos)
- continue;
-
const Token *op1tok = tok->astOperand1();
while (Token::Match(op1tok, ".|[|*"))
op1tok = op1tok->astOperand1();
diff --git a/lib/clangimport.cpp b/lib/clangimport.cpp
index 9f3bf593755..87877fd629e 100644
--- a/lib/clangimport.cpp
+++ b/lib/clangimport.cpp
@@ -1586,7 +1586,7 @@ static void setValues(const Tokenizer &tokenizer, const SymbolDatabase *symbolDa
return v * dim.num;
});
if (var.valueType())
- typeSize += mul * var.valueType()->typeSize(settings.platform, true);
+ typeSize += mul * var.valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer);
}
scope.definedType->sizeOf = typeSize;
}
@@ -1594,8 +1594,8 @@ static void setValues(const Tokenizer &tokenizer, const SymbolDatabase *symbolDa
for (auto *tok = const_cast(tokenizer.tokens()); tok; tok = tok->next()) {
if (Token::simpleMatch(tok, "sizeof (")) {
ValueType vt = ValueType::parseDecl(tok->tokAt(2), settings);
- const MathLib::bigint sz = vt.typeSize(settings.platform, true);
- if (sz <= 0)
+ const size_t sz = vt.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer);
+ if (sz == 0)
continue;
long long mul = 1;
for (const Token *arrtok = tok->linkAt(1)->previous(); arrtok; arrtok = arrtok->previous()) {
diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp
index 9490f62475d..7a637c8b7b3 100644
--- a/lib/cppcheck.cpp
+++ b/lib/cppcheck.cpp
@@ -1602,6 +1602,9 @@ void CppCheck::executeAddons(const std::vector& files, const std::s
}
errmsg.file0 = file0;
+ if (obj.count("cwe")>0)
+ errmsg.cwe = CWE(obj["cwe"].get());
+
if (obj.count("hash")>0)
errmsg.hash = obj["hash"].get();
diff --git a/lib/ctu.cpp b/lib/ctu.cpp
index 833a4dfda4b..aadba39d3c7 100644
--- a/lib/ctu.cpp
+++ b/lib/ctu.cpp
@@ -368,7 +368,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer &tokenizer)
functionCall.location = FileInfo::Location(tokenizer, tok);
functionCall.callArgNr = argnr + 1;
functionCall.callArgumentExpression = argtok->expressionString();
- const auto typeSize = argtok->valueType()->typeSize(tokenizer.getSettings().platform);
+ const auto typeSize = argtok->valueType()->getSizeOf(tokenizer.getSettings(), ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee);
functionCall.callArgValue.value = typeSize > 0 ? argtok->variable()->dimension(0) * typeSize : -1;
functionCall.warning = false;
fileInfo->functionCalls.push_back(std::move(functionCall));
@@ -382,7 +382,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer &tokenizer)
functionCall.location = FileInfo::Location(tokenizer, tok);
functionCall.callArgNr = argnr + 1;
functionCall.callArgumentExpression = argtok->expressionString();
- functionCall.callArgValue.value = argtok->astOperand1()->valueType()->typeSize(tokenizer.getSettings().platform);
+ functionCall.callArgValue.value = argtok->astOperand1()->valueType()->getSizeOf(tokenizer.getSettings(), ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee);
functionCall.warning = false;
fileInfo->functionCalls.push_back(std::move(functionCall));
}
diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp
index 0e02e3bb488..636e5a848a1 100644
--- a/lib/preprocessor.cpp
+++ b/lib/preprocessor.cpp
@@ -88,18 +88,22 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::Token *tok, std:
const std::string::size_type pos1 = comment.find_first_not_of("/* \t");
if (pos1 == std::string::npos)
return false;
- if (pos1 + cppchecksuppress.size() >= comment.size())
- return false;
if (comment.substr(pos1, cppchecksuppress.size()) != cppchecksuppress)
return false;
+ if (pos1 + cppchecksuppress.size() >= comment.size()) {
+ bad.emplace_back(tok->location.file(), tok->location.line, 0, "suppression without error ID");
+ return false;
+ }
// check if it has a prefix
const std::string::size_type posEndComment = comment.find_first_of(" [", pos1+cppchecksuppress.size());
// skip spaces after "cppcheck-suppress" and its possible prefix
const std::string::size_type pos2 = comment.find_first_not_of(' ', posEndComment);
- if (pos2 == std::string::npos)
+ if (pos2 == std::string::npos) {
+ bad.emplace_back(tok->location.file(), tok->location.line, 0, "suppression without error ID");
return false;
+ }
SuppressionList::Type errorType = SuppressionList::Type::unique;
@@ -142,9 +146,11 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::Token *tok, std:
s.lineNumber = tok->location.line;
}
+ // TODO: return false?
if (!errmsg.empty())
bad.emplace_back(tok->location.file(), tok->location.line, tok->location.col, std::move(errmsg));
+ // TODO: report ones without ID - return false?
std::copy_if(suppressions.cbegin(), suppressions.cend(), std::back_inserter(inlineSuppressions), [](const SuppressionList::Suppression& s) {
return !s.errorId.empty();
});
@@ -159,9 +165,12 @@ static bool parseInlineSuppressionCommentToken(const simplecpp::Token *tok, std:
s.type = errorType;
s.lineNumber = tok->location.line;
+ // TODO: report when no ID - unreachable?
if (!s.errorId.empty())
inlineSuppressions.push_back(std::move(s));
+ // TODO: unreachable?
+ // TODO: return false?
if (!errmsg.empty())
bad.emplace_back(tok->location.file(), tok->location.line, tok->location.col, std::move(errmsg));
}
diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp
index b75c9bfed4d..d4107884642 100644
--- a/lib/symboldatabase.cpp
+++ b/lib/symboldatabase.cpp
@@ -45,6 +45,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -6571,23 +6572,6 @@ const Type* SymbolDatabase::findType(const Token *startTok, const Scope *startSc
if (startTok->str() == startScope->className && startScope->isClassOrStruct() && startTok->strAt(1) != "::")
return startScope->definedType;
- if (startTok->isC()) {
- const Scope* scope = startScope;
- while (scope) {
- if (startTok->str() == scope->className && scope->isClassOrStruct())
- return scope->definedType;
- const Scope* typeScope = scope->findRecordInNestedList(startTok->str(), /*isC*/ true);
- if (typeScope) {
- if (startTok->str() == typeScope->className && typeScope->isClassOrStruct()) {
- if (const Type* type = typeScope->definedType)
- return type;
- }
- }
- scope = scope->nestedIn;
- }
- return nullptr;
- }
-
const Scope* start_scope = startScope;
// absolute path - directly start in global scope
@@ -8438,40 +8422,187 @@ bool ValueType::isVolatile(nonneg int indirect) const
return false;
return volatileness & (1 << (pointer - indirect));
}
-MathLib::bigint ValueType::typeSize(const Platform &platform, bool p) const
+
+namespace {
+ struct Result
+ {
+ size_t total;
+ bool success;
+ };
+}
+
+template
+static Result accumulateStructMembers(const Scope* scope, F f, ValueType::Accuracy accuracy)
{
- if (p && pointer)
- return platform.sizeof_pointer;
+ size_t total = 0;
+ std::set anonScopes;
+ for (const Variable& var : scope->varlist) {
+ if (var.isStatic())
+ continue;
+ const MathLib::bigint bits = var.nameToken() ? var.nameToken()->bits() : -1;
+ if (const ValueType* vt = var.valueType()) {
+ if (vt->type == ValueType::Type::RECORD && vt->typeScope == scope)
+ return {0, false};
+ const MathLib::bigint dim = std::accumulate(var.dimensions().cbegin(), var.dimensions().cend(), MathLib::bigint(1), [](MathLib::bigint i1, const Dimension& dim) {
+ return i1 * dim.num;
+ });
+ if (var.nameToken()->scope() != scope && var.nameToken()->scope()->definedType) { // anonymous union
+ const auto ret = anonScopes.insert(var.nameToken()->scope());
+ if (ret.second)
+ total = f(total, *vt, dim, bits);
+ }
+ else
+ total = f(total, *vt, dim, bits);
+ }
+ if (accuracy == ValueType::Accuracy::ExactOrZero && total == 0 && bits == -1)
+ return {0, false};
+ }
+ return {total, true};
+}
- if (typeScope && typeScope->definedType && typeScope->definedType->sizeOf)
- return typeScope->definedType->sizeOf;
- switch (type) {
- case ValueType::Type::BOOL:
- return platform.sizeof_bool;
- case ValueType::Type::CHAR:
+static size_t bitCeil(size_t x)
+{
+ if (x <= 1)
return 1;
- case ValueType::Type::SHORT:
+ --x;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ x |= x >> 32;
+ return x + 1;
+}
+
+static size_t getAlignOf(const ValueType& vt, const Settings& settings, ValueType::Accuracy accuracy, ValueType::SizeOf sizeOf, int maxRecursion = 0)
+{
+ if (maxRecursion == settings.vfOptions.maxAlignOfRecursion) {
+ // TODO: add bailout message
+ return 0;
+ }
+ if ((vt.pointer && sizeOf == ValueType::SizeOf::Pointer) || vt.reference != Reference::None || vt.isPrimitive()) {
+ auto align = vt.getSizeOf(settings, accuracy, ValueType::SizeOf::Pointer);
+ return align == 0 ? 0 : bitCeil(align);
+ }
+ if (vt.type == ValueType::Type::RECORD && vt.typeScope) {
+ auto accHelper = [&](size_t max, const ValueType& vt2, size_t /*dim*/, MathLib::bigint /*bits*/) {
+ size_t a = getAlignOf(vt2, settings, accuracy, ValueType::SizeOf::Pointer, ++maxRecursion);
+ return std::max(max, a);
+ };
+ Result result = accumulateStructMembers(vt.typeScope, accHelper, accuracy);
+ size_t total = result.total;
+ if (const Type* dt = vt.typeScope->definedType) {
+ total = std::accumulate(dt->derivedFrom.begin(), dt->derivedFrom.end(), total, [&](size_t v, const Type::BaseInfo& bi) {
+ if (bi.type && bi.type->classScope)
+ v += accumulateStructMembers(bi.type->classScope, accHelper, accuracy).total;
+ return v;
+ });
+ }
+ return result.success ? std::max(1, total) : total;
+ }
+ if (vt.type == ValueType::Type::CONTAINER)
+ return settings.platform.sizeof_pointer; // Just guess
+ return 0;
+}
+
+size_t ValueType::getSizeOf( const Settings& settings, Accuracy accuracy, SizeOf sizeOf, int maxRecursion) const
+{
+ if (maxRecursion == settings.vfOptions.maxSizeOfRecursion) {
+ // TODO: add bailout message
+ return 0;
+ }
+ const auto& platform = settings.platform;
+ if (sizeOf == SizeOf::Pointer && (pointer || reference != Reference::None))
+ return platform.sizeof_pointer;
+ if (type == ValueType::Type::BOOL || type == ValueType::Type::CHAR)
+ return 1;
+ if (type == ValueType::Type::SHORT)
return platform.sizeof_short;
- case ValueType::Type::WCHAR_T:
+ if (type == ValueType::Type::WCHAR_T)
return platform.sizeof_wchar_t;
- case ValueType::Type::INT:
+ if (type == ValueType::Type::INT)
return platform.sizeof_int;
- case ValueType::Type::LONG:
+ if (type == ValueType::Type::LONG)
return platform.sizeof_long;
- case ValueType::Type::LONGLONG:
+ if (type == ValueType::Type::LONGLONG)
return platform.sizeof_long_long;
- case ValueType::Type::FLOAT:
+ if (type == ValueType::Type::FLOAT)
return platform.sizeof_float;
- case ValueType::Type::DOUBLE:
+ if (type == ValueType::Type::DOUBLE)
return platform.sizeof_double;
- case ValueType::Type::LONGDOUBLE:
+ if (type == ValueType::Type::LONGDOUBLE)
return platform.sizeof_long_double;
- default:
- break;
+ if (type == ValueType::Type::CONTAINER)
+ return 3 * platform.sizeof_pointer; // Just guess
+ if (type == ValueType::Type::RECORD && typeScope) {
+ size_t currentBitCount = 0;
+ size_t currentBitfieldAlloc = 0;
+ auto accHelper = [&](size_t total, const ValueType& vt2, size_t dim, MathLib::bigint nBits) -> size_t {
+ const size_t charBit = settings.platform.char_bit;
+ size_t n = vt2.getSizeOf(settings, accuracy, SizeOf::Pointer, ++maxRecursion);
+ size_t a = getAlignOf(vt2, settings, accuracy, SizeOf::Pointer);
+ if (n == 0 || a == 0)
+ return accuracy == Accuracy::ExactOrZero ? 0 : total;
+ if (nBits == 0) {
+ if (currentBitfieldAlloc == 0) {
+ nBits = n * charBit;
+ } else {
+ nBits = (currentBitfieldAlloc * charBit) - currentBitCount;
+ }
+ }
+ if (nBits > 0) {
+ size_t ret = total;
+ if (currentBitfieldAlloc == 0) {
+ currentBitfieldAlloc = n;
+ currentBitCount = 0;
+ } else if (currentBitCount + nBits > charBit * currentBitfieldAlloc) {
+ ret += currentBitfieldAlloc;
+ currentBitfieldAlloc = n;
+ currentBitCount = 0;
+ }
+ while (nBits > charBit * currentBitfieldAlloc) {
+ ret += currentBitfieldAlloc;
+ nBits -= charBit * currentBitfieldAlloc;
+ }
+ currentBitCount += nBits;
+ return ret;
+ }
+ n *= dim;
+ size_t padding = (a - (total % a)) % a;
+ if (currentBitCount > 0) {
+ bool fitsInBitfield = currentBitCount + (n * charBit) <= currentBitfieldAlloc * charBit;
+ bool isAligned = currentBitCount % (charBit * a) == 0;
+ if (vt2.isIntegral() && fitsInBitfield && isAligned) {
+ currentBitCount += charBit * n;
+ return total;
+ }
+ n += currentBitfieldAlloc;
+ currentBitfieldAlloc = 0;
+ currentBitCount = 0;
+ }
+ return typeScope->type == ScopeType::eUnion ? std::max(total, n) : total + padding + n;
+ };
+ Result result = accumulateStructMembers(typeScope, accHelper, accuracy);
+ size_t total = result.total;
+ if (currentBitCount > 0)
+ total += currentBitfieldAlloc;
+ if (const ::Type* dt = typeScope->definedType) {
+ total = std::accumulate(dt->derivedFrom.begin(), dt->derivedFrom.end(), total, [&](size_t v, const ::Type::BaseInfo& bi) {
+ if (bi.type && bi.type->classScope)
+ v += accumulateStructMembers(bi.type->classScope, accHelper, accuracy).total;
+ return v;
+ });
+ }
+ if (accuracy == Accuracy::ExactOrZero && total == 0 && !result.success)
+ return 0;
+ total = std::max(size_t{1}, total);
+ size_t align = getAlignOf(*this, settings, accuracy, sizeOf);
+ if (align == 0)
+ return accuracy == Accuracy::ExactOrZero ? 0 : total;
+ total += (align - (total % align)) % align;
+ return total;
}
-
- // Unknown invalid size
return 0;
}
diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h
index 50f37fc1ebf..a0e6190db73 100644
--- a/lib/symboldatabase.h
+++ b/lib/symboldatabase.h
@@ -1312,7 +1312,15 @@ class CPPCHECKLIB ValueType {
bool isVolatile(nonneg int indirect = 0) const;
- MathLib::bigint typeSize(const Platform &platform, bool p=false) const;
+ enum class Accuracy : std::uint8_t {
+ ExactOrZero,
+ LowerBound,
+ };
+ enum class SizeOf : std::uint8_t {
+ Pointer,
+ Pointee,
+ };
+ size_t getSizeOf(const Settings& settings, Accuracy accuracy, SizeOf sizeOf, int maxRecursion = 0) const;
/// Check if type is the same ignoring const and references
bool isTypeEqual(const ValueType* that) const;
diff --git a/lib/token.cpp b/lib/token.cpp
index 0c64222801d..68e7838b6be 100644
--- a/lib/token.cpp
+++ b/lib/token.cpp
@@ -784,7 +784,7 @@ nonneg int Token::getStrSize(const Token *tok, const Settings &settings)
if (tok->valueType()) {
ValueType vt(*tok->valueType());
vt.pointer = 0;
- sizeofType = ValueFlow::getSizeOf(vt, settings, ValueFlow::Accuracy::ExactOrZero);
+ sizeofType = vt.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer);
}
return getStrArraySize(tok) * sizeofType;
}
diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp
index da279b8f453..40cbfbd3580 100644
--- a/lib/tokenize.cpp
+++ b/lib/tokenize.cpp
@@ -674,7 +674,7 @@ namespace {
return;
mUsed = true;
- const bool isFunctionPointer = Token::Match(mNameToken, "%name% )");
+ const bool isFunctionPointer = Tokenizer::isFunctionPointer(mNameToken);
// Special handling for T(...) when T is a pointer
if (Token::Match(tok, "%name% [({]") && !isFunctionPointer && !Token::simpleMatch(tok->linkAt(1), ") (")) {
@@ -1019,6 +1019,10 @@ namespace {
};
}
+bool Tokenizer::isFunctionPointer(const Token* tok) {
+ return Token::Match(tok, "%name% ) (");
+}
+
void Tokenizer::simplifyTypedef()
{
// Simplify global typedefs that are not redefined with the fast 1-pass simplification.
@@ -1088,7 +1092,7 @@ void Tokenizer::simplifyTypedef()
typedefInfo.lineNumber = typedefToken->linenr();
typedefInfo.column = typedefToken->column();
typedefInfo.used = t.second.isUsed();
- typedefInfo.isFunctionPointer = Token::Match(t.second.nameToken(), "%name% ) (");
+ typedefInfo.isFunctionPointer = isFunctionPointer(t.second.nameToken());
if (typedefInfo.isFunctionPointer) {
const Token* tok = typedefToken;
while (tok != t.second.endToken()) {
@@ -1622,7 +1626,7 @@ void Tokenizer::simplifyTypedefCpp()
typedefInfo.lineNumber = typeName->linenr();
typedefInfo.column = typeName->column();
typedefInfo.used = false;
- typedefInfo.isFunctionPointer = Token::Match(typeName, "%name% ) (");
+ typedefInfo.isFunctionPointer = isFunctionPointer(typeName);
if (typedefInfo.isFunctionPointer) {
const Token* t = typeDef;
while (t != tok) {
@@ -7155,7 +7159,7 @@ void Tokenizer::simplifyFunctionPointers()
while (Token::Match(tok2, "%type%|:: %type%|::"))
tok2 = tok2->next();
- if (!Token::Match(tok2, "%name% ) (") &&
+ if (!isFunctionPointer(tok2) &&
!Token::Match(tok2, "%name% [ ] ) (") &&
!(Token::Match(tok2, "%name% (") && Token::simpleMatch(tok2->linkAt(1), ") ) (")))
continue;
@@ -7448,7 +7452,7 @@ void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, co
}
// Function pointer
if (Token::simpleMatch(varName, "( *") &&
- Token::Match(varName->link()->previous(), "%name% ) (") &&
+ isFunctionPointer(varName->link()->previous()) &&
Token::simpleMatch(varName->link()->linkAt(1), ") =")) {
Token *endDecl = varName->link()->linkAt(1);
varName = varName->link()->previous();
@@ -9376,7 +9380,7 @@ Token* Tokenizer::getAttributeFuncTok(Token* tok, bool gccattr) const {
if (Token::simpleMatch(prev, ")")) {
if (Token::Match(prev->link()->previous(), "%name% ("))
return prev->link()->previous();
- if (Token::Match(prev->link()->tokAt(-2), "%name% ) ("))
+ if (isFunctionPointer(prev->link()->tokAt(-2)))
return prev->link()->tokAt(-2);
}
if (Token::simpleMatch(prev, ")") && Token::Match(prev->link()->tokAt(-2), "operator %op% (") && isCPP())
@@ -10085,17 +10089,7 @@ void Tokenizer::simplifyBitfields()
if (!Token::Match(tok, ";|{|}|public:|protected:|private:"))
continue;
- bool isEnum = false;
- if (tok->str() == "}") {
- const Token *type = tok->link()->previous();
- while (type && type->isName()) {
- if (type->str() == "enum") {
- isEnum = true;
- break;
- }
- type = type->previous();
- }
- }
+ const bool isEnum = tok->str() == "}" && isEnumStart(tok->link());
const auto tooLargeError = [this](const Token *tok) {
const auto max = std::numeric_limits::max();
diff --git a/lib/tokenize.h b/lib/tokenize.h
index f9feebb43f0..d001c54cb10 100644
--- a/lib/tokenize.h
+++ b/lib/tokenize.h
@@ -601,7 +601,7 @@ class CPPCHECKLIB Tokenizer {
/**
* Helper function to check whether number is one (1 or 0.1E+1 or 1E+0) or not?
* @param s the string to check
- * @return true in case is is one and false otherwise.
+ * @return true in case it is one and false otherwise.
*/
static bool isOneNumber(const std::string &s);
@@ -613,6 +613,13 @@ class CPPCHECKLIB Tokenizer {
*/
static const Token * startOfExecutableScope(const Token * tok);
+ /**
+ * Helper function to check whether tok is the declaration of a function pointer
+ * @param tok the Token to check
+ * @return true in case tok is a function pointer and false otherwise.
+ */
+ static bool isFunctionPointer(const Token* tok);
+
const Settings &getSettings() const {
return mSettings;
}
diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp
index 8eb5735c986..a4e24f5ca37 100644
--- a/lib/valueflow.cpp
+++ b/lib/valueflow.cpp
@@ -423,187 +423,6 @@ void ValueFlow::combineValueProperties(const ValueFlow::Value &value1, const Val
result.path = value1.path;
}
-namespace {
- struct Result
- {
- size_t total;
- bool success;
- };
-}
-
-template
-static Result accumulateStructMembers(const Scope* scope, F f, ValueFlow::Accuracy accuracy)
-{
- size_t total = 0;
- std::set anonScopes;
- for (const Variable& var : scope->varlist) {
- if (var.isStatic())
- continue;
- const MathLib::bigint bits = var.nameToken() ? var.nameToken()->bits() : -1;
- if (const ValueType* vt = var.valueType()) {
- if (vt->type == ValueType::Type::RECORD && vt->typeScope == scope)
- return {0, false};
- const MathLib::bigint dim = std::accumulate(var.dimensions().cbegin(), var.dimensions().cend(), MathLib::bigint(1), [](MathLib::bigint i1, const Dimension& dim) {
- return i1 * dim.num;
- });
- if (var.nameToken()->scope() != scope && var.nameToken()->scope()->definedType) { // anonymous union
- const auto ret = anonScopes.insert(var.nameToken()->scope());
- if (ret.second)
- total = f(total, *vt, dim, bits);
- }
- else
- total = f(total, *vt, dim, bits);
- }
- if (accuracy == ValueFlow::Accuracy::ExactOrZero && total == 0 && bits == -1)
- return {0, false};
- }
- return {total, true};
-}
-
-static size_t bitCeil(size_t x)
-{
- if (x <= 1)
- return 1;
- --x;
- x |= x >> 1;
- x |= x >> 2;
- x |= x >> 4;
- x |= x >> 8;
- x |= x >> 16;
- x |= x >> 32;
- return x + 1;
-}
-
-static size_t getAlignOf(const ValueType& vt, const Settings& settings, ValueFlow::Accuracy accuracy, int maxRecursion = 0)
-{
- if (maxRecursion == settings.vfOptions.maxAlignOfRecursion) {
- // TODO: add bailout message
- return 0;
- }
- if (vt.pointer || vt.reference != Reference::None || vt.isPrimitive()) {
- auto align = ValueFlow::getSizeOf(vt, settings, accuracy);
- return align == 0 ? 0 : bitCeil(align);
- }
- if (vt.type == ValueType::Type::RECORD && vt.typeScope) {
- auto accHelper = [&](size_t max, const ValueType& vt2, size_t /*dim*/, MathLib::bigint /*bits*/) {
- size_t a = getAlignOf(vt2, settings, accuracy, ++maxRecursion);
- return std::max(max, a);
- };
- Result result = accumulateStructMembers(vt.typeScope, accHelper, accuracy);
- size_t total = result.total;
- if (const Type* dt = vt.typeScope->definedType) {
- total = std::accumulate(dt->derivedFrom.begin(), dt->derivedFrom.end(), total, [&](size_t v, const Type::BaseInfo& bi) {
- if (bi.type && bi.type->classScope)
- v += accumulateStructMembers(bi.type->classScope, accHelper, accuracy).total;
- return v;
- });
- }
- return result.success ? std::max(1, total) : total;
- }
- if (vt.type == ValueType::Type::CONTAINER)
- return settings.platform.sizeof_pointer; // Just guess
- return 0;
-}
-
-size_t ValueFlow::getSizeOf(const ValueType &vt, const Settings &settings, Accuracy accuracy, int maxRecursion)
-{
- if (maxRecursion == settings.vfOptions.maxSizeOfRecursion) {
- // TODO: add bailout message
- return 0;
- }
- if (vt.pointer || vt.reference != Reference::None)
- return settings.platform.sizeof_pointer;
- if (vt.type == ValueType::Type::BOOL || vt.type == ValueType::Type::CHAR)
- return 1;
- if (vt.type == ValueType::Type::SHORT)
- return settings.platform.sizeof_short;
- if (vt.type == ValueType::Type::WCHAR_T)
- return settings.platform.sizeof_wchar_t;
- if (vt.type == ValueType::Type::INT)
- return settings.platform.sizeof_int;
- if (vt.type == ValueType::Type::LONG)
- return settings.platform.sizeof_long;
- if (vt.type == ValueType::Type::LONGLONG)
- return settings.platform.sizeof_long_long;
- if (vt.type == ValueType::Type::FLOAT)
- return settings.platform.sizeof_float;
- if (vt.type == ValueType::Type::DOUBLE)
- return settings.platform.sizeof_double;
- if (vt.type == ValueType::Type::LONGDOUBLE)
- return settings.platform.sizeof_long_double;
- if (vt.type == ValueType::Type::CONTAINER)
- return 3 * settings.platform.sizeof_pointer; // Just guess
- if (vt.type == ValueType::Type::RECORD && vt.typeScope) {
- size_t currentBitCount = 0;
- size_t currentBitfieldAlloc = 0;
- auto accHelper = [&](size_t total, const ValueType& vt2, size_t dim, MathLib::bigint bits) -> size_t {
- const size_t charBit = settings.platform.char_bit;
- size_t n = ValueFlow::getSizeOf(vt2, settings,accuracy, ++maxRecursion);
- size_t a = getAlignOf(vt2, settings, accuracy);
- if (n == 0 || a == 0)
- return accuracy == Accuracy::ExactOrZero ? 0 : total;
- if (bits == 0) {
- if (currentBitfieldAlloc == 0) {
- bits = n * charBit;
- } else {
- bits = (currentBitfieldAlloc * charBit) - currentBitCount;
- }
- }
- if (bits > 0) {
- size_t ret = total;
- if (currentBitfieldAlloc == 0) {
- currentBitfieldAlloc = n;
- currentBitCount = 0;
- } else if (currentBitCount + bits > charBit * currentBitfieldAlloc) {
- ret += currentBitfieldAlloc;
- currentBitfieldAlloc = n;
- currentBitCount = 0;
- }
- while (bits > charBit * currentBitfieldAlloc) {
- ret += currentBitfieldAlloc;
- bits -= charBit * currentBitfieldAlloc;
- }
- currentBitCount += bits;
- return ret;
- }
- n *= dim;
- size_t padding = (a - (total % a)) % a;
- if (currentBitCount > 0) {
- bool fitsInBitfield = currentBitCount + (n * charBit) <= currentBitfieldAlloc * charBit;
- bool isAligned = currentBitCount % (charBit * a) == 0;
- if (vt2.isIntegral() && fitsInBitfield && isAligned) {
- currentBitCount += charBit * n;
- return total;
- }
- n += currentBitfieldAlloc;
- currentBitfieldAlloc = 0;
- currentBitCount = 0;
- }
- return vt.typeScope->type == ScopeType::eUnion ? std::max(total, n) : total + padding + n;
- };
- Result result = accumulateStructMembers(vt.typeScope, accHelper, accuracy);
- size_t total = result.total;
- if (currentBitCount > 0)
- total += currentBitfieldAlloc;
- if (const Type* dt = vt.typeScope->definedType) {
- total = std::accumulate(dt->derivedFrom.begin(), dt->derivedFrom.end(), total, [&](size_t v, const Type::BaseInfo& bi) {
- if (bi.type && bi.type->classScope)
- v += accumulateStructMembers(bi.type->classScope, accHelper, accuracy).total;
- return v;
- });
- }
- if (accuracy == Accuracy::ExactOrZero && total == 0 && !result.success)
- return 0;
- total = std::max(size_t{1}, total);
- size_t align = getAlignOf(vt, settings, accuracy);
- if (align == 0)
- return accuracy == Accuracy::ExactOrZero ? 0 : total;
- total += (align - (total % align)) % align;
- return total;
- }
- return 0;
-}
-
static void valueFlowNumber(TokenList &tokenlist, const Settings& settings)
{
for (Token *tok = tokenlist.front(); tok;) {
@@ -3683,8 +3502,8 @@ static bool isTruncated(const ValueType* src, const ValueType* dst, const Settin
if (src->smartPointer && dst->smartPointer)
return false;
if ((src->isIntegral() && dst->isIntegral()) || (src->isFloat() && dst->isFloat())) {
- const size_t srcSize = ValueFlow::getSizeOf(*src, settings, ValueFlow::Accuracy::LowerBound);
- const size_t dstSize = ValueFlow::getSizeOf(*dst, settings, ValueFlow::Accuracy::LowerBound);
+ const size_t srcSize = src->getSizeOf(settings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer);
+ const size_t dstSize = dst->getSizeOf(settings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer);
if (srcSize > dstSize)
return true;
if (srcSize == dstSize && src->sign != dst->sign)
@@ -4207,10 +4026,10 @@ static std::list truncateValues(std::list va
if (!dst || !dst->isIntegral())
return values;
- const size_t sz = ValueFlow::getSizeOf(*dst, settings, ValueFlow::Accuracy::ExactOrZero);
+ const size_t sz = dst->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer);
if (src) {
- const size_t osz = ValueFlow::getSizeOf(*src, settings, ValueFlow::Accuracy::ExactOrZero);
+ const size_t osz = src->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer);
if (osz >= sz && dst->sign == ValueType::Sign::SIGNED && src->sign == ValueType::Sign::UNSIGNED) {
values.remove_if([&](const ValueFlow::Value& value) {
if (!value.isIntValue())
@@ -7078,8 +6897,9 @@ static void valueFlowDynamicBufferSize(const TokenList& tokenlist, const SymbolD
if (!typeTok || !typeTok->varId())
typeTok = newTok->astParent()->previous(); // hack for "int** z = ..."
if (typeTok && typeTok->valueType()) {
- const MathLib::bigint typeSize = typeTok->valueType()->typeSize(settings.platform, typeTok->valueType()->pointer > 1);
- if (typeSize >= 0)
+ const auto sizeOf = typeTok->valueType()->pointer > 1 ? ValueType::SizeOf::Pointer : ValueType::SizeOf::Pointee;
+ const size_t typeSize = typeTok->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, sizeOf);
+ if (typeSize > 0 || numElem == 0)
sizeValue = numElem * typeSize;
}
}
diff --git a/lib/valueflow.h b/lib/valueflow.h
index 85a8e49a9e7..6fe4d052fdf 100644
--- a/lib/valueflow.h
+++ b/lib/valueflow.h
@@ -61,16 +61,6 @@ namespace ValueFlow {
std::string eitherTheConditionIsRedundant(const Token *condition);
- enum class Accuracy : std::uint8_t {
- ExactOrZero,
- LowerBound,
- };
-
- size_t getSizeOf(const ValueType &vt,
- const Settings &settings,
- Accuracy accuracy,
- int maxRecursion = 0);
-
const Value* findValue(const std::list& values,
const Settings& settings,
const std::function &pred);
diff --git a/lib/vf_analyzers.cpp b/lib/vf_analyzers.cpp
index 104563b113b..5f5568663e4 100644
--- a/lib/vf_analyzers.cpp
+++ b/lib/vf_analyzers.cpp
@@ -355,9 +355,7 @@ struct ValueFlowAnalyzer : Analyzer {
/* Truncate value */
const ValueType *dst = tok->valueType();
if (dst) {
- const size_t sz = ValueFlow::getSizeOf(*dst,
- settings,
- ValueFlow::Accuracy::ExactOrZero);
+ const size_t sz = dst->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer);
if (sz > 0 && sz < sizeof(MathLib::biguint)) {
MathLib::bigint newvalue = ValueFlow::truncateIntValue(value->intvalue, sz, dst->sign);
diff --git a/lib/vf_common.cpp b/lib/vf_common.cpp
index 0498a7e303d..56a6b364c44 100644
--- a/lib/vf_common.cpp
+++ b/lib/vf_common.cpp
@@ -114,7 +114,7 @@ namespace ValueFlow
{
const ValueType &valueType = ValueType::parseDecl(typeTok, settings);
- return getSizeOf(valueType, settings, ValueFlow::Accuracy::ExactOrZero);
+ return valueType.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer);
}
// Handle various constants..
@@ -125,7 +125,7 @@ namespace ValueFlow
MathLib::bigint signedValue = MathLib::toBigNumber(tok);
const ValueType* vt = tok->valueType();
if (vt && vt->sign == ValueType::UNSIGNED && signedValue < 0
- && getSizeOf(*vt, settings, ValueFlow::Accuracy::ExactOrZero)
+ && vt->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer)
< sizeof(MathLib::bigint)) {
MathLib::bigint minValue{}, maxValue{};
if (getMinMaxValues(tok->valueType(), settings.platform, minValue, maxValue))
@@ -160,9 +160,7 @@ namespace ValueFlow
(tok->next()->astOperand2()->valueType()->pointer == 0 || // <- TODO this is a bailout, abort when there are array->pointer conversions
(tok->next()->astOperand2()->variable() && !tok->next()->astOperand2()->variable()->isArray())) &&
!tok->next()->astOperand2()->valueType()->isEnum()) { // <- TODO this is a bailout, handle enum with non-int types
- const size_t sz = getSizeOf(*tok->next()->astOperand2()->valueType(),
- settings,
- ValueFlow::Accuracy::ExactOrZero);
+ const size_t sz = tok->next()->astOperand2()->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer);
if (sz) {
Value value(sz);
value.setKnown();
@@ -181,7 +179,7 @@ namespace ValueFlow
}
if (Token::simpleMatch(tok, "sizeof ( *")) {
const ValueType *vt = tok->tokAt(2)->valueType();
- const size_t sz = vt ? getSizeOf(*vt, settings, ValueFlow::Accuracy::ExactOrZero)
+ const size_t sz = vt ? vt->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer)
: 0;
if (sz > 0) {
Value value(sz);
@@ -243,9 +241,7 @@ namespace ValueFlow
if (var->type()->classScope && var->type()->classScope->enumType)
size = getSizeOfType(var->type()->classScope->enumType, settings);
} else if (var->valueType()) {
- size = getSizeOf(*var->valueType(),
- settings,
- ValueFlow::Accuracy::ExactOrZero);
+ size = var->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer);
} else if (!var->type()) {
size = getSizeOfType(var->typeStartToken(), settings);
}
@@ -294,7 +290,7 @@ namespace ValueFlow
}
} else if (!tok2->type()) {
const ValueType& vt = ValueType::parseDecl(tok2, settings);
- size_t sz = getSizeOf(vt, settings, ValueFlow::Accuracy::ExactOrZero);
+ size_t sz = vt.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer);
const Token* brac = tok2->astParent();
while (Token::simpleMatch(brac, "[")) {
const Token* num = brac->astOperand2();
diff --git a/lib/vf_settokenvalue.cpp b/lib/vf_settokenvalue.cpp
index 0140b45ae06..4d39d35daae 100644
--- a/lib/vf_settokenvalue.cpp
+++ b/lib/vf_settokenvalue.cpp
@@ -83,8 +83,8 @@ namespace ValueFlow
// If the sign is the same there is no truncation
if (vt1->sign == vt2->sign)
return value;
- const size_t n1 = getSizeOf(*vt1, settings, ValueFlow::Accuracy::ExactOrZero);
- const size_t n2 = getSizeOf(*vt2, settings, ValueFlow::Accuracy::ExactOrZero);
+ const size_t n1 = vt1->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer);
+ const size_t n2 = vt2->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer);
ValueType::Sign sign = ValueType::Sign::UNSIGNED;
if (n1 < n2)
sign = vt2->sign;
@@ -225,7 +225,7 @@ namespace ValueFlow
{
// Skip setting values that are too big since its ambiguous
if (!value.isImpossible() && value.isIntValue() && value.intvalue < 0 && astIsUnsigned(tok)
- && getSizeOf(*tok->valueType(), settings, ValueFlow::Accuracy::LowerBound)
+ && tok->valueType()->getSizeOf(settings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer)
>= sizeof(MathLib::bigint))
return;
@@ -379,8 +379,8 @@ namespace ValueFlow
const ValueType &valueType = ValueType::parseDecl(castType, settings);
if (value.isImpossible() && value.isIntValue() && value.intvalue < 0
&& astIsUnsigned(tok) && valueType.sign == ValueType::SIGNED && tok->valueType()
- && getSizeOf(*tok->valueType(), settings, ValueFlow::Accuracy::ExactOrZero)
- >= getSizeOf(valueType, settings, ValueFlow::Accuracy::ExactOrZero))
+ && tok->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer)
+ >= valueType.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer))
return;
setTokenValueCast(parent, valueType, value, settings);
}
@@ -642,9 +642,7 @@ namespace ValueFlow
if (v.isIntValue() || v.isSymbolicValue()) {
const ValueType *dst = tok->valueType();
if (dst) {
- const size_t sz = ValueFlow::getSizeOf(*dst,
- settings,
- ValueFlow::Accuracy::ExactOrZero);
+ const size_t sz = dst->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer);
MathLib::bigint newvalue = ValueFlow::truncateIntValue(v.intvalue + 1, sz, dst->sign);
if (v.bound != ValueFlow::Value::Bound::Point) {
if (newvalue < v.intvalue) {
@@ -674,9 +672,7 @@ namespace ValueFlow
if (v.isIntValue() || v.isSymbolicValue()) {
const ValueType *dst = tok->valueType();
if (dst) {
- const size_t sz = ValueFlow::getSizeOf(*dst,
- settings,
- ValueFlow::Accuracy::ExactOrZero);
+ const size_t sz = dst->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer);
MathLib::bigint newvalue = ValueFlow::truncateIntValue(v.intvalue - 1, sz, dst->sign);
if (v.bound != ValueFlow::Value::Bound::Point) {
if (newvalue > v.intvalue) {
diff --git a/man/manual-premium.md b/man/manual-premium.md
index 6ae337a9fb0..9f2e5992537 100644
--- a/man/manual-premium.md
+++ b/man/manual-premium.md
@@ -1158,14 +1158,41 @@ The output screen says:
Default is reading from stdin.
--report-dir=REPORT_DIR
The directory where the html report content is written.
- --source-dir=SOURCE_DIR
- Base directory where source code files can be found.
+ --source-dir=SOURCE_DIR|URL
+ Base directory where source code files can be found, or
+ a URL to a remote GitHub/GitLab repository including a
+ branch, e.g.:
+ --source-dir=https://github.com///blob//
Example usage:
cppcheck gui/test.cpp --xml 2> err.xml
cppcheck-htmlreport --file=err.xml --report-dir=test1 --source-dir=.
+or
+ cppcheck gui/test.cpp --xml 2> err.xml
+ cppcheck-htmlreport --file=err.xml --report-dir=test1 \
+ --source-dir=https://github.com///blob//
+
+## Choosing Between Local Annotated HTML and Remote Repository Links
+
+cppcheck-htmlreport supports two modes for linking to source files:
+ - Local annotated HTML files (default when `--source-dir` is a filesystem path)
+ - Remote GitHub/GitLab links (when `--source-dir` is a URL)
+
+Pointing `--source-dir` to a filesystem path generates local annotated HTML files.
+This is useful when you need a fully self-contained report that works offline,
+includes inline annotations, and is ideal for small or medium projects where
+generation is fast.
+Using a remote GitHub/GitLab URL avoids generating per-file HTML and keeps the
+summary report lightweight and fast to produce. This mode is ideal when the
+source is already hosted online and local duplication is unnecessary.
+Remote mode is especially helpful when the HTML report may be public or widely
+distributed but the source code should remain private, since access control is
+handled by the hosting service.
+In general, local mode fits air-gapped environments, while remote mode works
+best for CI workflows and large or private repositories.
+
# Check Level
## Reduced
diff --git a/man/manual.md b/man/manual.md
index 9698c56e84b..d8da119f388 100644
--- a/man/manual.md
+++ b/man/manual.md
@@ -1198,14 +1198,41 @@ The output screen says:
Default is reading from stdin.
--report-dir=REPORT_DIR
The directory where the html report content is written.
- --source-dir=SOURCE_DIR
- Base directory where source code files can be found.
+ --source-dir=SOURCE_DIR|URL
+ Base directory where source code files can be found, or
+ a URL to a remote GitHub/GitLab repository including a
+ branch, e.g.:
+ --source-dir=https://github.com///blob//
Example usage:
cppcheck gui/test.cpp --xml 2> err.xml
cppcheck-htmlreport --file=err.xml --report-dir=test1 --source-dir=.
+or
+ cppcheck gui/test.cpp --xml 2> err.xml
+ cppcheck-htmlreport --file=err.xml --report-dir=test1 \
+ --source-dir=https://github.com///blob//
+
+## Choosing Between Local Annotated HTML and Remote Repository Links
+
+cppcheck-htmlreport supports two modes for linking to source files:
+ - Local annotated HTML files (default when `--source-dir` is a filesystem path)
+ - Remote GitHub/GitLab links (when `--source-dir` is a URL)
+
+Pointing `--source-dir` to a filesystem path generates local annotated HTML files.
+This is useful when you need a fully self-contained report that works offline,
+includes inline annotations, and is ideal for small or medium projects where
+generation is fast.
+Using a remote GitHub/GitLab URL avoids generating per-file HTML and keeps the
+summary report lightweight and fast to produce. This mode is ideal when the
+source is already hosted online and local duplication is unnecessary.
+Remote mode is especially helpful when the HTML report may be public or widely
+distributed but the source code should remain private, since access control is
+handled by the hosting service.
+In general, local mode fits air-gapped environments, while remote mode works
+best for CI workflows and large or private repositories.
+
# Check Level
## Reduced
diff --git a/test/cfg/gtk.c b/test/cfg/gtk.c
index b2c82216e25..8d5e9dd801d 100644
--- a/test/cfg/gtk.c
+++ b/test/cfg/gtk.c
@@ -293,7 +293,6 @@ void g_new_if_test()
};
const struct a * pNew3;
- // cppcheck-suppress valueFlowBailoutIncompleteVar
if (pNew3 = g_new(struct a, 6)) {
printf("%p", pNew3);
}
@@ -306,7 +305,6 @@ void g_new0_test()
int b;
};
// valid
- // cppcheck-suppress valueFlowBailoutIncompleteVar
struct a * pNew1 = g_new0(struct a, 5);
printf("%p", pNew1);
g_free(pNew1);
@@ -325,7 +323,6 @@ void g_try_new_test()
int b;
};
// valid
- // cppcheck-suppress valueFlowBailoutIncompleteVar
struct a * pNew1 = g_try_new(struct a, 5);
printf("%p", pNew1);
g_free(pNew1);
@@ -343,7 +340,6 @@ void g_try_new0_test()
int b;
};
// valid
- // cppcheck-suppress valueFlowBailoutIncompleteVar
struct a * pNew1 = g_try_new0(struct a, 5);
printf("%p", pNew1);
g_free(pNew1);
@@ -361,7 +357,7 @@ void g_renew_test()
struct a {
int b;
};
- // cppcheck-suppress [leakReturnValNotUsed,valueFlowBailoutIncompleteVar]
+ // cppcheck-suppress leakReturnValNotUsed
g_renew(struct a, NULL, 1);
struct a * pNew = g_new(struct a, 1);
@@ -376,7 +372,7 @@ void g_try_renew_test()
struct a {
int b;
};
- // cppcheck-suppress [leakReturnValNotUsed,valueFlowBailoutIncompleteVar]
+ // cppcheck-suppress leakReturnValNotUsed
g_try_renew(struct a, NULL, 1);
struct a * pNew = g_try_new(struct a, 1);
diff --git a/test/cli/premium_test.py b/test/cli/premium_test.py
index 45121819e87..1bb01260b42 100644
--- a/test/cli/premium_test.py
+++ b/test/cli/premium_test.py
@@ -166,6 +166,23 @@ def test_help(tmpdir):
assert 'cppchecksolutions.com' in stdout, stdout # check for premium help link
+def test_cwe(tmpdir):
+ # Trac 14323 - addon warnings with cwe
+ test_file = os.path.join(tmpdir, 'test.c')
+ addon_file = os.path.join(tmpdir, 'premiumaddon.py')
+
+ with open(test_file, 'wt') as f:
+ f.write('void foo();\n')
+
+ args = [f"--addon={addon_file}", '--xml', test_file]
+
+ with open(addon_file, 'wt') as f:
+ f.write('print(\'{"addon":"a","column":1,"errorId":"id","extra":"","file":"test.c","cwe":123,"linenr":1,"message":"bug","severity":"error"}\')')
+
+ _, _, stderr = cppcheck(args)
+ assert ';\n"
"}\n");
ASSERT_EQUALS("", errout_str());
+
+ check("int f();\n" // #11522
+ "void g() {\n"
+ " int (*fp)() = *(int(*)())f;\n"
+ "}\n");
+ ASSERT_EQUALS("", errout_str());
}
void novardecl() {
diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp
index b9a8a4e63df..ba687ad9983 100644
--- a/test/testmemleak.cpp
+++ b/test/testmemleak.cpp
@@ -2350,7 +2350,7 @@ class TestMemleakNoVar : public TestFixture {
"void x() {\n"
" set_error(strdup(p));\n"
"}");
- TODO_ASSERT_EQUALS("[test.cpp:5]: (error) Allocation with strdup, set_error doesn't release it.\n", "", errout_str());
+ ASSERT_EQUALS("[test.cpp:5:15]: (error) Allocation with strdup, set_error doesn't release it. [leakNoVarFunctionCall]\n", errout_str());
check("void f()\n"
"{\n"
diff --git a/test/testsuppressions.cpp b/test/testsuppressions.cpp
index 205c6a2f33c..f946461ff89 100644
--- a/test/testsuppressions.cpp
+++ b/test/testsuppressions.cpp
@@ -396,7 +396,6 @@ class TestSuppressions : public TestFixture {
}
#endif // HAS_THREADING_MODEL_FORK
- // TODO: check all results
void runChecks(unsigned int (TestSuppressions::*check)(const char[], const std::string &)) {
// check to make sure the appropriate errors are present
ASSERT_EQUALS(1, (this->*check)("void f() {\n"
@@ -720,6 +719,40 @@ class TestSuppressions : public TestFixture {
"[test.cpp:6:0]: (error) unknown suppression type 'cppcheck-suppress-end-unknown' [invalidSuppression]\n"
"[test.cpp:4:0]: (error) Suppress Begin: No matching end [invalidSuppression]\n", errout_str());
+ ASSERT_EQUALS(1, (this->*check)("// cppcheck-suppress-file\n"
+ "// cppcheck-suppress\n"
+ "// cppcheck-suppress \n"
+ "// cppcheck-suppress\t\n"
+ "// cppcheck-suppress []\n" // TODO
+ "// cppcheck-suppress-macro\n"
+ "// cppcheck-suppress-begin\n"
+ "// cppcheck-suppress-begin id0\n"
+ "void f() {}\n"
+ "// cppcheck-suppress-end\n",
+ ""));
+ ASSERT_EQUALS("[test.cpp:1:0]: (error) suppression without error ID [invalidSuppression]\n"
+ "[test.cpp:2:0]: (error) suppression without error ID [invalidSuppression]\n"
+ "[test.cpp:3:0]: (error) suppression without error ID [invalidSuppression]\n"
+ "[test.cpp:4:0]: (error) suppression without error ID [invalidSuppression]\n"
+ "[test.cpp:6:0]: (error) suppression without error ID [invalidSuppression]\n"
+ "[test.cpp:7:0]: (error) suppression without error ID [invalidSuppression]\n"
+ "[test.cpp:10:0]: (error) suppression without error ID [invalidSuppression]\n"
+ "[test.cpp:8:0]: (error) Suppress Begin: No matching end [invalidSuppression]\n", errout_str());
+
+ ASSERT_EQUALS(1, (this->*check)("// cppcheck-suppress:\n"
+ "// cppcheck-suppress-unknown\n"
+ "// cppcheck-suppress-begin-unknown\n"
+ "// cppcheck-suppress-begin\n"
+ "void f() {}\n"
+ "// cppcheck-suppress-end-unknown\n",
+ ""));
+ // TODO: actually these are all invalid types
+ ASSERT_EQUALS("[test.cpp:1:0]: (error) suppression without error ID [invalidSuppression]\n"
+ "[test.cpp:2:0]: (error) suppression without error ID [invalidSuppression]\n"
+ "[test.cpp:3:0]: (error) suppression without error ID [invalidSuppression]\n"
+ "[test.cpp:4:0]: (error) suppression without error ID [invalidSuppression]\n"
+ "[test.cpp:6:0]: (error) suppression without error ID [invalidSuppression]\n", errout_str());
+
ASSERT_EQUALS(1, (this->*check)("void f() {\n"
" int a;\n"
" // cppcheck-suppress-begin uninitvar\n"
@@ -915,13 +948,14 @@ class TestSuppressions : public TestFixture {
"uninitvar"));
ASSERT_EQUALS("", errout_str());
- // cppcheck-suppress-macro
+ // TODO: check result
(this->*check)("// cppcheck-suppress-macro zerodiv\n"
"#define DIV(A,B) A/B\n"
"a = DIV(10,0);\n",
"");
ASSERT_EQUALS("", errout_str());
+ // TODO: check result
(this->*check)("// cppcheck-suppress-macro abc\n"
"#define DIV(A,B) A/B\n"
"a = DIV(10,1);\n",
diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp
index 7d146551d25..e6a1527f2f2 100644
--- a/test/testsymboldatabase.cpp
+++ b/test/testsymboldatabase.cpp
@@ -465,6 +465,8 @@ class TestSymbolDatabase : public TestFixture {
TEST_CASE(enum18);
TEST_CASE(enum19);
+ TEST_CASE(struct1);
+
TEST_CASE(sizeOfType);
TEST_CASE(isImplicitlyVirtual);
@@ -6859,6 +6861,42 @@ class TestSymbolDatabase : public TestFixture {
}
}
+ void struct1() {
+ GET_SYMBOL_DB_C("struct deer {\n"
+ " uint16_t a;\n"
+ " uint16_t b;\n"
+ "};\n"
+ "void herd ( void ) {\n"
+ " struct deer {\n"
+ " uint16_t a;\n"
+ " };\n"
+ "}");
+
+ ASSERT_EQUALS("", errout_str());
+ ASSERT(db);
+
+ const Token* deer = Token::findsimplematch(tokenizer.tokens(), "deer {");
+ ASSERT(deer);
+ ASSERT(deer->type());
+ ASSERT(deer->type()->classScope);
+ const Token* tok = deer->next();
+ ASSERT(tok->scope());
+ ASSERT_EQUALS_ENUM(ScopeType::eStruct, tok->scope()->type);
+ ASSERT_EQUALS(tok, tok->scope()->bodyStart);
+ ASSERT_EQUALS(tok->scope(), deer->type()->classScope);
+
+ const Token* secondDeer = Token::findsimplematch(tok, "deer {");
+ ASSERT(secondDeer);
+ ASSERT(secondDeer != deer);
+ ASSERT(secondDeer->type());
+ ASSERT(secondDeer->type()->classScope);
+ tok = secondDeer->next();
+ ASSERT(tok->scope());
+ ASSERT_EQUALS_ENUM(ScopeType::eStruct, tok->scope()->type);
+ ASSERT_EQUALS(tok, tok->scope()->bodyStart);
+ ASSERT_EQUALS(tok->scope(), secondDeer->type()->classScope);
+ }
+
void sizeOfType() {
// #7615 - crash in Symboldatabase::sizeOfType()
GET_SYMBOL_DB("enum e;\n"
diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp
index c7ac88abcfa..444bb25583e 100644
--- a/test/testtokenize.cpp
+++ b/test/testtokenize.cpp
@@ -4945,6 +4945,20 @@ class TestTokenizer : public TestFixture {
tokenizeAndStringify("struct AB {\n"
" enum Foo {A,B} foo : 4;\n"
"};"));
+
+ ASSERT_EQUALS("struct S {\n" // #14324
+ "enum E : int { E0 , E1 } ; enum E e ;\n"
+ "} ;",
+ tokenizeAndStringify("struct S {\n"
+ " enum E : int { E0, E1 } e : 2;\n"
+ "};\n"));
+
+ ASSERT_EQUALS("struct S {\n"
+ "enum class E : std :: uint8_t { E0 , E1 } ; enum E e ;\n"
+ "} ;",
+ tokenizeAndStringify("struct S {\n"
+ " enum class E : std::uint8_t { E0, E1 } e : 2;\n"
+ "};\n"));
}
void bitfields16() {
diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp
index 200f8252017..5b94a1f7fba 100644
--- a/test/testunusedvar.cpp
+++ b/test/testunusedvar.cpp
@@ -5228,6 +5228,13 @@ class TestUnusedVar : public TestFixture {
" }\n"
"}");
ASSERT_EQUALS("", errout_str());
+
+ functionVariableUsage("void f(const std::vector& v) {\n" // #13303
+ " std::vector::const_iterator it = v.cbegin();\n"
+ " if (*it == 0)\n"
+ " it = v.cend();\n"
+ "}\n");
+ ASSERT_EQUALS("[test.cpp:4:12]: (style) Variable 'it' is assigned a value that is never used. [unreadVariable]\n", errout_str());
}
void localvaralias19() { // #9828
diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp
index 8762c5141d6..79ad6e45b30 100644
--- a/test/testvalueflow.cpp
+++ b/test/testvalueflow.cpp
@@ -1726,6 +1726,22 @@ class TestValueFlow : public TestFixture {
ASSERT_EQUALS(1U, values.size());
ASSERT_EQUALS(-1, values.back().intvalue);
ASSERT_EQUALS_ENUM(ValueFlow::Value::ValueKind::Impossible, values.back().valueKind);
+
+ code = "struct E;\n"
+ "struct B {\n"
+ " E* e;\n"
+ " B* b;\n"
+ "};\n"
+ "struct D : B {};\n"
+ "struct E : B {\n"
+ " B* be;\n"
+ "};\n"
+ "int f() {\n"
+ " return sizeof(D);\n"
+ "}";
+ values = tokenValues(code, "( D )");
+ ASSERT_EQUALS(1U, values.size());
+ TODO_ASSERT_EQUALS(2 * settings.platform.sizeof_pointer, 1, values.back().intvalue);
}
void valueFlowComma()
@@ -7457,6 +7473,32 @@ class TestValueFlow : public TestFixture {
"}";
ASSERT_EQUALS(true, testValueOfX(code, 4U, 100, ValueFlow::Value::ValueType::BUFFER_SIZE));
+ code = "struct A {};\n" // #14305
+ "void* f() {\n"
+ " A* x = new A();\n"
+ " return x;\n"
+ "}";
+ ASSERT_EQUALS(true, testValueOfX(code, 4U, 1, ValueFlow::Value::ValueType::BUFFER_SIZE));
+
+ code = "struct A {};\n"
+ "void* f() {\n"
+ " void* x = new A;\n"
+ " return x;\n"
+ "}";
+ {
+ auto values = tokenValues(code, "x ; }");
+ ASSERT_EQUALS(1, values.size());
+ ASSERT(values.front().isSymbolicValue());
+ // TODO: add BUFFER_SIZE value = 1
+ }
+
+ code = "struct B { int32_t i; };\n"
+ "void* f() {\n"
+ " B* x = new B();\n"
+ " return x;\n"
+ "}";
+ ASSERT_EQUALS(true, testValueOfX(code, 4U, 4, ValueFlow::Value::ValueType::BUFFER_SIZE));
+
settings = settingsOld;
}