From 8f386e15fdedff37486c683d933ccc9a1e307388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Mon, 11 Apr 2022 07:30:55 +0200 Subject: [PATCH] Remove bug hunting. This feature will be provided in Cppcheck premium. --- .github/workflows/CI-unixish.yml | 21 +- .github/workflows/CI-windows.yml | 21 - .github/workflows/asan.yml | 8 +- .github/workflows/bughunting.yml | 47 - .github/workflows/clang-tidy.yml | 3 +- .github/workflows/codeql-analysis.yml | 3 +- .github/workflows/coverage.yml | 3 +- .github/workflows/iwyu.yml | 4 +- .github/workflows/release-windows.yml | 20 - .github/workflows/selfcheck.yml | 11 +- .github/workflows/ubsan.yml | 8 +- .github/workflows/valgrind.yml | 5 +- .travis.yml | 3 +- Makefile | 26 +- cli/CMakeLists.txt | 3 - cli/cmdlineparser.cpp | 14 +- cli/cppcheckexecutor.cpp | 12 +- cli/cppcheckexecutor.h | 7 - cli/threadexecutor.cpp | 10 - cmake/compilerDefinitions.cmake | 4 - cmake/findDependencies.cmake | 14 - cmake/options.cmake | 2 - cmake/printInfo.cmake | 6 - createrelease | 5 +- democlient/democlient.cpp | 2 - externals/z3-LICENSE | 10 - externals/z3_version_old.h | 12 - gui/CMakeLists.txt | 3 - gui/about.ui | 8 +- gui/functioncontractdialog.cpp | 50 - gui/functioncontractdialog.h | 39 - gui/functioncontractdialog.ui | 83 - gui/gui.pro | 21 +- gui/mainwindow.cpp | 106 - gui/mainwindow.h | 21 +- gui/newsuppressiondialog.cpp | 1 - gui/projectfile.cpp | 122 - gui/projectfile.h | 41 - gui/projectfile.ui | 17 - gui/projectfiledialog.cpp | 3 - gui/resultstree.cpp | 27 +- gui/resultstree.h | 7 - gui/resultsview.cpp | 129 - gui/resultsview.h | 38 - gui/resultsview.ui | 103 - gui/test/benchmark/simple/CMakeLists.txt | 3 - gui/test/benchmark/simple/benchmarksimple.h | 1 - gui/test/xmlreportv2/CMakeLists.txt | 3 - gui/threadhandler.cpp | 3 - gui/threadhandler.h | 2 - gui/threadresult.cpp | 7 - gui/threadresult.h | 4 - gui/variablecontractsdialog.cpp | 69 - gui/variablecontractsdialog.h | 44 - gui/variablecontractsdialog.ui | 108 - lib/CMakeLists.txt | 3 - lib/bughuntingchecks.cpp | 719 ----- lib/bughuntingchecks.h | 31 - lib/check.cpp | 4 +- lib/checkmemoryleak.cpp | 2 +- lib/cppcheck.cpp | 69 +- lib/cppcheck.h | 2 - lib/cppcheck.vcxproj | 6 +- lib/cppcheck.vcxproj.filters | 11 +- lib/errorlogger.cpp | 26 +- lib/errorlogger.h | 8 +- lib/exprengine.cpp | 3174 ------------------- lib/exprengine.h | 348 -- lib/importproject.cpp | 29 +- lib/importproject.h | 7 - lib/lib.pri | 4 - lib/library.cpp | 56 +- lib/library.h | 3 - lib/settings.cpp | 5 +- lib/settings.h | 21 - lib/token.cpp | 15 - lib/token.h | 2 - oss-fuzz/CMakeLists.txt | 3 - oss-fuzz/main.cpp | 3 - readme.txt | 8 - test/testbughuntingchecks.cpp | 389 --- test/testcppcheck.cpp | 1 - test/testexprengine.cpp | 1076 ------- test/testrunner.vcxproj | 3 +- test/testrunner.vcxproj.filters | 3 - test/testsuite.h | 1 - tools/dmake.cpp | 10 - win_installer/config.wxi | 1 - win_installer/cppcheck.wxs | 5 - win_installer/productInfo.wxi | 1 - 90 files changed, 87 insertions(+), 7309 deletions(-) delete mode 100644 .github/workflows/bughunting.yml delete mode 100644 externals/z3-LICENSE delete mode 100644 externals/z3_version_old.h delete mode 100644 gui/functioncontractdialog.cpp delete mode 100644 gui/functioncontractdialog.h delete mode 100644 gui/functioncontractdialog.ui delete mode 100644 gui/variablecontractsdialog.cpp delete mode 100644 gui/variablecontractsdialog.h delete mode 100644 gui/variablecontractsdialog.ui delete mode 100644 lib/bughuntingchecks.cpp delete mode 100644 lib/bughuntingchecks.h delete mode 100644 lib/exprengine.cpp delete mode 100644 lib/exprengine.h delete mode 100644 test/testbughuntingchecks.cpp delete mode 100644 test/testexprengine.cpp diff --git a/.github/workflows/CI-unixish.yml b/.github/workflows/CI-unixish.yml index 259333dd1..18e039c13 100644 --- a/.github/workflows/CI-unixish.yml +++ b/.github/workflows/CI-unixish.yml @@ -22,18 +22,13 @@ jobs: run: | sudo apt-get update sudo apt-get install libxml2-utils - sudo apt-get install libz3-dev libtinyxml2-dev + sudo apt-get install libtinyxml2-dev sudo apt-get install qtbase5-dev qttools5-dev libqt5charts5-dev qt5-default - - name: Fix missing z3_version.h - if: matrix.os == 'ubuntu-18.04' - run: | - cp externals/z3_version_old.h externals/z3_version.h - - name: Install missing software on macos if: contains(matrix.os, 'macos') run: | - brew install coreutils python3 z3 qt@5 + brew install coreutils python3 qt@5 - name: Install missing Python packages run: | @@ -45,7 +40,7 @@ jobs: run: | mkdir cmake.output.tinyxml2 cd cmake.output.tinyxml2 - cmake -G "Unix Makefiles" -DUSE_Z3=On -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DUSE_BUNDLED_TINYXML2=Off .. + cmake -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DUSE_BUNDLED_TINYXML2=Off .. cmake --build . -- -j$(nproc) cd .. @@ -59,7 +54,7 @@ jobs: run: | mkdir cmake.output cd cmake.output - cmake -G "Unix Makefiles" -DUSE_Z3=On -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On .. + cmake -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On .. cmake --build . -- -j$(nproc) cd .. @@ -68,7 +63,7 @@ jobs: run: | mkdir cmake.output cd cmake.output - cmake -G "Unix Makefiles" -DUSE_Z3=On -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DQt5_DIR=$(brew --prefix qt@5)/lib/cmake/Qt5 .. + cmake -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DQt5_DIR=$(brew --prefix qt@5)/lib/cmake/Qt5 .. cmake --build . -- -j$(nproc) cd .. @@ -95,15 +90,15 @@ jobs: - name: Build cppcheck run: | make clean - make -j$(nproc) USE_Z3=yes HAVE_RULES=yes + make -j$(nproc) HAVE_RULES=yes - name: Build test run: | - make -j$(nproc) testrunner USE_Z3=yes HAVE_RULES=yes + make -j$(nproc) testrunner HAVE_RULES=yes - name: Run test run: | - make -j$(nproc) check USE_Z3=yes HAVE_RULES=yes + make -j$(nproc) check HAVE_RULES=yes # the script uses sed parameters not supported by MacOS - name: Run extra tests diff --git a/.github/workflows/CI-windows.yml b/.github/workflows/CI-windows.yml index e39718b29..3496d2c92 100644 --- a/.github/workflows/CI-windows.yml +++ b/.github/workflows/CI-windows.yml @@ -25,8 +25,6 @@ jobs: env: # see https://www.pcre.org/original/changelog.txt PCRE_VERSION: 8.45 - # see https://github.com/Z3Prover/z3/releases: - Z3_VERSION: 4.8.15 steps: - uses: actions/checkout@v2 @@ -72,25 +70,6 @@ jobs: env: CL: /MP - - name: Cache Z3 Library - id: cache-z3 - uses: actions/cache@v2 - if: matrix.arch == 'x64' || matrix.qt_ver == '' - with: - path: z3-${{ env.Z3_VERSION }}-${{ matrix.arch }}-win.zip - key: z3-${{ env.Z3_VERSION }}-${{ matrix.arch }}-win - - - name: Download Z3 library - if: (matrix.arch == 'x64' || matrix.qt_ver == '') && steps.cache-z3.outputs.cache-hit != 'true' - run: | - curl -fsSL https://github.com/Z3Prover/z3/releases/download/z3-%Z3_VERSION%/z3-%Z3_VERSION%-${{ matrix.arch }}-win.zip -o z3-%Z3_VERSION%-${{ matrix.arch }}-win.zip || exit /b !errorlevel! - - - name: Install Z3 library - if: matrix.arch == 'x64' || matrix.qt_ver == '' - run: | - 7z x z3-%Z3_VERSION%-${{ matrix.arch }}-win.zip -oexternals -r -y || exit /b !errorlevel! - move externals\z3-%Z3_VERSION%-${{ matrix.arch }}-win externals\z3 || exit /b !errorlevel! - - name: Cache Qt ${{ matrix.qt_ver }} if: matrix.qt_ver != '' && matrix.arch == 'x64' id: cache-qt diff --git a/.github/workflows/asan.yml b/.github/workflows/asan.yml index 43fddfa94..1a12c6301 100644 --- a/.github/workflows/asan.yml +++ b/.github/workflows/asan.yml @@ -26,11 +26,11 @@ jobs: - name: Install missing software on ubuntu run: | apt-get update - apt-get install -y make libz3-dev libpcre3-dev + apt-get install -y make libpcre3-dev apt-get install -y clang-13 - name: Build - run: make -j$(nproc) cppcheck testrunner USE_Z3=yes HAVE_RULES=yes MATCHCOMPILER=yes VERIFY=1 + run: make -j$(nproc) cppcheck testrunner HAVE_RULES=yes MATCHCOMPILER=yes VERIFY=1 env: CC: clang-13 CXX: clang++-13 @@ -47,7 +47,3 @@ jobs: # ./cppcheck -q -j$(nproc) --std=c++11 --template=selfcheck -D__CPPCHECK__ -DQT_VERSION=0x050000 --error-exitcode=1 --inline-suppr --suppressions-list=.travis_suppressions --library=qt -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2/ --enable=style,performance,portability,warning,internal --exception-handling --debug-warnings gui/*.cpp # ./cppcheck -q -j$(nproc) --std=c++11 --template=selfcheck -D__CPPCHECK__ --error-exitcode=1 --inline-suppr --suppressions-list=.travis_suppressions --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2/ -Icli -Igui --inconclusive --enable=style,performance,portability,warning,internal --exception-handling --debug-warnings test/*.cpp tools -# TODO: This does takes too long to run -# - name: Bughunting lib -# run: ./cppcheck -D__CPPCHECK__ --bug-hunting -j$(nproc) lib - diff --git a/.github/workflows/bughunting.yml b/.github/workflows/bughunting.yml deleted file mode 100644 index 8f88c2a6c..000000000 --- a/.github/workflows/bughunting.yml +++ /dev/null @@ -1,47 +0,0 @@ -# Syntax reference https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions -# Environment reference https://help.github.com/en/actions/reference/virtual-environments-for-github-hosted-runners -name: bughunting - -# TODO: enable this when -on: workflow_dispatch - -jobs: - build: - - runs-on: ubuntu-20.04 - - steps: - - uses: actions/checkout@v2 - - - name: Set up Python 3.10 - uses: actions/setup-python@v2 - with: - python-version: '3.10' - - - name: Install missing software - run: | - sudo apt-get update - sudo apt-get install z3 libz3-dev - - - name: Build cppcheck - run: | - make -j$(nproc) USE_Z3=yes HAVE_RULES=yes MATCHCOMPILER=yes - env: - CXXFLAGS: "-O2 -march=native" - - # currently to slow to execute it in the CI - - name: Run CVE suite - run: | - python test/bug-hunting/cve.py - - - name: Run ITC suite - run: | - git clone https://github.com/regehr/itc-benchmarks.git ~/itc - python test/bug-hunting/itc.py - - - name: Run juliet - run: | - mkdir ~/juliet - curl https://samate.nist.gov/SARD/testsuites/juliet/Juliet_Test_Suite_v1.3_for_C_Cpp.zip -o ~/juliet/juliet.zip - cd ~/juliet && unzip -qq ~/juliet/juliet.zip - python test/bug-hunting/juliet.py diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index e0df49728..1536e16ac 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -22,7 +22,6 @@ jobs: run: | apt-get update apt-get install -y cmake g++ make - apt-get install -y libz3-dev apt-get install -y libpcre3-dev apt-get install -y libffi7 # work around missing dependency for Qt install step apt-get install -y clang-tidy-13 @@ -46,7 +45,7 @@ jobs: run: | mkdir cmake.output cd cmake.output - cmake -G "Unix Makefiles" -DUSE_Z3=On -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DCPPCHK_GLIBCXX_DEBUG=Off .. + cmake -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DCPPCHK_GLIBCXX_DEBUG=Off .. cd .. - name: Prepare CMake dependencies diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 1734626ef..4d487c1ea 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,7 +24,6 @@ jobs: run: | sudo apt-get update sudo apt-get install libxml2-utils - sudo apt-get install libz3-dev libz3-4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL @@ -38,7 +37,7 @@ jobs: setup-python-dependencies: false - run: | - make -j$(nproc) USE_Z3=yes HAVE_RULES=yes cppcheck + make -j$(nproc) HAVE_RULES=yes cppcheck - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 120db3e9f..4334e852f 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -16,7 +16,6 @@ jobs: run: | sudo apt-get update sudo apt-get install libxml2-utils - sudo apt-get install libz3-dev libz3-4 sudo apt-get install lcov sudo apt-get install libcppunit-dev python -m pip install pip --upgrade @@ -24,7 +23,7 @@ jobs: - name: Compile instrumented run: | - make -j$(nproc) test CXXFLAGS="-g -fprofile-arcs -ftest-coverage" USE_Z3=yes HAVE_RULES=yes + make -j$(nproc) test CXXFLAGS="-g -fprofile-arcs -ftest-coverage" HAVE_RULES=yes - name: Generate coverage report run: | diff --git a/.github/workflows/iwyu.yml b/.github/workflows/iwyu.yml index f52ac353e..44c2732dc 100644 --- a/.github/workflows/iwyu.yml +++ b/.github/workflows/iwyu.yml @@ -19,7 +19,7 @@ jobs: - name: Install missing software run: | apt-get update - apt-get install -y cmake g++ make libz3-dev libpcre3-dev + apt-get install -y cmake g++ make libpcre3-dev apt-get install -y qtbase5-dev qttools5-dev libqt5charts5-dev apt-get install -y wget iwyu @@ -27,7 +27,7 @@ jobs: run: | mkdir cmake.output cd cmake.output - cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DUSE_Z3=On -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off .. + cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=On -DBUILD_TESTS=On -DBUILD_GUI=On -DWITH_QCHART=On -DCMAKE_GLOBAL_AUTOGEN_TARGET=On -DCMAKE_DISABLE_PRECOMPILE_HEADERS=On -DCPPCHK_GLIBCXX_DEBUG=Off -DUSE_MATCHCOMPILER=Off .. cd .. - name: Prepare CMake dependencies diff --git a/.github/workflows/release-windows.yml b/.github/workflows/release-windows.yml index 841c3fe42..6c635d28a 100644 --- a/.github/workflows/release-windows.yml +++ b/.github/workflows/release-windows.yml @@ -25,8 +25,6 @@ jobs: env: # see https://www.pcre.org/original/changelog.txt PCRE_VERSION: 8.45 - # see https://github.com/Z3Prover/z3/releases: - Z3_VERSION: 4.8.15 QT_VERSION: 5.15.2 steps: @@ -56,23 +54,6 @@ jobs: copy pcre.h ..\externals copy Release\pcre.lib ..\externals\pcre64.lib - - name: Cache Z3 Library - id: cache-z3 - uses: actions/cache@v2 - with: - path: z3-${{ env.Z3_VERSION }}-x64-win.zip - key: z3-${{ env.Z3_VERSION }}-x64-win - - - name: Download Z3 library - if: steps.cache-z3.outputs.cache-hit != 'true' - run: | - curl -fsSL https://github.com/Z3Prover/z3/releases/download/z3-%Z3_VERSION%/z3-%Z3_VERSION%-x64-win.zip -o z3-%Z3_VERSION%-x64-win.zip - - - name: Install Z3 library - run: | - 7z x z3-%Z3_VERSION%-x64-win.zip -oexternals -r -y - move externals\z3-%Z3_VERSION%-x64-win externals\z3 - - name: Cache Qt ${{ env.QT_VERSION }} id: cache-qt uses: actions/cache@v1 # not v2! @@ -125,7 +106,6 @@ jobs: copy platforms\*.xml win_installer\files\platforms copy bin\cppcheck.exe win_installer\files copy bin\cppcheck-core.dll win_installer\files - copy externals\z3\bin\libz3.dll win_installer\files mkdir win_installer\files\help xcopy /s gui\help win_installer\files\help del win_installer\files\translations\*.qm diff --git a/.github/workflows/selfcheck.yml b/.github/workflows/selfcheck.yml index 9d5829580..a03a6cf59 100644 --- a/.github/workflows/selfcheck.yml +++ b/.github/workflows/selfcheck.yml @@ -15,11 +15,6 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Install missing software - run: | - sudo apt-get update - sudo apt-get install libz3-dev - - name: Cache Qt ${{ env.QT_VERSION }} id: cache-qt uses: actions/cache@v1 # not v2! @@ -44,7 +39,7 @@ jobs: run: | mkdir cmake.output pushd cmake.output - cmake -G "Unix Makefiles" -DUSE_Z3=On -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=ON -DWITH_QCHART=ON -DCMAKE_GLOBAL_AUTOGEN_TARGET=On .. + cmake -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=On -DBUILD_GUI=ON -DWITH_QCHART=ON -DCMAKE_GLOBAL_AUTOGEN_TARGET=On .. - name: Generate dependencies run: | @@ -68,7 +63,7 @@ jobs: run: | mkdir cmake.output.notest pushd cmake.output.notest - cmake -G "Unix Makefiles" -DUSE_Z3=On -DHAVE_RULES=On -DBUILD_TESTS=0 -DBUILD_GUI=ON -DWITH_QCHART=ON -DCMAKE_GLOBAL_AUTOGEN_TARGET=On .. + cmake -G "Unix Makefiles" -DHAVE_RULES=On -DBUILD_TESTS=0 -DBUILD_GUI=ON -DWITH_QCHART=ON -DCMAKE_GLOBAL_AUTOGEN_TARGET=On .. - name: Generate dependencies (no test) run: | @@ -83,4 +78,4 @@ jobs: run: | ./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib --library=qt -D__GNUC__ -DQT_VERSION=0x050000 -DQ_MOC_OUTPUT_REVISION=67 --inconclusive --enable=unusedFunction --exception-handling -rp=. --project=cmake.output.notest/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr env: - DISABLE_VALUEFLOW: 1 \ No newline at end of file + DISABLE_VALUEFLOW: 1 diff --git a/.github/workflows/ubsan.yml b/.github/workflows/ubsan.yml index 5d82154eb..7c81fe458 100644 --- a/.github/workflows/ubsan.yml +++ b/.github/workflows/ubsan.yml @@ -26,11 +26,11 @@ jobs: - name: Install missing software on ubuntu run: | apt-get update - apt-get install -y make libz3-dev libpcre3-dev + apt-get install -y make libpcre3-dev apt-get install -y clang-13 - name: Build - run: make -j$(nproc) cppcheck testrunner USE_Z3=yes HAVE_RULES=yes MATCHCOMPILER=yes VERIFY=1 + run: make -j$(nproc) cppcheck testrunner HAVE_RULES=yes MATCHCOMPILER=yes VERIFY=1 env: CC: clang-13 CXX: clang++-13 @@ -46,7 +46,3 @@ jobs: ./cppcheck -q -j$(nproc) --std=c++11 --template=selfcheck -D__CPPCHECK__ -DQT_VERSION=0x050000 --error-exitcode=1 --inline-suppr --suppressions-list=.travis_suppressions --library=qt -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2/ --enable=style,performance,portability,warning,internal --exception-handling --debug-warnings gui/*.cpp ./cppcheck -q -j$(nproc) --std=c++11 --template=selfcheck -D__CPPCHECK__ --error-exitcode=1 --inline-suppr --suppressions-list=.travis_suppressions --library=cppcheck-lib -Ilib -Iexternals/simplecpp/ -Iexternals/tinyxml2/ -Icli -Igui --inconclusive --enable=style,performance,portability,warning,internal --exception-handling --debug-warnings test/*.cpp tools -# TODO: This does takes too long to run -# - name: Bughunting lib -# run: ./cppcheck -D__CPPCHECK__ --bug-hunting -j$(nproc) lib - diff --git a/.github/workflows/valgrind.yml b/.github/workflows/valgrind.yml index 5f9bb5b97..941f725b6 100644 --- a/.github/workflows/valgrind.yml +++ b/.github/workflows/valgrind.yml @@ -30,16 +30,15 @@ jobs: sudo apt-get update sudo apt-get install libxml2-utils sudo apt-get install valgrind - sudo apt-get install libz3-dev libz3-4 libz3-4-dbgsym sudo apt-get install libc6-dbg-amd64-cross - name: Build cppcheck run: | - CXXFLAGS="-O1 -g" make -j$(nproc) USE_Z3=yes HAVE_RULES=yes MATCHCOMPILER=yes + CXXFLAGS="-O1 -g" make -j$(nproc) HAVE_RULES=yes MATCHCOMPILER=yes - name: Build test run: | - CXXFLAGS="-O1 -g" make -j$(nproc) testrunner USE_Z3=yes HAVE_RULES=yes MATCHCOMPILER=yes + CXXFLAGS="-O1 -g" make -j$(nproc) testrunner HAVE_RULES=yes MATCHCOMPILER=yes - name: Run valgrind run: | diff --git a/.travis.yml b/.travis.yml index 34ca800a0..46c3a211c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ env: before_install: # install needed deps - travis_retry sudo apt-get update -qq - - travis_retry sudo apt-get install -qq python3-pip libxml2-utils libpcre3 gdb unzip wx-common xmlstarlet python3-dev liblua5.3-dev libcurl3 libcairo2-dev libsigc++-2.0-dev tidy libopencv-dev libz3-dev + - travis_retry sudo apt-get install -qq python3-pip libxml2-utils libpcre3 gdb unzip wx-common xmlstarlet python3-dev liblua5.3-dev libcurl3 libcairo2-dev libsigc++-2.0-dev tidy libopencv-dev # Python 2 modules - travis_retry python2 -m pip install --user pytest==4.6.4 - travis_retry python2 -m pip install --user unittest2 @@ -32,7 +32,6 @@ before_install: - travis_retry python3 -m pip install --user requests # imported by tools/pr.py - travis_retry python3 -m pip install --user pygments - travis_retry python3 -m pip install --user natsort - - cp externals/z3_version_old.h externals/z3_version.h # because travis z3 version is old matrix: # do notify immediately about it when a job of a build fails. diff --git a/Makefile b/Makefile index fec318778..a3c699d91 100644 --- a/Makefile +++ b/Makefile @@ -5,14 +5,6 @@ ifndef HAVE_RULES HAVE_RULES=no endif -ifndef USE_Z3 - USE_Z3=no -endif - -ifeq ($(USE_Z3),yes) - CPPFLAGS += -DUSE_Z3 - LIBS += -lz3 -endif # use match compiler ifeq ($(SRCDIR),build) $(warning Usage of SRCDIR to activate match compiler is deprecated. Use MATCHCOMPILER=yes instead.) @@ -154,7 +146,6 @@ MAN_SOURCE=man/cppcheck.1.xml LIBOBJ = $(libcppdir)/analyzerinfo.o \ $(libcppdir)/astutils.o \ - $(libcppdir)/bughuntingchecks.o \ $(libcppdir)/check.o \ $(libcppdir)/check64bit.o \ $(libcppdir)/checkassert.o \ @@ -187,7 +178,6 @@ LIBOBJ = $(libcppdir)/analyzerinfo.o \ $(libcppdir)/ctu.o \ $(libcppdir)/errorlogger.o \ $(libcppdir)/errortypes.o \ - $(libcppdir)/exprengine.o \ $(libcppdir)/forwardanalyzer.o \ $(libcppdir)/importproject.o \ $(libcppdir)/infer.o \ @@ -229,7 +219,6 @@ TESTOBJ = test/options.o \ test/testbool.o \ test/testboost.o \ test/testbufferoverrun.o \ - test/testbughuntingchecks.o \ test/testcharvar.o \ test/testclangimport.o \ test/testclass.o \ @@ -239,7 +228,6 @@ TESTOBJ = test/options.o \ test/testcppcheck.o \ test/testerrorlogger.o \ test/testexceptionsafety.o \ - test/testexprengine.o \ test/testfilelister.o \ test/testfunctions.o \ test/testgarbage.o \ @@ -410,9 +398,6 @@ $(libcppdir)/analyzerinfo.o: lib/analyzerinfo.cpp externals/tinyxml2/tinyxml2.h $(libcppdir)/astutils.o: lib/astutils.cpp lib/astutils.h lib/check.h lib/checkclass.h lib/config.h lib/errortypes.h lib/importproject.h lib/infer.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/astutils.o $(libcppdir)/astutils.cpp -$(libcppdir)/bughuntingchecks.o: lib/bughuntingchecks.cpp lib/astutils.h lib/bughuntingchecks.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/exprengine.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/utils.h lib/valueflow.h - $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/bughuntingchecks.o $(libcppdir)/bughuntingchecks.cpp - $(libcppdir)/check.o: lib/check.cpp lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/check.o $(libcppdir)/check.cpp @@ -497,7 +482,7 @@ $(libcppdir)/clangimport.o: lib/clangimport.cpp lib/clangimport.h lib/config.h l $(libcppdir)/color.o: lib/color.cpp lib/color.h lib/config.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/color.o $(libcppdir)/color.cpp -$(libcppdir)/cppcheck.o: lib/cppcheck.cpp externals/picojson/picojson.h externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.h lib/analyzerinfo.h lib/check.h lib/checkunusedfunctions.h lib/clangimport.h lib/color.h lib/config.h lib/cppcheck.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/exprengine.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/version.h +$(libcppdir)/cppcheck.o: lib/cppcheck.cpp externals/picojson/picojson.h externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.h lib/analyzerinfo.h lib/check.h lib/checkunusedfunctions.h lib/clangimport.h lib/color.h lib/config.h lib/cppcheck.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/version.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/cppcheck.o $(libcppdir)/cppcheck.cpp $(libcppdir)/ctu.o: lib/ctu.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h @@ -509,9 +494,6 @@ $(libcppdir)/errorlogger.o: lib/errorlogger.cpp externals/tinyxml2/tinyxml2.h li $(libcppdir)/errortypes.o: lib/errortypes.cpp lib/config.h lib/errortypes.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/errortypes.o $(libcppdir)/errortypes.cpp -$(libcppdir)/exprengine.o: lib/exprengine.cpp lib/astutils.h lib/bughuntingchecks.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/exprengine.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h - $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/exprengine.o $(libcppdir)/exprengine.cpp - $(libcppdir)/forwardanalyzer.o: lib/forwardanalyzer.cpp lib/analyzer.h lib/astutils.h lib/config.h lib/errortypes.h lib/forwardanalyzer.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/utils.h lib/valueflow.h lib/valueptr.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/forwardanalyzer.o $(libcppdir)/forwardanalyzer.cpp @@ -620,9 +602,6 @@ test/testboost.o: test/testboost.cpp lib/check.h lib/checkboost.h lib/color.h li test/testbufferoverrun.o: test/testbufferoverrun.cpp externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.h lib/check.h lib/checkbufferoverrun.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testbufferoverrun.o test/testbufferoverrun.cpp -test/testbughuntingchecks.o: test/testbughuntingchecks.cpp lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/exprengine.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h - $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testbughuntingchecks.o test/testbughuntingchecks.cpp - test/testcharvar.o: test/testcharvar.cpp lib/check.h lib/checkother.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testcharvar.o test/testcharvar.cpp @@ -650,9 +629,6 @@ test/testerrorlogger.o: test/testerrorlogger.cpp externals/tinyxml2/tinyxml2.h l test/testexceptionsafety.o: test/testexceptionsafety.cpp lib/check.h lib/checkexceptionsafety.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testexceptionsafety.o test/testexceptionsafety.cpp -test/testexprengine.o: test/testexprengine.cpp lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/exprengine.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h - $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testexprengine.o test/testexprengine.cpp - test/testfilelister.o: test/testfilelister.cpp cli/filelister.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/pathmatch.h lib/suppressions.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testfilelister.o test/testfilelister.cpp diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index 626b968dc..20915ae4e 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -29,9 +29,6 @@ target_include_directories(cppcheck PRIVATE ${PROJECT_SOURCE_DIR}/externals/simp if (HAVE_RULES) target_link_libraries(cppcheck ${PCRE_LIBRARY}) endif() -if (USE_Z3) - target_link_libraries(cppcheck ${Z3_LIBRARIES}) -endif() if (WIN32 AND NOT BORLAND) if(NOT MINGW) target_link_libraries(cppcheck Shlwapi.lib) diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 6dfa4eede..0c3f84320 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -229,13 +229,6 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) else if (std::strncmp(argv[i],"--addon-python=", 15) == 0) mSettings->addonPython.assign(argv[i]+15); - else if (std::strcmp(argv[i], "--bug-hunting") == 0) - mSettings->bugHunting = true; - - // TODO: Rename or move this parameter? - else if (std::strncmp(argv[i], "--bug-hunting-check-function-max-time=", 38) == 0) - mSettings->bugHuntingCheckFunctionMaxTime = std::atoi(argv[i] + 38); - // Check configuration else if (std::strcmp(argv[i], "--check-config") == 0) mSettings->checkConfiguration = true; @@ -278,10 +271,6 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) std::strcmp(argv[i], "--debug-normal") == 0) mSettings->debugnormal = true; - // show bug hunting debug output - else if (std::strcmp(argv[i], "--debug-bug-hunting") == 0) - mSettings->debugBugHunting = true; - // Flag used for various purposes during debugging else if (std::strcmp(argv[i], "--debug-simplified") == 0) mSettings->debugSimplified = true; @@ -1289,6 +1278,5 @@ void CmdLineParser::printHelp() " * tinyxml2 -- loading project/library/ctu files.\n" " * picojson -- loading compile database.\n" " * pcre -- rules.\n" - " * qt -- used in GUI\n" - " * z3 -- theorem prover from Microsoft Research used in bug hunting.\n"; + " * qt -- used in GUI\n"; } diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 784884f61..af227c891 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -92,13 +92,12 @@ /*static*/ FILE* CppCheckExecutor::mExceptionOutput = stdout; CppCheckExecutor::CppCheckExecutor() - : mSettings(nullptr), mLatestProgressOutputTime(0), mErrorOutput(nullptr), mBugHuntingReport(nullptr), mShowAllErrors(false) + : mSettings(nullptr), mLatestProgressOutputTime(0), mErrorOutput(nullptr), mShowAllErrors(false) {} CppCheckExecutor::~CppCheckExecutor() { delete mErrorOutput; - delete mBugHuntingReport; } bool CppCheckExecutor::parseFromArgs(CppCheck *cppcheck, int argc, const char* const argv[]) @@ -1121,15 +1120,6 @@ void CppCheckExecutor::reportErr(const ErrorMessage &msg) reportErr(msg.toString(mSettings->verbose, mSettings->templateFormat, mSettings->templateLocation)); } -void CppCheckExecutor::bughuntingReport(const std::string &str) -{ - if (!mSettings || str.empty()) - return; - if (!mBugHuntingReport) - mBugHuntingReport = new std::ofstream(mSettings->bugHuntingReport); - (*mBugHuntingReport) << str << std::endl; -} - void CppCheckExecutor::setExceptionOutput(FILE* exceptionOutput) { mExceptionOutput = exceptionOutput; diff --git a/cli/cppcheckexecutor.h b/cli/cppcheckexecutor.h index 93a723cf6..6d437b275 100644 --- a/cli/cppcheckexecutor.h +++ b/cli/cppcheckexecutor.h @@ -86,8 +86,6 @@ public: */ void reportInfo(const ErrorMessage &msg) override; - void bughuntingReport(const std::string &str) override; - /** * Information about how many files have been checked * @@ -195,11 +193,6 @@ private: */ std::ofstream *mErrorOutput; - /** - * Bug hunting report - */ - std::ostream *mBugHuntingReport; - /** * Has --errorlist been given? */ diff --git a/cli/threadexecutor.cpp b/cli/threadexecutor.cpp index 04e302d27..67c91b947 100644 --- a/cli/threadexecutor.cpp +++ b/cli/threadexecutor.cpp @@ -91,10 +91,6 @@ public: report(msg, MessageType::REPORT_INFO); } - void bughuntingReport(const std::string &str) override { - writeToPipe(REPORT_VERIFICATION, str); - } - void writeEnd(const std::string& str) { writeToPipe(CHILD_END, str); } @@ -425,12 +421,6 @@ public: report(msg, MessageType::REPORT_INFO); } - void bughuntingReport(const std::string &str) override - { - std::lock_guard lg(mReportSync); - mThreadExecutor.mErrorLogger.bughuntingReport(str); - } - ThreadExecutor &mThreadExecutor; std::map::const_iterator mItNextFile; diff --git a/cmake/compilerDefinitions.cmake b/cmake/compilerDefinitions.cmake index 905a9de76..3ee4665f8 100644 --- a/cmake/compilerDefinitions.cmake +++ b/cmake/compilerDefinitions.cmake @@ -19,10 +19,6 @@ if (HAVE_RULES) add_definitions(-DHAVE_RULES -DTIXML_USE_STL) endif() -if (USE_Z3) - add_definitions(-DUSE_Z3) -endif() - if (Boost_FOUND) add_definitions(-DHAVE_BOOST) endif() diff --git a/cmake/findDependencies.cmake b/cmake/findDependencies.cmake index 08f2950cd..918f3d5a5 100644 --- a/cmake/findDependencies.cmake +++ b/cmake/findDependencies.cmake @@ -17,20 +17,6 @@ if (HAVE_RULES) endif() endif() -if (USE_Z3) - find_package(Z3 QUIET) - if (NOT Z3_FOUND) - find_library(Z3_LIBRARIES z3) - if (NOT Z3_LIBRARIES) - message(FATAL_ERROR "z3 dependency has not been found") - endif() - find_path(Z3_CXX_INCLUDE_DIRS z3++.h PATH_SUFFIXES "z3") - if (NOT Z3_CXX_INCLUDE_DIRS) - message(FATAL_ERROR "z3++.h has not been found") - endif() - endif() -endif() - set(CMAKE_INCLUDE_CURRENT_DIR ON) if (NOT USE_MATCHCOMPILER_OPT MATCHES "Off") diff --git a/cmake/options.cmake b/cmake/options.cmake index 709895fd2..c6dc87fc9 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -1,4 +1,3 @@ -#------------------------------------------------------ # Build type #------------------------------------------------------ set(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo;MinSizeRel" CACHE STRING "Configs" FORCE) @@ -40,7 +39,6 @@ option(BUILD_GUI "Build the qt application" option(WITH_QCHART "When building GUI(need BUILD_GUI=ON), use Qt5 Charts" OFF) option(HAVE_RULES "Usage of rules (needs PCRE library and headers)" OFF) -option(USE_Z3 "Usage of z3 library" OFF) option(USE_BUNDLED_TINYXML2 "Usage of bundled tinyxml2 library" ON) option(CPPCHK_GLIBCXX_DEBUG "Usage of _GLIBCXX_DEBUG in Debug build" ON) option(USE_THREADS "Usage of threads instead of fork() for -j" OFF) diff --git a/cmake/printInfo.cmake b/cmake/printInfo.cmake index c70edb12b..2fcb4f71a 100644 --- a/cmake/printInfo.cmake +++ b/cmake/printInfo.cmake @@ -58,12 +58,6 @@ if (NOT USE_MATCHCOMPILER_OPT MATCHES "Off") message( STATUS "PYTHON_EXECUTABLE = ${PYTHON_EXECUTABLE}" ) endif() message( STATUS ) -message( STATUS "USE_Z3 = ${USE_Z3}" ) -if (USE_Z3) - message( STATUS "Z3_LIBRARIES = ${Z3_LIBRARIES}" ) - message( STATUS "Z3_CXX_INCLUDE_DIRS = ${Z3_CXX_INCLUDE_DIRS}" ) -endif() -message( STATUS ) message( STATUS "USE_BUNDLED_TINYXML2 = ${USE_BUNDLED_TINYXML2}" ) if (NOT USE_BUNDLED_TINYXML2) message(STATUS "tinyxml2_LIBRARIES = ${tinyxml2_LIBRARIES}") diff --git a/createrelease b/createrelease index 3e140dc1e..fb622eeb7 100755 --- a/createrelease +++ b/createrelease @@ -13,9 +13,6 @@ # make clean && make CXXFLAGS=-O2 MATCHCOMPILER=yes -j4 # ./cppcheck -D__CPPCHECK__ --std=c++11 --library=cppcheck-lib --enable=style --inconclusive --inline-suppr --suppress=bitwiseOnBoolean --suppress=shadowFunction --suppress=useStlAlgorithm --suppress=*:externals/picojson.h --suppress=functionConst --suppress=functionStatic --xml cli gui/*.cpp lib 2> selfcheck.xml # -# check --bug-hunting output: -# make clean && make -j4 USE_Z3=yes CXXFLAGS=-O2 MATCHCOMPILER=yes && ./cppcheck -D__CPPCHECK__ --bug-hunting --xml lib 2> bughunting.xml -# # Update translations # lupdate gui.pro # @@ -131,7 +128,7 @@ cp -R ~/cppcheck/cfg . cp -R ~/cppcheck/addons . cp -R ~/cppcheck/platforms . cd ~/cppcheck -make clean ; make -j4 FILESDIR=~/.cppcheck/$tag MATCHCOMPILER=yes USE_Z3=yes +make clean ; make -j4 FILESDIR=~/.cppcheck/$tag MATCHCOMPILER=yes mv cppcheck ~/.cppcheck/cppcheck-$tag git checkout main diff --git a/democlient/democlient.cpp b/democlient/democlient.cpp index bf38e1958..994c12a78 100644 --- a/democlient/democlient.cpp +++ b/democlient/democlient.cpp @@ -44,8 +44,6 @@ public: cppcheck.check("test.cpp", code); } - void bughuntingReport(const std::string&) override {} - void reportOut(const std::string &outmsg, Color c) override {} void reportErr(const ErrorMessage &msg) override { const std::string s = msg.toString(true); diff --git a/externals/z3-LICENSE b/externals/z3-LICENSE deleted file mode 100644 index cc90bed74..000000000 --- a/externals/z3-LICENSE +++ /dev/null @@ -1,10 +0,0 @@ -Z3 -Copyright (c) Microsoft Corporation -All rights reserved. -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/externals/z3_version_old.h b/externals/z3_version_old.h deleted file mode 100644 index 8459cd168..000000000 --- a/externals/z3_version_old.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef Z3_MAJOR_VERSION -#define Z3_MAJOR_VERSION 0 -#endif - -#ifndef Z3_MINOR_VERSION -#define Z3_MINOR_VERSION 0 -#endif - -#ifndef Z3_BUILD_NUMBER -#define Z3_BUILD_NUMBER 0 -#endif - diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index 6c0447d47..f67261bc6 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -32,9 +32,6 @@ if (BUILD_GUI) if (HAVE_RULES) target_link_libraries(cppcheck-gui ${PCRE_LIBRARY}) endif() - if (USE_Z3) - target_link_libraries(cppcheck-gui ${Z3_LIBRARIES}) - endif() if(tinyxml2_FOUND AND NOT USE_BUNDLED_TINYXML2) target_link_libraries(cppcheck-gui ${tinyxml2_LIBRARIES}) endif() diff --git a/gui/about.ui b/gui/about.ui index 56b66c1c4..3e3b1b380 100644 --- a/gui/about.ui +++ b/gui/about.ui @@ -112,13 +112,7 @@ of the GNU General Public License version 3 - <html><head/><body> -<p>Many thanks to these libraries that we use:</p><ul> -<li>pcre</li> -<li>picojson</li> -<li>qt</li> -<li>tinyxml2</li> -<li>z3</li></ul></body></html> + <html><head/><body><p>Many thanks to these libraries that we use:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">pcre</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">picojson</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">qt</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">tinyxml2</li></ul></body></html> diff --git a/gui/functioncontractdialog.cpp b/gui/functioncontractdialog.cpp deleted file mode 100644 index 0454e9cb9..000000000 --- a/gui/functioncontractdialog.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2022 Cppcheck team. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "functioncontractdialog.h" - -#include "ui_functioncontractdialog.h" - -static QString formatFunctionName(QString f) -{ - if (f.endsWith("()")) - return f; - f.replace("(", "(\n "); - f.replace(",", ",\n "); - return f; -} - -FunctionContractDialog::FunctionContractDialog(QWidget *parent, const QString &name, const QString &expects) : - QDialog(parent), - mUi(new Ui::FunctionContractDialog) -{ - mUi->setupUi(this); - mUi->functionName->setText(formatFunctionName(name)); - mUi->expects->setPlainText(expects); -} - -FunctionContractDialog::~FunctionContractDialog() -{ - delete mUi; -} - -QString FunctionContractDialog::getExpects() const -{ - return mUi->expects->toPlainText(); -} - diff --git a/gui/functioncontractdialog.h b/gui/functioncontractdialog.h deleted file mode 100644 index f67864d09..000000000 --- a/gui/functioncontractdialog.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2022 Cppcheck team. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef FUNCTIONCONTRACTDIALOG_H -#define FUNCTIONCONTRACTDIALOG_H - -#include - -namespace Ui { - class FunctionContractDialog; -} - -class FunctionContractDialog : public QDialog { - Q_OBJECT - -public: - explicit FunctionContractDialog(QWidget *parent, const QString &name, const QString &expects); - ~FunctionContractDialog() override; - QString getExpects() const; -private: - Ui::FunctionContractDialog *mUi; -}; - -#endif // FUNCTIONCONTRACTDIALOG_H diff --git a/gui/functioncontractdialog.ui b/gui/functioncontractdialog.ui deleted file mode 100644 index dac6a14d0..000000000 --- a/gui/functioncontractdialog.ui +++ /dev/null @@ -1,83 +0,0 @@ - - - FunctionContractDialog - - - - 0 - 0 - 640 - 401 - - - - Function contract - - - - - - Name - - - - - - - Requirements for parameters - - - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - buttonBox - accepted() - FunctionContractDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - FunctionContractDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/gui/gui.pro b/gui/gui.pro index f04127f6d..d8c8202a0 100644 --- a/gui/gui.pro +++ b/gui/gui.pro @@ -6,8 +6,7 @@ CONFIG += warn_on debug DEPENDPATH += . \ ../lib INCLUDEPATH += . \ - ../lib \ - ../externals/z3/include + ../lib QT += widgets QT += printsupport QT += help @@ -27,15 +26,7 @@ contains(LINKCORE, [yY][eE][sS]) { LIBS += -l../bin/cppcheck-core DEFINES += CPPCHECKLIB_IMPORT } -LIBS += -L$$PWD/../externals -L$$PWD/../externals/z3/bin - -# z3 -win32 { - LIBS += -llibz3 -} else { - LIBS += -lz3 -} -QMAKE_CXXFLAGS += -DUSE_Z3 +LIBS += -L$$PWD/../externals DESTDIR = . RCC_DIR = temp @@ -72,7 +63,6 @@ RESOURCES = gui.qrc FORMS = about.ui \ applicationdialog.ui \ fileview.ui \ - functioncontractdialog.ui \ helpdialog.ui \ mainwindow.ui \ projectfile.ui \ @@ -83,8 +73,7 @@ FORMS = about.ui \ librarydialog.ui \ libraryaddfunctiondialog.ui \ libraryeditargdialog.ui \ - newsuppressiondialog.ui \ - variablecontractsdialog.ui + newsuppressiondialog.ui TRANSLATIONS = cppcheck_de.ts \ cppcheck_es.ts \ @@ -136,7 +125,6 @@ HEADERS += aboutdialog.h \ erroritem.h \ filelist.h \ fileviewdialog.h \ - functioncontractdialog.h \ helpdialog.h \ mainwindow.h \ platforms.h \ @@ -154,7 +142,6 @@ HEADERS += aboutdialog.h \ threadresult.h \ translationhandler.h \ txtreport.h \ - variablecontractsdialog.h \ xmlreport.h \ xmlreportv2.h \ librarydialog.h \ @@ -178,7 +165,6 @@ SOURCES += aboutdialog.cpp \ erroritem.cpp \ filelist.cpp \ fileviewdialog.cpp \ - functioncontractdialog.cpp \ helpdialog.cpp \ main.cpp \ mainwindow.cpp\ @@ -197,7 +183,6 @@ SOURCES += aboutdialog.cpp \ threadresult.cpp \ translationhandler.cpp \ txtreport.cpp \ - variablecontractsdialog.cpp \ xmlreport.cpp \ xmlreportv2.cpp \ librarydialog.cpp \ diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 7696bc45c..837577343 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -24,7 +24,6 @@ #include "cppcheck.h" #include "filelist.h" #include "fileviewdialog.h" -#include "functioncontractdialog.h" #include "helpdialog.h" #include "librarydialog.h" #include "projectfile.h" @@ -37,7 +36,6 @@ #include "threadhandler.h" #include "threadresult.h" #include "translationhandler.h" -#include "variablecontractsdialog.h" #include "ui_mainwindow.h" @@ -143,15 +141,10 @@ MainWindow::MainWindow(TranslationHandler* th, QSettings* settings) : connect(mThread, &ThreadHandler::done, this, &MainWindow::analysisDone); connect(mThread, &ThreadHandler::log, mUI->mResults, &ResultsView::log); connect(mThread, &ThreadHandler::debugError, mUI->mResults, &ResultsView::debugError); - connect(mThread, &ThreadHandler::bughuntingReportLine, mUI->mResults, &ResultsView::bughuntingReportLine); connect(mUI->mResults, &ResultsView::gotResults, this, &MainWindow::resultsAdded); connect(mUI->mResults, &ResultsView::resultsHidden, mUI->mActionShowHidden, &QAction::setEnabled); connect(mUI->mResults, &ResultsView::checkSelected, this, &MainWindow::performSelectedFilesCheck); connect(mUI->mResults, &ResultsView::suppressIds, this, &MainWindow::suppressIds); - connect(mUI->mResults, &ResultsView::editFunctionContract, this, &MainWindow::editFunctionContract); - connect(mUI->mResults, &ResultsView::editVariableContract, this, &MainWindow::editVariableContract); - connect(mUI->mResults, &ResultsView::deleteFunctionContract, this, &MainWindow::deleteFunctionContract); - connect(mUI->mResults, &ResultsView::deleteVariableContract, this, &MainWindow::deleteVariableContract); connect(mUI->mMenuView, &QMenu::aboutToShow, this, &MainWindow::aboutToShowViewMenu); // File menu @@ -356,9 +349,6 @@ void MainWindow::loadSettings() QDir::setCurrent(inf.absolutePath()); } } - - updateFunctionContractsTab(); - updateVariableContractsTab(); } void MainWindow::saveSettings() const @@ -620,33 +610,6 @@ QStringList MainWindow::selectFilesToAnalyze(QFileDialog::FileMode mode) return selected; } -void MainWindow::updateFunctionContractsTab() -{ - QStringList addedContracts; - if (mProjectFile) { - for (const auto& it: mProjectFile->getFunctionContracts()) { - addedContracts << QString::fromStdString(it.first); - } - } - mUI->mResults->setAddedFunctionContracts(addedContracts); -} - -void MainWindow::updateVariableContractsTab() -{ - QStringList added; - if (mProjectFile) { - for (const auto &vc: mProjectFile->getVariableContracts()) { - QString line = vc.first; - if (!vc.second.minValue.empty()) - line += " min:" + QString::fromStdString(vc.second.minValue); - if (!vc.second.maxValue.empty()) - line += " max:" + QString::fromStdString(vc.second.maxValue); - added << line; - } - } - mUI->mResults->setAddedVariableContracts(added); -} - void MainWindow::analyzeFiles() { Settings::terminate(false); @@ -881,13 +844,6 @@ Settings MainWindow::getCppcheckSettings() } result.clang = mProjectFile->clangParser; - result.bugHunting = mProjectFile->bugHunting; - result.bugHuntingReport = " "; - - result.functionContracts = mProjectFile->getFunctionContracts(); - - for (const auto& vc: mProjectFile->getVariableContracts()) - result.variableContracts[vc.first.toStdString()] = vc.second; const QStringList undefines = mProjectFile->getUndefines(); for (const QString& undefine : undefines) @@ -1557,9 +1513,6 @@ void MainWindow::loadProjectFile(const QString &filePath) delete mProjectFile; mProjectFile = new ProjectFile(filePath, this); mProjectFile->setActiveProject(); - mUI->mResults->showContracts(mProjectFile->bugHunting); - updateFunctionContractsTab(); - updateVariableContractsTab(); if (!loadLastResults()) analyzeProject(mProjectFile); } @@ -1693,14 +1646,10 @@ void MainWindow::newProjectFile() ProjectFileDialog dlg(mProjectFile, this); if (dlg.exec() == QDialog::Accepted) { addProjectMRU(filepath); - mUI->mResults->showContracts(mProjectFile->bugHunting); analyzeProject(mProjectFile); } else { closeProjectFile(); } - - updateFunctionContractsTab(); - updateVariableContractsTab(); } void MainWindow::closeProjectFile() @@ -1708,8 +1657,6 @@ void MainWindow::closeProjectFile() delete mProjectFile; mProjectFile = nullptr; mUI->mResults->clear(true); - mUI->mResults->clearContracts(); - mUI->mResults->showContracts(false); enableProjectActions(false); enableProjectOpenActions(true); formatAndSetTitle(); @@ -1730,7 +1677,6 @@ void MainWindow::editProjectFile() ProjectFileDialog dlg(mProjectFile, this); if (dlg.exec() == QDialog::Accepted) { mProjectFile->write(); - mUI->mResults->showContracts(mProjectFile->bugHunting); analyzeProject(mProjectFile); } } @@ -1897,55 +1843,3 @@ void MainWindow::suppressIds(QStringList ids) mProjectFile->setSuppressions(suppressions); mProjectFile->write(); } - -void MainWindow::editFunctionContract(QString function) -{ - if (!mProjectFile) - return; - - QString expects; - const auto it = mProjectFile->getFunctionContracts().find(function.toStdString()); - if (it != mProjectFile->getFunctionContracts().end()) - expects = QString::fromStdString(it->second); - - FunctionContractDialog dlg(nullptr, - function, - expects); - - if (dlg.exec() == QDialog::Accepted) { - mProjectFile->setFunctionContract(function, dlg.getExpects()); - mProjectFile->write(); - } - - updateFunctionContractsTab(); -} - -void MainWindow::editVariableContract(QString var) -{ - if (!mProjectFile) - return; - - VariableContractsDialog dlg(nullptr, var); - if (dlg.exec() == QDialog::Accepted) { - mProjectFile->setVariableContracts(dlg.getVarname(), dlg.getMin(), dlg.getMax()); - mProjectFile->write(); - } - - updateVariableContractsTab(); -} - -void MainWindow::deleteFunctionContract(const QString& function) -{ - if (mProjectFile) { - mProjectFile->deleteFunctionContract(function); - mProjectFile->write(); - } -} - -void MainWindow::deleteVariableContract(const QString& var) -{ - if (mProjectFile) { - mProjectFile->deleteVariableContract(var); - mProjectFile->write(); - } -} diff --git a/gui/mainwindow.h b/gui/mainwindow.h index de83d9e99..394d0a734 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -38,7 +38,7 @@ class QTimer; class QLineEdit; namespace Ui { class MainWindow; -}; +} /// @addtogroup GUI /// @{ @@ -75,13 +75,6 @@ public: void analyzeCode(const QString& code, const QString& filename); public slots: - - /** Update "Functions" tab */ - void updateFunctionContractsTab(); - - /** Update "Variables" tab */ - void updateVariableContractsTab(); - /** @brief Slot for analyze files menu item */ void analyzeFiles(); @@ -231,18 +224,6 @@ protected slots: /** Suppress error ids */ void suppressIds(QStringList ids); - /** Edit contract for function */ - void editFunctionContract(QString function); - - /** Edit constraints for variable */ - void editVariableContract(QString var); - - /** Delete contract for function */ - void deleteFunctionContract(const QString& function); - - /** Edit constraints for variable */ - void deleteVariableContract(const QString& var); - private: /** Get filename for last results */ diff --git a/gui/newsuppressiondialog.cpp b/gui/newsuppressiondialog.cpp index 67227df01..246d1df22 100644 --- a/gui/newsuppressiondialog.cpp +++ b/gui/newsuppressiondialog.cpp @@ -37,7 +37,6 @@ NewSuppressionDialog::NewSuppressionDialog(QWidget *parent) : void reportErr(const ErrorMessage &msg) override { errorIds << QString::fromStdString(msg.id); } - void bughuntingReport(const std::string & /*str*/) override {} QStringList errorIds; }; diff --git a/gui/projectfile.cpp b/gui/projectfile.cpp index a1031ea9c..b3e24f8be 100644 --- a/gui/projectfile.cpp +++ b/gui/projectfile.cpp @@ -46,7 +46,6 @@ void ProjectFile::clear() { const Settings settings; clangParser = false; - bugHunting = false; mRootPath.clear(); mBuildDir.clear(); mImportProject.clear(); @@ -56,8 +55,6 @@ void ProjectFile::clear() mUndefines.clear(); mPaths.clear(); mExcludedPaths.clear(); - mFunctionContracts.clear(); - mVariableContracts.clear(); mLibraries.clear(); mPlatform.clear(); mSuppressions.clear(); @@ -121,9 +118,6 @@ bool ProjectFile::read(const QString &filename) if (xmlReader.name() == QString(CppcheckXml::Parser)) clangParser = true; - if (xmlReader.name() == QString(CppcheckXml::BugHunting)) - bugHunting = true; - if (xmlReader.name() == QString(CppcheckXml::CheckHeadersElementName)) mCheckHeaders = readBool(xmlReader); @@ -151,14 +145,6 @@ bool ProjectFile::read(const QString &filename) if (xmlReader.name() == QString(CppcheckXml::IgnoreElementName)) readExcludes(xmlReader); - // Function contracts - if (xmlReader.name() == QString(CppcheckXml::FunctionContracts)) - readFunctionContracts(xmlReader); - - // Variable constraints - if (xmlReader.name() == QString(CppcheckXml::VariableContractsElementName)) - readVariableContracts(xmlReader); - // Find libraries list from inside project element if (xmlReader.name() == QString(CppcheckXml::LibrariesElementName)) readStringList(mLibraries, xmlReader, CppcheckXml::LibraryElementName); @@ -501,79 +487,6 @@ void ProjectFile::readExcludes(QXmlStreamReader &reader) } while (!allRead); } -void ProjectFile::readFunctionContracts(QXmlStreamReader &reader) -{ - QXmlStreamReader::TokenType type; - bool allRead = false; - do { - type = reader.readNext(); - switch (type) { - case QXmlStreamReader::StartElement: - if (reader.name().toString() == CppcheckXml::FunctionContract) { - QXmlStreamAttributes attribs = reader.attributes(); - QString function = attribs.value(QString(), CppcheckXml::ContractFunction).toString(); - QString expects = attribs.value(QString(), CppcheckXml::ContractExpects).toString(); - if (!function.isEmpty() && !expects.isEmpty()) - mFunctionContracts[function.toStdString()] = expects.toStdString(); - } - break; - - case QXmlStreamReader::EndElement: - if (reader.name().toString() == CppcheckXml::FunctionContracts) - allRead = true; - break; - - // Not handled - case QXmlStreamReader::NoToken: - case QXmlStreamReader::Invalid: - case QXmlStreamReader::StartDocument: - case QXmlStreamReader::EndDocument: - case QXmlStreamReader::Characters: - case QXmlStreamReader::Comment: - case QXmlStreamReader::DTD: - case QXmlStreamReader::EntityReference: - case QXmlStreamReader::ProcessingInstruction: - break; - } - } while (!allRead); -} - -void ProjectFile::readVariableContracts(QXmlStreamReader &reader) -{ - QXmlStreamReader::TokenType type; - while (true) { - type = reader.readNext(); - switch (type) { - case QXmlStreamReader::StartElement: - if (reader.name().toString() == CppcheckXml::VariableContractItemElementName) { - QXmlStreamAttributes attribs = reader.attributes(); - QString varname = attribs.value(QString(), CppcheckXml::VariableContractVarName).toString(); - QString minValue = attribs.value(QString(), CppcheckXml::VariableContractMin).toString(); - QString maxValue = attribs.value(QString(), CppcheckXml::VariableContractMax).toString(); - setVariableContracts(varname, minValue, maxValue); - } - break; - - case QXmlStreamReader::EndElement: - if (reader.name().toString() == CppcheckXml::VariableContractsElementName) - return; - break; - - // Not handled - case QXmlStreamReader::NoToken: - case QXmlStreamReader::Invalid: - case QXmlStreamReader::StartDocument: - case QXmlStreamReader::EndDocument: - case QXmlStreamReader::Characters: - case QXmlStreamReader::Comment: - case QXmlStreamReader::DTD: - case QXmlStreamReader::EntityReference: - case QXmlStreamReader::ProcessingInstruction: - break; - } - } -} - void ProjectFile::readVsConfigurations(QXmlStreamReader &reader) { QXmlStreamReader::TokenType type; @@ -788,11 +701,6 @@ void ProjectFile::setLibraries(const QStringList &libraries) mLibraries = libraries; } -void ProjectFile::setFunctionContract(const QString& function, const QString& expects) -{ - mFunctionContracts[function.toStdString()] = expects.toStdString(); -} - void ProjectFile::setPlatform(const QString &platform) { mPlatform = platform; @@ -881,11 +789,6 @@ bool ProjectFile::write(const QString &filename) xmlWriter.writeEndElement(); } - if (bugHunting) { - xmlWriter.writeStartElement(CppcheckXml::BugHunting); - xmlWriter.writeEndElement(); - } - xmlWriter.writeStartElement(CppcheckXml::CheckHeadersElementName); xmlWriter.writeCharacters(mCheckHeaders ? "true" : "false"); xmlWriter.writeEndElement(); @@ -959,31 +862,6 @@ bool ProjectFile::write(const QString &filename) CppcheckXml::LibrariesElementName, CppcheckXml::LibraryElementName); - if (!mFunctionContracts.empty()) { - xmlWriter.writeStartElement(CppcheckXml::FunctionContracts); - for (const auto& contract: mFunctionContracts) { - xmlWriter.writeStartElement(CppcheckXml::FunctionContract); - xmlWriter.writeAttribute(CppcheckXml::ContractFunction, QString::fromStdString(contract.first)); - xmlWriter.writeAttribute(CppcheckXml::ContractExpects, QString::fromStdString(contract.second)); - xmlWriter.writeEndElement(); - } - xmlWriter.writeEndElement(); - } - - if (!mVariableContracts.empty()) { - xmlWriter.writeStartElement(CppcheckXml::VariableContractsElementName); - - for (const auto &vc: mVariableContracts) { - xmlWriter.writeStartElement(CppcheckXml::VariableContractItemElementName); - xmlWriter.writeAttribute(CppcheckXml::VariableContractVarName, vc.first); - xmlWriter.writeAttribute(CppcheckXml::VariableContractMin, QString::fromStdString(vc.second.minValue)); - xmlWriter.writeAttribute(CppcheckXml::VariableContractMax, QString::fromStdString(vc.second.maxValue)); - xmlWriter.writeEndElement(); - } - - xmlWriter.writeEndElement(); - } - if (!mSuppressions.isEmpty()) { xmlWriter.writeStartElement(CppcheckXml::SuppressionsElementName); for (const Suppressions::Suppression &suppression : mSuppressions) { diff --git a/gui/projectfile.h b/gui/projectfile.h index 5d14d8e62..9c33e268c 100644 --- a/gui/projectfile.h +++ b/gui/projectfile.h @@ -228,26 +228,6 @@ public: mMaxTemplateRecursion = maxTemplateRecursion; } - const std::map& getFunctionContracts() const { - return mFunctionContracts; - } - - const std::map& getVariableContracts() const { - return mVariableContracts; - } - - void setVariableContracts(QString var, const QString& min, const QString& max) { - mVariableContracts[var] = Settings::VariableContracts{min.toStdString(), max.toStdString()}; - } - - void deleteFunctionContract(const QString& function) { - mFunctionContracts.erase(function.toStdString()); - } - - void deleteVariableContract(const QString& var) { - mVariableContracts.erase(var); - } - /** * @brief Get filename for the project file. * @return file name. @@ -312,9 +292,6 @@ public: */ void setLibraries(const QStringList &libraries); - /** Set contract for a function */ - void setFunctionContract(const QString& function, const QString& expects); - /** * @brief Set platform. * @param platform platform. @@ -391,8 +368,6 @@ public: /** Use Clang parser */ bool clangParser; - /** Bug hunting */ - bool bugHunting; protected: /** @@ -437,18 +412,6 @@ protected: */ void readExcludes(QXmlStreamReader &reader); - /** - * @brief Read function contracts. - * @param reader XML stream reader. - */ - void readFunctionContracts(QXmlStreamReader &reader); - - /** - * @brief Read variable constraints. - * @param reader XML stream reader. - */ - void readVariableContracts(QXmlStreamReader &reader); - /** * @brief Read lists of Visual Studio configurations * @param reader XML stream reader. @@ -564,10 +527,6 @@ private: */ QStringList mLibraries; - std::map mFunctionContracts; - - std::map mVariableContracts; - /** * @brief Platform */ diff --git a/gui/projectfile.ui b/gui/projectfile.ui index 99c475610..f35f54daa 100644 --- a/gui/projectfile.ui +++ b/gui/projectfile.ui @@ -458,23 +458,6 @@ Analysis - - - - Normal analysis -- Avoid false positives. - - - true - - - - - - - Bug hunting -- Generates mostly noise. The goal is to be "soundy" and detect most bugs. - - - diff --git a/gui/projectfiledialog.cpp b/gui/projectfiledialog.cpp index cd7ef5ccc..ea5769d6b 100644 --- a/gui/projectfiledialog.cpp +++ b/gui/projectfiledialog.cpp @@ -210,7 +210,6 @@ ProjectFileDialog::ProjectFileDialog(ProjectFile *projectFile, QWidget *parent) connect(mUI->mListSuppressions, &QListWidget::doubleClicked, this, &ProjectFileDialog::editSuppression); connect(mUI->mBtnBrowseMisraFile, &QPushButton::clicked, this, &ProjectFileDialog::browseMisraFile); connect(mUI->mChkAllVsConfigs, &QCheckBox::clicked, this, &ProjectFileDialog::checkAllVSConfigs); - connect(mUI->mBtnNormalAnalysis, &QCheckBox::toggled, mUI->mBtnSafeClasses, &QCheckBox::setEnabled); loadFromProjectFile(projectFile); } @@ -282,7 +281,6 @@ void ProjectFileDialog::loadFromProjectFile(const ProjectFile *projectFile) else mUI->mBtnCppcheckParser->setChecked(true); mUI->mBtnSafeClasses->setChecked(projectFile->safeChecks.classes); - mUI->mBtnBugHunting->setChecked(projectFile->bugHunting); setExcludedPaths(projectFile->getExcludedPaths()); setLibraries(projectFile->getLibraries()); const QString platform = projectFile->getPlatform(); @@ -376,7 +374,6 @@ void ProjectFileDialog::saveToProjectFile(ProjectFile *projectFile) const projectFile->setLibraries(getLibraries()); projectFile->clangParser = mUI->mBtnClangParser->isChecked(); projectFile->safeChecks.classes = mUI->mBtnSafeClasses->isChecked(); - projectFile->bugHunting = mUI->mBtnBugHunting->isChecked(); if (mUI->mComboBoxPlatform->currentText().endsWith(".xml")) projectFile->setPlatform(mUI->mComboBoxPlatform->currentText()); else { diff --git a/gui/resultstree.cpp b/gui/resultstree.cpp index a1447aa0d..7de443754 100644 --- a/gui/resultstree.cpp +++ b/gui/resultstree.cpp @@ -645,15 +645,6 @@ void ResultsTree::contextMenuEvent(QContextMenuEvent * e) menu.addSeparator(); } - const bool bughunting = !multipleSelection && mContextItem->data().toMap().value("id").toString().startsWith("bughunting"); - - if (bughunting && !getFunction(mContextItem).isEmpty()) { - QAction *editContract = new QAction(tr("Edit contract.."), &menu); - connect(editContract, &QAction::triggered, this, &ResultsTree::editContract); - menu.addAction(editContract); - menu.addSeparator(); - } - //Create an action for the application QAction *recheckSelectedFiles = new QAction(tr("Recheck"), &menu); QAction *copy = new QAction(tr("Copy"), &menu); @@ -677,15 +668,10 @@ void ResultsTree::contextMenuEvent(QContextMenuEvent * e) menu.addAction(hide); menu.addAction(hideallid); - if (!bughunting) { - QAction *suppress = new QAction(tr("Suppress selected id(s)"), &menu); - menu.addAction(suppress); - connect(suppress, &QAction::triggered, this, &ResultsTree::suppressSelectedIds); - } else { - QAction *suppress = new QAction(tr("Suppress"), &menu); - menu.addAction(suppress); - connect(suppress, &QAction::triggered, this, &ResultsTree::suppressHash); - } + QAction *suppress = new QAction(tr("Suppress selected id(s)"), &menu); + menu.addAction(suppress); + connect(suppress, &QAction::triggered, this, &ResultsTree::suppressSelectedIds); + menu.addSeparator(); menu.addAction(opencontainingfolder); @@ -1107,11 +1093,6 @@ void ResultsTree::openContainingFolder() } } -void ResultsTree::editContract() -{ - emit editFunctionContract(getFunction(mContextItem)); -} - void ResultsTree::tagSelectedItems(const QString &tag) { if (!mSelectionModel) diff --git a/gui/resultstree.h b/gui/resultstree.h index 75cc122d0..dfd0c50b1 100644 --- a/gui/resultstree.h +++ b/gui/resultstree.h @@ -205,8 +205,6 @@ signals: /** Suppress Ids */ void suppressIds(QStringList ids); - /** Edit contract for function */ - void editFunctionContract(QString function); public slots: /** @@ -284,11 +282,6 @@ protected slots: */ void openContainingFolder(); - /** - * @brief Allow user to edit contract to fix bughunting warning - */ - void editContract(); - /** * @brief Slot for selection change in the results tree. * diff --git a/gui/resultsview.cpp b/gui/resultsview.cpp index c4b8d2e0d..bca3ecc5a 100644 --- a/gui/resultsview.cpp +++ b/gui/resultsview.cpp @@ -55,7 +55,6 @@ ResultsView::ResultsView(QWidget * parent) : connect(mUI->mTree, &ResultsTree::checkSelected, this, &ResultsView::checkSelected); connect(mUI->mTree, &ResultsTree::treeSelectionChanged, this, &ResultsView::updateDetails); connect(mUI->mTree, &ResultsTree::suppressIds, this, &ResultsView::suppressIds); - connect(mUI->mTree, &ResultsTree::editFunctionContract, this, &ResultsView::editFunctionContract); connect(this, &ResultsView::showResults, mUI->mTree, &ResultsTree::showResults); connect(this, &ResultsView::showCppcheckResults, mUI->mTree, &ResultsTree::showCppcheckResults); connect(this, &ResultsView::showClangResults, mUI->mTree, &ResultsTree::showClangResults); @@ -63,21 +62,7 @@ ResultsView::ResultsView(QWidget * parent) : connect(this, &ResultsView::expandAllResults, mUI->mTree, &ResultsTree::expandAll); connect(this, &ResultsView::showHiddenResults, mUI->mTree, &ResultsTree::showHiddenResults); - // Function contracts - connect(mUI->mListAddedContracts, &QListWidget::itemDoubleClicked, this, &ResultsView::contractDoubleClicked); - connect(mUI->mListMissingContracts, &QListWidget::itemDoubleClicked, this, &ResultsView::contractDoubleClicked); - mUI->mListAddedContracts->installEventFilter(this); - - // Variable contracts - connect(mUI->mListAddedVariables, &QListWidget::itemDoubleClicked, this, &ResultsView::variableDoubleClicked); - connect(mUI->mListMissingVariables, &QListWidget::itemDoubleClicked, this, &ResultsView::variableDoubleClicked); - connect(mUI->mEditVariablesFilter, &QLineEdit::textChanged, this, &ResultsView::editVariablesFilter); - mUI->mListAddedVariables->installEventFilter(this); - mUI->mListLog->setContextMenuPolicy(Qt::CustomContextMenu); - - mUI->mListAddedContracts->setSortingEnabled(true); - mUI->mListMissingContracts->setSortingEnabled(true); } void ResultsView::initialize(QSettings *settings, ApplicationList *list, ThreadHandler *checkThreadHandler) @@ -100,28 +85,6 @@ ResultsView::~ResultsView() delete mUI; } -void ResultsView::setAddedFunctionContracts(const QStringList &addedContracts) -{ - mUI->mListAddedContracts->clear(); - mUI->mListAddedContracts->addItems(addedContracts); - for (const QString& f: addedContracts) { - auto res = mUI->mListMissingContracts->findItems(f, Qt::MatchExactly); - if (!res.empty()) - delete res.front(); - } -} - -void ResultsView::setAddedVariableContracts(const QStringList &added) -{ - mUI->mListAddedVariables->clear(); - mUI->mListAddedVariables->addItems(added); - for (const QString& var: added) { - for (auto *item: mUI->mListMissingVariables->findItems(var, Qt::MatchExactly)) - delete item; - mVariableContracts.insert(var); - } -} - void ResultsView::clear(bool results) { if (results) { @@ -148,27 +111,11 @@ void ResultsView::clearRecheckFile(const QString &filename) mUI->mTree->clearRecheckFile(filename); } -void ResultsView::clearContracts() -{ - mUI->mListAddedContracts->clear(); - mUI->mListAddedVariables->clear(); - mUI->mListMissingContracts->clear(); - mUI->mListMissingVariables->clear(); - mFunctionContracts.clear(); - mVariableContracts.clear(); -} - ShowTypes * ResultsView::getShowTypes() const { return &mUI->mTree->mShowSeverities; } -void ResultsView::showContracts(bool visible) -{ - mUI->mTabFunctionContracts->setVisible(visible); - mUI->mTabVariableContracts->setVisible(visible); -} - void ResultsView::progress(int value, const QString& description) { mUI->mProgress->setValue(value); @@ -497,25 +444,6 @@ void ResultsView::debugError(const ErrorItem &item) mUI->mListLog->addItem(item.toString()); } -void ResultsView::bughuntingReportLine(const QString& line) -{ - for (const QString& s: line.split("\n")) { - if (s.startsWith("[intvar] ")) { - const QString varname = s.mid(9); - if (!mVariableContracts.contains(varname)) { - mVariableContracts.insert(varname); - mUI->mListMissingVariables->addItem(varname); - } - } else if (s.startsWith("[missing contract] ")) { - const QString functionName = s.mid(19); - if (!mFunctionContracts.contains(functionName)) { - mFunctionContracts.insert(functionName); - mUI->mListMissingContracts->addItem(functionName); - } - } - } -} - void ResultsView::logClear() { mUI->mListLog->clear(); @@ -543,34 +471,6 @@ void ResultsView::logCopyComplete() clipboard->setText(logText); } -void ResultsView::contractDoubleClicked(QListWidgetItem* item) -{ - emit editFunctionContract(item->text()); -} - -void ResultsView::variableDoubleClicked(QListWidgetItem* item) -{ - emit editVariableContract(item->text()); -} - -void ResultsView::editVariablesFilter(const QString &text) -{ -#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) - for (auto *item: mUI->mListAddedVariables->findItems(".*", Qt::MatchRegularExpression)) { -#else - for (auto *item: mUI->mListAddedVariables->findItems(".*", Qt::MatchRegExp)) { -#endif - QString varname = item->text().mid(0, item->text().indexOf(" ")); - item->setHidden(!varname.contains(text)); - } -#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) - for (auto *item: mUI->mListMissingVariables->findItems(".*", Qt::MatchRegularExpression)) -#else - for (auto *item: mUI->mListMissingVariables->findItems(".*", Qt::MatchRegExp)) -#endif - item->setHidden(!item->text().contains(text)); -} - void ResultsView::on_mListLog_customContextMenuRequested(const QPoint &pos) { if (mUI->mListLog->count() <= 0) @@ -585,32 +485,3 @@ void ResultsView::on_mListLog_customContextMenuRequested(const QPoint &pos) contextMenu.exec(globalPos); } - -bool ResultsView::eventFilter(QObject *target, QEvent *event) -{ - if (event->type() == QEvent::KeyPress) { - if (target == mUI->mListAddedVariables) { - QKeyEvent *keyEvent = static_cast(event); - if (keyEvent->key() == Qt::Key_Delete) { - for (auto *i: mUI->mListAddedVariables->selectedItems()) { - emit deleteVariableContract(i->text().mid(0, i->text().indexOf(" "))); - delete i; - } - return true; - } - } - - if (target == mUI->mListAddedContracts) { - QKeyEvent *keyEvent = static_cast(event); - if (keyEvent->key() == Qt::Key_Delete) { - for (auto *i: mUI->mListAddedContracts->selectedItems()) { - emit deleteFunctionContract(i->text()); - delete i; - } - - return true; - } - } - } - return QObject::eventFilter(target, event); -} diff --git a/gui/resultsview.h b/gui/resultsview.h index e7febdc6c..dbe894854 100644 --- a/gui/resultsview.h +++ b/gui/resultsview.h @@ -56,9 +56,6 @@ public: ~ResultsView() override; ResultsView &operator=(const ResultsView &) = delete; - void setAddedFunctionContracts(const QStringList &addedContracts); - void setAddedVariableContracts(const QStringList &added); - /** * @brief Clear results and statistics and reset progressinfo. * @param results Remove all the results from view? @@ -75,9 +72,6 @@ public: */ void clearRecheckFile(const QString &filename); - /** Clear the contracts */ - void clearContracts(); - /** * @brief Write statistics in file * @@ -204,9 +198,6 @@ public: */ ShowTypes * getShowTypes() const; - /** Show/hide the contract tabs */ - void showContracts(bool visible); - signals: /** @@ -232,18 +223,6 @@ signals: /** Suppress Ids */ void suppressIds(QStringList ids); - /** Edit contract for function */ - void editFunctionContract(QString function); - - /** Delete contract for function */ - void deleteFunctionContract(QString function); - - /** Edit contract for variable */ - void editVariableContract(QString var); - - /** Delete variable contract */ - void deleteVariableContract(QString var); - /** * @brief Show/hide certain type of errors * Refreshes the tree. @@ -339,11 +318,6 @@ public slots: */ void debugError(const ErrorItem &item); - /** - * \brief bughunting report line - */ - void bughuntingReportLine(const QString& line); - /** * \brief Clear log messages */ @@ -359,14 +333,6 @@ public slots: */ void logCopyComplete(); - /** \brief Contract was double clicked => edit it */ - void contractDoubleClicked(QListWidgetItem* item); - - /** \brief Variable was double clicked => edit it */ - void variableDoubleClicked(QListWidgetItem* item); - - void editVariablesFilter(const QString &text); - protected: /** * @brief Should we show a "No errors found dialog" every time no errors were found? @@ -377,16 +343,12 @@ protected: CheckStatistics *mStatistics; - bool eventFilter(QObject *target, QEvent *event) override; private slots: /** * @brief Custom context menu for Analysis Log * @param pos Mouse click position */ void on_mListLog_customContextMenuRequested(const QPoint &pos); -private: - QSet mFunctionContracts; - QSet mVariableContracts; }; /// @} #endif // RESULTSVIEW_H diff --git a/gui/resultsview.ui b/gui/resultsview.ui index 92f15e461..9e22e561e 100644 --- a/gui/resultsview.ui +++ b/gui/resultsview.ui @@ -153,109 +153,6 @@ - - - Functions - - - - - - Configured contracts: - - - - - - - QAbstractItemView::NoEditTriggers - - - - - - - Missing contracts: - - - - - - - QAbstractItemView::NoEditTriggers - - - true - - - - - - - - Variables - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Only show variable names that contain text: - - - - - - - - - - - - Configured contracts: - - - - - - - QAbstractItemView::NoEditTriggers - - - - - - - Missing contracts: - - - - - - - QAbstractItemView::NoEditTriggers - - - true - - - - - diff --git a/gui/test/benchmark/simple/CMakeLists.txt b/gui/test/benchmark/simple/CMakeLists.txt index 2d7b716bc..caf20d2be 100644 --- a/gui/test/benchmark/simple/CMakeLists.txt +++ b/gui/test/benchmark/simple/CMakeLists.txt @@ -16,9 +16,6 @@ target_link_libraries(benchmark-simple ${QT_CORE_LIB} ${QT_TEST_LIB}) if (HAVE_RULES) target_link_libraries(benchmark-simple ${PCRE_LIBRARY}) endif() -if (USE_Z3) - target_link_libraries(benchmark-simple ${Z3_LIBRARIES}) -endif() if(tinyxml2_FOUND AND NOT USE_BUNDLED_TINYXML2) target_link_libraries(benchmark-simple ${tinyxml2_LIBRARIES}) endif() diff --git a/gui/test/benchmark/simple/benchmarksimple.h b/gui/test/benchmark/simple/benchmarksimple.h index ec5ca9974..4a9ae325f 100644 --- a/gui/test/benchmark/simple/benchmarksimple.h +++ b/gui/test/benchmark/simple/benchmarksimple.h @@ -33,5 +33,4 @@ private: // We don't care about the output in the benchmark tests. void reportOut(const std::string & /*outmsg*/, Color /*c*/ = Color::Reset) override {} void reportErr(const ErrorMessage & /*msg*/) override {} - void bughuntingReport(const std::string & /*str*/) override {} }; diff --git a/gui/test/xmlreportv2/CMakeLists.txt b/gui/test/xmlreportv2/CMakeLists.txt index 028e61059..39deb074e 100644 --- a/gui/test/xmlreportv2/CMakeLists.txt +++ b/gui/test/xmlreportv2/CMakeLists.txt @@ -20,9 +20,6 @@ target_link_libraries(test-xmlreportv2 ${QT_CORE_LIB} ${QT_TEST_LIB}) if (HAVE_RULES) target_link_libraries(test-xmlreportv2 ${PCRE_LIBRARY}) endif() -if (USE_Z3) - target_link_libraries(test-xmlreportv2 ${Z3_LIBRARIES}) -endif() if(tinyxml2_FOUND AND NOT USE_BUNDLED_TINYXML2) target_link_libraries(test-xmlreportv2 ${tinyxml2_LIBRARIES}) endif() diff --git a/gui/threadhandler.cpp b/gui/threadhandler.cpp index ff5bd32cb..8fe716a8b 100644 --- a/gui/threadhandler.cpp +++ b/gui/threadhandler.cpp @@ -200,9 +200,6 @@ void ThreadHandler::initialize(ResultsView *view) connect(&mResults, &ThreadResult::debugError, this, &ThreadHandler::debugError); - - connect(&mResults, &ThreadResult::bughuntingReportLine, - this, &ThreadHandler::bughuntingReportLine); } void ThreadHandler::loadSettings(const QSettings &settings) diff --git a/gui/threadhandler.h b/gui/threadhandler.h index 95b4591e9..158f4f365 100644 --- a/gui/threadhandler.h +++ b/gui/threadhandler.h @@ -187,8 +187,6 @@ signals: void debugError(const ErrorItem &item); - void bughuntingReportLine(QString line); - public slots: /** diff --git a/gui/threadresult.cpp b/gui/threadresult.cpp index 2d43a5003..e759ab6e4 100644 --- a/gui/threadresult.cpp +++ b/gui/threadresult.cpp @@ -134,10 +134,3 @@ int ThreadResult::getFileCount() const QMutexLocker locker(&mutex); return mFiles.size() + mFileSettings.size(); } - -void ThreadResult::bughuntingReport(const std::string &str) -{ - if (str.empty()) - return; - emit bughuntingReportLine(QString::fromStdString(str)); -} diff --git a/gui/threadresult.h b/gui/threadresult.h index 79e3557f0..0e38a1610 100644 --- a/gui/threadresult.h +++ b/gui/threadresult.h @@ -76,7 +76,6 @@ public: */ void reportOut(const std::string &outmsg, Color c = Color::Reset) override; void reportErr(const ErrorMessage &msg) override; - void bughuntingReport(const std::string &str) override; public slots: @@ -114,9 +113,6 @@ signals: */ void debugError(const ErrorItem &item); - /** @brief bug hunting report */ - void bughuntingReportLine(QString line); - protected: /** diff --git a/gui/variablecontractsdialog.cpp b/gui/variablecontractsdialog.cpp deleted file mode 100644 index 8bbfb7089..000000000 --- a/gui/variablecontractsdialog.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2022 Cppcheck team. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "variablecontractsdialog.h" - -#include "ui_variablecontractsdialog.h" - -#include -#include - -VariableContractsDialog::VariableContractsDialog(QWidget *parent, QString var) : - QDialog(parent), - mUI(new Ui::VariableContractsDialog) -{ - mUI->setupUi(this); - - mVarName = var.indexOf(" ") < 0 ? var : var.mid(0, var.indexOf(" ")); - - this->setWindowTitle(mVarName); - - auto getMinMax = [](const QString& var, const QString& minmax) { - if (var.indexOf(" " + minmax + ":") < 0) - return QString(); - int pos1 = var.indexOf(" " + minmax + ":") + 2 + minmax.length(); - int pos2 = var.indexOf(" ", pos1); - if (pos2 < 0) - return var.mid(pos1); - return var.mid(pos1, pos2-pos1); - }; - - mUI->mMinValue->setText(getMinMax(var, "min")); - mUI->mMaxValue->setText(getMinMax(var, "max")); - - mUI->mMinValue->setValidator(new QRegularExpressionValidator(QRegularExpression("-?[0-9]*"))); - mUI->mMaxValue->setValidator(new QRegularExpressionValidator(QRegularExpression("-?[0-9]*"))); -} - -VariableContractsDialog::~VariableContractsDialog() -{ - delete mUI; -} - -QString VariableContractsDialog::getVarname() const -{ - return mVarName; -} -QString VariableContractsDialog::getMin() const -{ - return mUI->mMinValue->text(); -} -QString VariableContractsDialog::getMax() const -{ - return mUI->mMaxValue->text(); -} diff --git a/gui/variablecontractsdialog.h b/gui/variablecontractsdialog.h deleted file mode 100644 index 419caaef6..000000000 --- a/gui/variablecontractsdialog.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2022 Cppcheck team. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef VARIABLECONSTRAINTSDIALOG_H -#define VARIABLECONSTRAINTSDIALOG_H - -#include - -namespace Ui { - class VariableContractsDialog; -} - -class VariableContractsDialog : public QDialog { - Q_OBJECT - -public: - explicit VariableContractsDialog(QWidget *parent, QString var); - ~VariableContractsDialog() override; - - QString getVarname() const; - QString getMin() const; - QString getMax() const; - -private: - Ui::VariableContractsDialog *mUI; - QString mVarName; -}; - -#endif // VARIABLECONSTRAINTSDIALOG_H diff --git a/gui/variablecontractsdialog.ui b/gui/variablecontractsdialog.ui deleted file mode 100644 index 48a5642b7..000000000 --- a/gui/variablecontractsdialog.ui +++ /dev/null @@ -1,108 +0,0 @@ - - - VariableContractsDialog - - - - 0 - 0 - 400 - 172 - - - - Dialog - - - - - - You can specify min and max value for the variable here - - - - - - - - - Min - - - - - - - - - - Max - - - - - - - - - - - - Qt::Vertical - - - - 20 - 25 - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - buttonBox - accepted() - VariableContractsDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - VariableContractsDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 079b4871f..360844298 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -42,9 +42,6 @@ target_include_directories(lib_objs SYSTEM PRIVATE ${PROJECT_SOURCE_DIR}/externa if (HAVE_RULES) target_include_directories(lib_objs SYSTEM PRIVATE ${PCRE_INCLUDE}) endif() -if (USE_Z3) - target_include_directories(lib_objs SYSTEM PRIVATE ${Z3_CXX_INCLUDE_DIRS}) -endif() if (Boost_FOUND) target_include_directories(lib_objs SYSTEM PRIVATE ${Boost_INCLUDE_DIRS}) endif() diff --git a/lib/bughuntingchecks.cpp b/lib/bughuntingchecks.cpp deleted file mode 100644 index 6102f28e8..000000000 --- a/lib/bughuntingchecks.cpp +++ /dev/null @@ -1,719 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2022 Cppcheck team. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "bughuntingchecks.h" - -#include "astutils.h" -#include "errorlogger.h" -#include "errortypes.h" -#include "library.h" -#include "mathlib.h" -#include "settings.h" -#include "symboldatabase.h" -#include "token.h" -#include "utils.h" -#include "valueflow.h" - -#include -#include -#include -#include -#include -#include -#include - -static const CWE CWE_BUFFER_UNDERRUN(786U); // Access of Memory Location Before Start of Buffer -static const CWE CWE_BUFFER_OVERRUN(788U); // Access of Memory Location After End of Buffer - - -static float getKnownFloatValue(const Token *tok, float def) -{ - for (const auto &value: tok->values()) { - if (value.isKnown() && value.valueType == ValueFlow::Value::ValueType::FLOAT) - return value.floatValue; - } - return def; -} - -static bool isLessThan(ExprEngine::DataBase *dataBase, ExprEngine::ValuePtr lhs, ExprEngine::ValuePtr rhs) -{ - return ExprEngine::BinOpResult("<", lhs, rhs).isTrue(dataBase); -} - -static void arrayIndex(const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase) -{ - if (!Token::simpleMatch(tok->astParent(), "[")) - return; - int nr = 0; - const Token *buf = tok->astParent()->astOperand1(); - while (Token::simpleMatch(buf, "[")) { - ++nr; - buf = buf->astOperand1(); - } - if (!buf || !buf->variable() || !buf->variable()->isArray() || buf == buf->variable()->nameToken()) - // TODO - return; - const Token *index = tok->astParent()->astOperand2(); - if (tok != index) - // TODO - return; - if (buf->variable()->dimensions().size() > nr && buf->variable()->dimensions()[nr].known) { - const MathLib::bigint bufSize = buf->variable()->dimensions()[nr].num; - if (value.isGreaterThan(dataBase, bufSize - 1)) { - const bool bailout = (value.type == ExprEngine::ValueType::BailoutValue); - dataBase->reportError(tok, - Severity::SeverityType::error, - "bughuntingArrayIndexOutOfBounds", - "Array index out of bounds, cannot determine that " + index->expressionString() + " is less than " + std::to_string(bufSize), - CWE_BUFFER_OVERRUN, - false, - bailout); - } - } - bool isUnsigned = tok->valueType() && tok->valueType()->sign == ::ValueType::Sign::UNSIGNED; - if (!isUnsigned && value.isLessThan(dataBase, 0)) { - const bool bailout = (value.type == ExprEngine::ValueType::BailoutValue); - dataBase->reportError(tok, - Severity::SeverityType::error, - "bughuntingArrayIndexNegative", - "Array index out of bounds, cannot determine that " + index->expressionString() + " is not negative", - CWE_BUFFER_UNDERRUN, - false, - bailout); - } -} - -static void bufferOverflow(const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase) -{ - if (value.type != ExprEngine::ValueType::FunctionCallArgumentValues) - return; - if (!Token::simpleMatch(tok, "(") || !Token::Match(tok->previous(), "%name% (")) - return; - - const Library::Function *func = dataBase->settings->library.getFunction(tok->previous()); - if (!func) - return; - - const ExprEngine::FunctionCallArgumentValues *functionCallArguments = dynamic_cast(&value); - if (!functionCallArguments) - return; - - const std::vector arguments = getArguments(tok); - if (functionCallArguments->argValues.size() != arguments.size()) - // TODO investigate what to do - return; - - int overflowArgument = 0; - bool bailout = false; - - for (const auto &argNrChecks: func->argumentChecks) { - const int argnr = argNrChecks.first; - const Library::ArgumentChecks &checks = argNrChecks.second; - if (argnr <= 0 || argnr > arguments.size() || checks.minsizes.empty()) - continue; - - ExprEngine::ValuePtr argValue = functionCallArguments->argValues[argnr - 1]; - if (!argValue || argValue->type == ExprEngine::ValueType::BailoutValue) { - overflowArgument = argnr; - bailout = true; - break; - } - - std::shared_ptr arrayValue = std::dynamic_pointer_cast(argValue); - if (!arrayValue || arrayValue->size.size() != 1) { - // TODO: implement this properly. - overflowArgument = argnr; - bailout = true; - break; - } - - for (const Library::ArgumentChecks::MinSize &minsize: checks.minsizes) { - if (minsize.type == Library::ArgumentChecks::MinSize::Type::ARGVALUE && minsize.arg > 0 && minsize.arg <= arguments.size()) { - ExprEngine::ValuePtr otherValue = functionCallArguments->argValues[minsize.arg - 1]; - if (!otherValue || otherValue->type == ExprEngine::ValueType::BailoutValue) { - overflowArgument = argnr; - bailout = true; - break; - } - if (isLessThan(dataBase, arrayValue->size[0], otherValue)) { - overflowArgument = argnr; - break; - } - } else if (minsize.type == Library::ArgumentChecks::MinSize::Type::STRLEN && minsize.arg > 0 && minsize.arg <= arguments.size()) { - if (func->formatstr) { - // TODO: implement this properly. check if minsize refers to a format string and check max length of that.. - overflowArgument = argnr; - bailout = true; - break; - } - if (Token::Match(arguments[minsize.arg - 1], "%str%")) { - const Token * const str = arguments[minsize.arg - 1]; - if (arrayValue->size[0]->isLessThan(dataBase, Token::getStrLength(str))) { - overflowArgument = argnr; - break; - } - } else { - ExprEngine::ValuePtr otherValue = functionCallArguments->argValues[minsize.arg - 1]; - if (!otherValue || otherValue->type == ExprEngine::ValueType::BailoutValue) { - overflowArgument = argnr; - bailout = true; - break; - } - std::shared_ptr arrayValue2 = std::dynamic_pointer_cast(otherValue); - if (!arrayValue2 || arrayValue2->size.size() != 1) { - overflowArgument = argnr; - bailout = true; - break; - } - if (isLessThan(dataBase, arrayValue->size[0], arrayValue2->size[0])) { - overflowArgument = argnr; - break; - } - } - } - } - - if (overflowArgument > 0) - break; - } - - if (overflowArgument == 0) - return; - - dataBase->reportError(tok, - Severity::SeverityType::error, - "bughuntingBufferOverflow", - "Buffer read/write, when calling '" + tok->previous()->str() + "' it cannot be determined that " + std::to_string(overflowArgument) + getOrdinalText(overflowArgument) + " argument is not overflowed", - CWE(120), - false, - bailout); -} - -static void divByZero(const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase) -{ - if (!tok->astParent() || !std::strchr("/%", tok->astParent()->str()[0])) - return; - if (tok->hasKnownIntValue() && tok->getKnownIntValue() != 0) - return; - if (tok->isImpossibleIntValue(0)) - return; - if (value.isUninit(dataBase) && value.type != ExprEngine::ValueType::BailoutValue) - return; - float f = getKnownFloatValue(tok, 0.0f); - if (f > 0.0f || f < 0.0f) - return; - if (value.type == ExprEngine::ValueType::BailoutValue) { - if (Token::simpleMatch(tok->previous(), "sizeof (")) - return; - } - if (tok->astParent()->astOperand2() == tok && value.isEqual(dataBase, 0)) { - const char * const id = (tok->valueType() && tok->valueType()->isFloat()) ? "bughuntingDivByZeroFloat" : "bughuntingDivByZero"; - const bool bailout = (value.type == ExprEngine::ValueType::BailoutValue); - dataBase->reportError(dataBase->settings->clang ? tok : tok->astParent(), - Severity::SeverityType::error, - id, - "There is division, cannot determine that there can't be a division by zero.", - CWE(369), - false, - bailout); - } -} - -#ifdef BUG_HUNTING_INTEGEROVERFLOW -static void integerOverflow(const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase) -{ - if (!tok->isArithmeticalOp() || !tok->valueType() || !tok->valueType()->isIntegral() || tok->valueType()->pointer > 0) - return; - - const ExprEngine::BinOpResult *b = dynamic_cast(&value); - if (!b) - return; - - int bits = getIntBitsFromValueType(tok->valueType(), *dataBase->settings); - if (bits == 0 || bits >= 60) - return; - - std::string errorMessage; - if (tok->valueType()->sign == ::ValueType::Sign::SIGNED) { - MathLib::bigint v = 1LL << (bits - 1); - if (b->isGreaterThan(dataBase, v-1)) - errorMessage = "greater than " + std::to_string(v - 1); - if (b->isLessThan(dataBase, -v)) { - if (!errorMessage.empty()) - errorMessage += " or "; - errorMessage += "less than " + std::to_string(-v); - } - } else { - MathLib::bigint maxValue = (1LL << bits) - 1; - if (b->isGreaterThan(dataBase, maxValue)) - errorMessage = "greater than " + std::to_string(maxValue); - if (b->isLessThan(dataBase, 0)) { - if (!errorMessage.empty()) - errorMessage += " or "; - errorMessage += "less than 0"; - } - } - - if (errorMessage.empty()) - return; - - - errorMessage = "There is integer arithmetic, cannot determine that there can't be overflow (if result is " + errorMessage + ")."; - - if (tok->valueType()->sign == ::ValueType::Sign::UNSIGNED) - errorMessage += " Note that unsigned integer overflow is defined and will wrap around."; - - dataBase->reportError(tok, Severity::SeverityType::error, "bughuntingIntegerOverflow", errorMessage, false, value.type == ExprEngine::ValueType::BailoutValue); -} -#endif - -/** check if variable is unconditionally assigned */ -static bool isVariableAssigned(const Variable *var, const Token *tok, const Token *scopeStart=nullptr) -{ - const Token * const start = scopeStart && precedes(var->nameToken(), scopeStart) ? scopeStart : var->nameToken(); - - for (const Token *prev = tok->previous(); prev; prev = prev->previous()) { - if (!precedes(start, prev)) - break; - - if (prev->str() == "}") { - if (Token::simpleMatch(prev->link()->tokAt(-2), "} else {")) { - const Token *elseEnd = prev; - const Token *elseStart = prev->link(); - const Token *ifEnd = elseStart->tokAt(-2); - const Token *ifStart = ifEnd->link(); - if (isVariableAssigned(var, ifEnd, ifStart) && isVariableAssigned(var, elseEnd, elseStart)) { - return true; - } - } - prev = prev->link(); - } - if (scopeStart && Token::Match(prev, "return|throw|continue|break")) - return true; - if (Token::Match(prev, "%varid% =", var->declarationId())) { - bool usedInRhs = false; - visitAstNodes(prev->next()->astOperand2(), [&usedInRhs, var](const Token *tok) { - if (tok->varId() == var->declarationId()) { - usedInRhs = true; - return ChildrenToVisit::done; - } - return ChildrenToVisit::op1_and_op2; - }); - if (!usedInRhs) - return true; - } - } - return false; -} - -static void uninit(const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase) -{ - if (!tok->astParent()) - return; - - std::string uninitStructMember; - if (const auto* structValue = dynamic_cast(&value)) { - uninitStructMember = structValue->getUninitStructMember(dataBase); - - // uninitialized struct member => is there data copy of struct.. - if (!uninitStructMember.empty()) { - if (!Token::Match(tok->astParent(), "[=,(]")) - return; - } - } - - bool uninitData = false; - if (!value.isUninit(dataBase) && uninitStructMember.empty()) { - if (Token::Match(tok->astParent(), "[(,]")) { - if (const auto* arrayValue = dynamic_cast(&value)) { - uninitData = arrayValue->data.size() >= 1 && arrayValue->data[0].value->isUninit(dataBase); - } - } - - if (!uninitData) - return; - } - - // container is not uninitialized - if (tok->valueType() && tok->valueType()->pointer==0 && tok->valueType()->container) - return; - - // container element is not uninitialized - if (tok->str() == "[" && - tok->astOperand1() && - tok->astOperand1()->valueType() && - tok->astOperand1()->valueType()->pointer==0 && - tok->astOperand1()->valueType()->container) { - if (tok->astOperand1()->valueType()->container->stdStringLike) - return; - bool pointerType = false; - for (const Token *typeTok = tok->astOperand1()->valueType()->containerTypeToken; Token::Match(typeTok, "%name%|*|::|<"); typeTok = typeTok->next()) { - if (typeTok->str() == "<" && typeTok->link()) - typeTok = typeTok->link(); - if (typeTok->str() == "*") - pointerType = true; - } - if (!pointerType) - return; - } - - // variable that is not uninitialized.. - if (tok->variable() && !tok->variable()->isPointer() && !tok->variable()->isReference()) { - // smart pointer is not uninitialized - if (tok->variable()->isSmartPointer()) - return; - - // struct - if (tok->variable()->type() && tok->variable()->type()->needInitialization == Type::NeedInitialization::False) - return; - - // template variable is not uninitialized - if (Token::findmatch(tok->variable()->typeStartToken(), "%name% <", tok->variable()->typeEndToken())) - return; - } - - // lhs in assignment - if (tok->astParent()->str() == "=" && tok == tok->astParent()->astOperand1()) - return; - - // Avoid FP when there is bailout.. - if (value.type == ExprEngine::ValueType::BailoutValue) { - if (tok->hasKnownValue()) - return; - if (!tok->variable()) - // FIXME - return; - - // lhs for scope operator - if (Token::Match(tok, "%name% ::")) - return; - if (tok->astParent()->str() == "::" && tok == tok->astParent()->astOperand1()) - return; - - // Object allocated on the stack - if (Token::Match(tok, "%var% .") && tok->next()->originalName() != "->") - return; - - // Assume that stream object is initialized - if (Token::Match(tok->previous(), "[;{}] %var% <<|>>") && !tok->next()->astParent()) - return; - - // Containers are not uninitialized - std::vector tokens{tok, tok->astOperand1(), tok->astOperand2()}; - if (Token::Match(tok->previous(), ". %name%")) - tokens.push_back(tok->previous()->astOperand1()); - for (const Token *t: tokens) { - if (t && t->valueType() && t->valueType()->pointer == 0 && t->valueType()->container) - return; - } - - const Variable *var = tok->variable(); - if (var && var->nameToken() == tok) - return; - if (var && !var->isLocal()) - return; // FIXME - if (var && !var->isPointer()) { - if (!var->isLocal() || var->isStatic()) - return; - } - if (var && (Token::Match(var->nameToken(), "%name% [=:({)]") || var->isInit())) - return; - if (var && var->nameToken() == tok) - return; - - // Are there unconditional assignment? - if (var && Token::Match(var->nameToken(), "%varid% ;| %varid%| =", tok->varId())) - return; - - // Arrays are allocated on the stack - if (var && Token::Match(tok, "%var% [") && var->isArray()) - return; - - if (tok->variable() && isVariableAssigned(tok->variable(), tok)) - return; - } - - // Uninitialized function argument - bool inconclusive = false; - if (Token::Match(tok->astParent(), "[,(]")) { - const Token *parent = tok->astParent(); - int count = 0; - if (Token::simpleMatch(parent, ",")) { - if (tok == parent->astOperand2()) - count = 1; - parent = parent->astParent(); - while (Token::simpleMatch(parent, ",")) { - count++; - parent = parent->astParent(); - } - } - if (Token::simpleMatch(parent, "(") && parent->astOperand1() != tok) { - if (parent->astOperand1()->function()) { - const Variable *argvar = parent->astOperand1()->function()->getArgumentVar(count); - if (argvar && argvar->isReference() && !argvar->isConst()) - return; - if (uninitData && argvar && !argvar->isConst()) { - if (parent->astOperand1()->function()->hasBody()) - return; - inconclusive = true; - } - if (!uninitStructMember.empty() && dataBase->isC() && argvar && !argvar->isConst()) { - if (parent->astOperand1()->function()->hasBody()) - return; - inconclusive = true; - } - } else if (uninitData) { - if (dataBase->settings->library.getFunction(parent->astOperand1())) - return; - if (parent->astOperand1()->isKeyword()) - return; - } - } else if (uninitData) - return; - } - - if (inconclusive && !dataBase->settings->certainty.isEnabled(Certainty::inconclusive)) - return; - - // Avoid FP for array declaration - const Token *parent = tok->astParent(); - while (parent && parent->str() == "[") - parent = parent->astParent(); - if (!parent) - return; - - const std::string inconclusiveMessage(inconclusive ? ". It is inconclusive if there would be a problem in the function call." : ""); - - if (!uninitStructMember.empty()) { - const std::string symbol = tok->expressionString() + "." + uninitStructMember; - dataBase->reportError(tok, - Severity::SeverityType::error, - "bughuntingUninitStructMember", - "$symbol:" + symbol + "\nCannot determine that '$symbol' is initialized" + inconclusiveMessage, - CWE_USE_OF_UNINITIALIZED_VARIABLE, - inconclusive, - value.type == ExprEngine::ValueType::BailoutValue); - return; - } - - std::string uninitexpr = tok->expressionString(); - if (uninitData) - uninitexpr += "[0]"; - - const std::string symbol = (tok->varId() > 0) ? ("$symbol:" + tok->str() + "\n") : std::string(); - - std::string constMessage; - std::string errorId = "bughuntingUninit"; - - { - const Token *vartok = tok; - while (Token::Match(vartok, ".|[")) - vartok = vartok->astOperand1(); - const Variable *var = vartok ? vartok->variable() : nullptr; - if (var && var->isArgument()) { - errorId += "NonConstArg"; - constMessage = " (you can use 'const' to say data must be initialized)"; - } - } - - - dataBase->reportError(tok, - Severity::SeverityType::error, - errorId.c_str(), - symbol + "Cannot determine that '" + uninitexpr + "' is initialized" + constMessage + inconclusiveMessage, - CWE_USE_OF_UNINITIALIZED_VARIABLE, - inconclusive, - value.type == ExprEngine::ValueType::BailoutValue); -} - -static void checkFunctionCall(const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase) -{ - if (!Token::Match(tok->astParent(), "[(,]")) - return; - const Token *parent = tok->astParent(); - while (Token::simpleMatch(parent, ",")) - parent = parent->astParent(); - if (!parent || parent->str() != "(") - return; - - int num = 0; - for (const Token *argTok: getArguments(parent->astOperand1())) { - --num; - if (argTok == tok) { - num = -num; - break; - } - } - if (num <= 0) - return; - - if (parent->astOperand1()->function()) { - const Variable *arg = parent->astOperand1()->function()->getArgumentVar(num - 1); - if (arg && arg->nameToken()) { - std::string bad; - - MathLib::bigint low; - if (arg->nameToken()->getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, &low)) { - if (!(tok->hasKnownIntValue() && tok->getKnownIntValue() >= low) && value.isLessThan(dataBase, low)) - bad = "__cppcheck_low__(" + std::to_string(low) + ")"; - } - - MathLib::bigint high; - if (arg->nameToken()->getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, &high)) { - if (!(tok->hasKnownIntValue() && tok->getKnownIntValue() <= high) && value.isGreaterThan(dataBase, high)) - bad = "__cppcheck_high__(" + std::to_string(high) + ")"; - } - - if (!bad.empty()) { - dataBase->reportError(tok, - Severity::SeverityType::error, - "bughuntingInvalidArgValue", - "There is function call, cannot determine that " + std::to_string(num) + getOrdinalText(num) + " argument value meets the attribute " + bad, - CWE(0), - false); - return; - } - } - } - - // Check invalid function argument values.. - for (const Library::InvalidArgValue &invalidArgValue : Library::getInvalidArgValues(dataBase->settings->library.validarg(parent->astOperand1(), num))) { - bool err = false; - std::string bad; - switch (invalidArgValue.type) { - case Library::InvalidArgValue::Type::eq: - if (!tok->hasKnownIntValue() || tok->getKnownIntValue() == MathLib::toLongNumber(invalidArgValue.op1)) - err = value.isEqual(dataBase, MathLib::toLongNumber(invalidArgValue.op1)); - bad = "equals " + invalidArgValue.op1; - break; - case Library::InvalidArgValue::Type::le: - if (!tok->hasKnownIntValue() || tok->getKnownIntValue() <= MathLib::toLongNumber(invalidArgValue.op1)) - err = value.isLessThan(dataBase, MathLib::toLongNumber(invalidArgValue.op1) + 1); - bad = "less equal " + invalidArgValue.op1; - break; - case Library::InvalidArgValue::Type::lt: - if (!tok->hasKnownIntValue() || tok->getKnownIntValue() < MathLib::toLongNumber(invalidArgValue.op1)) - err = value.isLessThan(dataBase, MathLib::toLongNumber(invalidArgValue.op1)); - bad = "less than " + invalidArgValue.op1; - break; - case Library::InvalidArgValue::Type::ge: - if (!tok->hasKnownIntValue() || tok->getKnownIntValue() >= MathLib::toLongNumber(invalidArgValue.op1)) - err = value.isGreaterThan(dataBase, MathLib::toLongNumber(invalidArgValue.op1) - 1); - bad = "greater equal " + invalidArgValue.op1; - break; - case Library::InvalidArgValue::Type::gt: - if (!tok->hasKnownIntValue() || tok->getKnownIntValue() > MathLib::toLongNumber(invalidArgValue.op1)) - err = value.isGreaterThan(dataBase, MathLib::toLongNumber(invalidArgValue.op1)); - bad = "greater than " + invalidArgValue.op1; - break; - case Library::InvalidArgValue::Type::range: - // TODO - err = value.isEqual(dataBase, MathLib::toLongNumber(invalidArgValue.op1)); - err |= value.isEqual(dataBase, MathLib::toLongNumber(invalidArgValue.op2)); - bad = "range " + invalidArgValue.op1 + "-" + invalidArgValue.op2; - break; - } - - if (err) { - dataBase->reportError(tok, Severity::SeverityType::error, "bughuntingInvalidArgValue", "There is function call, cannot determine that " + std::to_string(num) + getOrdinalText(num) + " argument value is valid. Bad value: " + bad, CWE(0), false); - break; - } - } - - // Uninitialized function argument.. - if (dataBase->settings->library.isuninitargbad(parent->astOperand1(), num) && dataBase->settings->library.isnullargbad(parent->astOperand1(), num) && value.type == ExprEngine::ValueType::ArrayValue) { - const ExprEngine::ArrayValue &arrayValue = static_cast(value); - auto index0 = std::make_shared("0", 0, 0); - for (const auto &v: arrayValue.read(index0)) { - if (v.second->isUninit(dataBase)) { - dataBase->reportError(tok, Severity::SeverityType::error, "bughuntingUninitArg", "There is function call, cannot determine that " + std::to_string(num) + getOrdinalText(num) + " argument is initialized.", CWE_USE_OF_UNINITIALIZED_VARIABLE, false); - break; - } - } - } -} - -static void checkAssignment(const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase) -{ - if (!Token::simpleMatch(tok->astParent(), "=")) - return; - const Token *lhs = tok->astParent()->astOperand1(); - while (Token::simpleMatch(lhs, ".")) - lhs = lhs->astOperand2(); - if (!lhs || !lhs->variable() || !lhs->variable()->nameToken()) - return; - - const Token *vartok = lhs->variable()->nameToken(); - - bool executable = false; - std::string fullName = lhs->variable()->name(); - for (const Scope *s = lhs->variable()->nameToken()->scope(); s->type != Scope::ScopeType::eGlobal; s = s->nestedIn) { - if (s->isExecutable()) { - executable = true; - break; - } - fullName = s->className + "::" + fullName; - } - - auto getMinMaxValue = [=](TokenImpl::CppcheckAttributes::Type type, MathLib::bigint *val) { - if (vartok->getCppcheckAttribute(type, val)) - return true; - if (!executable) { - const auto it = dataBase->settings->variableContracts.find(fullName); - if (it != dataBase->settings->variableContracts.end()) { - const std::string *str; - if (type == TokenImpl::CppcheckAttributes::Type::LOW) - str = &it->second.minValue; - else if (type == TokenImpl::CppcheckAttributes::Type::HIGH) - str = &it->second.maxValue; - else - return false; - *val = MathLib::toLongNumber(*str); - return !str->empty(); - } - } - return false; - }; - - MathLib::bigint low; - if (getMinMaxValue(TokenImpl::CppcheckAttributes::Type::LOW, &low)) { - if (value.isLessThan(dataBase, low)) - dataBase->reportError(tok, Severity::SeverityType::error, "bughuntingAssign", "There is assignment, cannot determine that value is greater or equal with " + std::to_string(low), CWE_INCORRECT_CALCULATION, false); - } - - MathLib::bigint high; - if (getMinMaxValue(TokenImpl::CppcheckAttributes::Type::HIGH, &high)) { - if (value.isGreaterThan(dataBase, high)) - dataBase->reportError(tok, Severity::SeverityType::error, "bughuntingAssign", "There is assignment, cannot determine that value is lower or equal with " + std::to_string(high), CWE_INCORRECT_CALCULATION, false); - } -} - -void addBughuntingChecks(std::vector *callbacks) -{ - callbacks->push_back(arrayIndex); - callbacks->push_back(bufferOverflow); - callbacks->push_back(divByZero); - callbacks->push_back(checkFunctionCall); - callbacks->push_back(checkAssignment); -#ifdef BUG_HUNTING_INTEGEROVERFLOW - callbacks->push_back(integerOverflow); -#endif - callbacks->push_back(uninit); - -} - diff --git a/lib/bughuntingchecks.h b/lib/bughuntingchecks.h deleted file mode 100644 index d12129e23..000000000 --- a/lib/bughuntingchecks.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2022 Cppcheck team. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -//--------------------------------------------------------------------------- -#ifndef bughuntingchecksH -#define bughuntingchecksH -//--------------------------------------------------------------------------- - -#include "exprengine.h" -#include - -void addBughuntingChecks(std::vector *callbacks); - -//--------------------------------------------------------------------------- -#endif // bughuntingchecksH diff --git a/lib/check.cpp b/lib/check.cpp index aca767560..7579152a1 100644 --- a/lib/check.cpp +++ b/lib/check.cpp @@ -51,7 +51,7 @@ void Check::reportError(const ErrorMessage &errmsg) void Check::reportError(const std::list &callstack, Severity::SeverityType severity, const std::string &id, const std::string &msg, const CWE &cwe, Certainty::CertaintyLevel certainty) { - const ErrorMessage errmsg(callstack, mTokenizer ? &mTokenizer->list : nullptr, severity, id, msg, cwe, certainty, mSettings ? mSettings->bugHunting : false); + const ErrorMessage errmsg(callstack, mTokenizer ? &mTokenizer->list : nullptr, severity, id, msg, cwe, certainty); if (mErrorLogger) mErrorLogger->reportErr(errmsg); else @@ -60,7 +60,7 @@ void Check::reportError(const std::list &callstack, Severity::Sev void Check::reportError(const ErrorPath &errorPath, Severity::SeverityType severity, const char id[], const std::string &msg, const CWE &cwe, Certainty::CertaintyLevel certainty) { - const ErrorMessage errmsg(errorPath, mTokenizer ? &mTokenizer->list : nullptr, severity, id, msg, cwe, certainty, mSettings ? mSettings->bugHunting : false); + const ErrorMessage errmsg(errorPath, mTokenizer ? &mTokenizer->list : nullptr, severity, id, msg, cwe, certainty); if (mErrorLogger) mErrorLogger->reportErr(errmsg); else diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index 3381d36fd..348c9387a 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -302,7 +302,7 @@ void CheckMemoryLeak::reportErr(const Token *tok, Severity::SeverityType severit void CheckMemoryLeak::reportErr(const std::list &callstack, Severity::SeverityType severity, const std::string &id, const std::string &msg, const CWE &cwe) const { - const ErrorMessage errmsg(callstack, mTokenizer_ ? &mTokenizer_->list : nullptr, severity, id, msg, cwe, Certainty::normal, mSettings_->bugHunting); + const ErrorMessage errmsg(callstack, mTokenizer_ ? &mTokenizer_->list : nullptr, severity, id, msg, cwe, Certainty::normal); if (mErrorLogger_) mErrorLogger_->reportErr(errmsg); else diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 2493f903a..8abec31c8 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -23,7 +23,6 @@ #include "color.h" #include "ctu.h" #include "errortypes.h" -#include "exprengine.h" #include "library.h" #include "mathlib.h" #include "path.h" @@ -1016,44 +1015,39 @@ void CppCheck::checkRawTokens(const Tokenizer &tokenizer) void CppCheck::checkNormalTokens(const Tokenizer &tokenizer) { - mSettings.library.bugHunting = mSettings.bugHunting; - if (mSettings.bugHunting) - ExprEngine::runChecks(this, &tokenizer, &mSettings); - else { - // call all "runChecks" in all registered Check classes - for (Check *check : Check::instances()) { - if (Settings::terminated()) - return; - - if (Tokenizer::isMaxTime()) - return; - - Timer timerRunChecks(check->name() + "::runChecks", mSettings.showtime, &s_timerResults); - check->runChecks(&tokenizer, &mSettings, this); - } - - if (mSettings.clang) - // TODO: Use CTU for Clang analysis + // call all "runChecks" in all registered Check classes + for (Check *check : Check::instances()) { + if (Settings::terminated()) return; - // Analyse the tokens.. + if (Tokenizer::isMaxTime()) + return; - CTU::FileInfo *fi1 = CTU::getFileInfo(&tokenizer); - if (fi1) { - mFileInfo.push_back(fi1); - mAnalyzerInformation.setFileInfo("ctu", fi1->toString()); - } - - for (const Check *check : Check::instances()) { - Check::FileInfo *fi = check->getFileInfo(&tokenizer, &mSettings); - if (fi != nullptr) { - mFileInfo.push_back(fi); - mAnalyzerInformation.setFileInfo(check->name(), fi->toString()); - } - } - - executeRules("normal", tokenizer); + Timer timerRunChecks(check->name() + "::runChecks", mSettings.showtime, &s_timerResults); + check->runChecks(&tokenizer, &mSettings, this); } + + if (mSettings.clang) + // TODO: Use CTU for Clang analysis + return; + + // Analyse the tokens.. + + CTU::FileInfo *fi1 = CTU::getFileInfo(&tokenizer); + if (fi1) { + mFileInfo.push_back(fi1); + mAnalyzerInformation.setFileInfo("ctu", fi1->toString()); + } + + for (const Check *check : Check::instances()) { + Check::FileInfo *fi = check->getFileInfo(&tokenizer, &mSettings); + if (fi != nullptr) { + mFileInfo.push_back(fi); + mAnalyzerInformation.setFileInfo(check->name(), fi->toString()); + } + } + + executeRules("normal", tokenizer); } //--------------------------------------------------------------------------- @@ -1573,11 +1567,6 @@ void CppCheck::reportInfo(const ErrorMessage &msg) void CppCheck::reportStatus(unsigned int /*fileindex*/, unsigned int /*filecount*/, std::size_t /*sizedone*/, std::size_t /*sizetotal*/) {} -void CppCheck::bughuntingReport(const std::string &str) -{ - mErrorLogger.bughuntingReport(str); -} - void CppCheck::getErrorMessages() { Settings s(mSettings); diff --git a/lib/cppcheck.h b/lib/cppcheck.h index 2b0173645..77f9feaf3 100644 --- a/lib/cppcheck.h +++ b/lib/cppcheck.h @@ -206,8 +206,6 @@ private: */ void reportOut(const std::string &outmsg, Color c = Color::Reset) override; - void bughuntingReport(const std::string &str) override; - std::list mErrorList; Settings mSettings; diff --git a/lib/cppcheck.vcxproj b/lib/cppcheck.vcxproj index 582bda056..fd638c2c4 100644 --- a/lib/cppcheck.vcxproj +++ b/lib/cppcheck.vcxproj @@ -1,4 +1,3 @@ - @@ -39,7 +38,6 @@ - Create Create @@ -81,7 +79,6 @@ - @@ -111,7 +108,6 @@ - @@ -577,4 +573,4 @@ xcopy "$(SolutionDir)platforms" "$(OutDir)platforms" /E /I /D /Y - \ No newline at end of file + diff --git a/lib/cppcheck.vcxproj.filters b/lib/cppcheck.vcxproj.filters index 1b465925e..5595bd5ae 100644 --- a/lib/cppcheck.vcxproj.filters +++ b/lib/cppcheck.vcxproj.filters @@ -161,9 +161,6 @@ Source Files - - Source Files - Source Files @@ -182,9 +179,6 @@ Source Files - - Source Files - Source Files @@ -364,9 +358,6 @@ Header Files - - Header Files - Header Files @@ -386,4 +377,4 @@ - \ No newline at end of file + diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index 58ec67755..294ff8708 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -61,14 +61,6 @@ InternalError::InternalError(const Token *tok, const std::string &errorMsg, Type break; } } - -static std::size_t calculateWarningHash(const TokenList *tokenList, const std::string &msg) -{ - if (!tokenList) - return 0; - return std::hash {}(msg + "\n" + tokenList->front()->stringifyList(false, true, false, false, false)); -} - ErrorMessage::ErrorMessage() : incomplete(false), severity(Severity::none), cwe(0U), certainty(Certainty::normal), hash(0) {} @@ -122,7 +114,7 @@ ErrorMessage::ErrorMessage(const std::list& callstack, const Token } -ErrorMessage::ErrorMessage(const std::list& callstack, const TokenList* list, Severity::SeverityType severity, const std::string& id, const std::string& msg, const CWE &cwe, Certainty::CertaintyLevel certainty, bool bugHunting) +ErrorMessage::ErrorMessage(const std::list& callstack, const TokenList* list, Severity::SeverityType severity, const std::string& id, const std::string& msg, const CWE &cwe, Certainty::CertaintyLevel certainty) : id(id), incomplete(false), severity(severity), cwe(cwe.id), certainty(certainty) { // Format callstack @@ -139,15 +131,10 @@ ErrorMessage::ErrorMessage(const std::list& callstack, const Token setmsg(msg); - std::ostringstream hashWarning; - for (const Token *tok: callstack) - hashWarning << std::hex << (tok ? tok->index() : 0) << " "; - hashWarning << mShortMessage; - - hash = bugHunting ? calculateWarningHash(list, hashWarning.str()) : 0; + hash = 0; // calculateWarningHash(list, hashWarning.str()); } -ErrorMessage::ErrorMessage(const ErrorPath &errorPath, const TokenList *tokenList, Severity::SeverityType severity, const char id[], const std::string &msg, const CWE &cwe, Certainty::CertaintyLevel certainty, bool bugHunting) +ErrorMessage::ErrorMessage(const ErrorPath &errorPath, const TokenList *tokenList, Severity::SeverityType severity, const char id[], const std::string &msg, const CWE &cwe, Certainty::CertaintyLevel certainty) : id(id), incomplete(false), severity(severity), cwe(cwe.id), certainty(certainty) { // Format callstack @@ -171,12 +158,7 @@ ErrorMessage::ErrorMessage(const ErrorPath &errorPath, const TokenList *tokenLis setmsg(msg); - std::ostringstream hashWarning; - for (const ErrorPathItem &e: errorPath) - hashWarning << std::hex << (e.first ? e.first->index() : 0) << " "; - hashWarning << mShortMessage; - - hash = bugHunting ? calculateWarningHash(tokenList, hashWarning.str()) : 0; + hash = 0; // calculateWarningHash(tokenList, hashWarning.str()); } ErrorMessage::ErrorMessage(const tinyxml2::XMLElement * const errmsg) diff --git a/lib/errorlogger.h b/lib/errorlogger.h index 4fddff6cf..e81e541d7 100644 --- a/lib/errorlogger.h +++ b/lib/errorlogger.h @@ -144,16 +144,14 @@ public: const std::string& id, const std::string& msg, const CWE &cwe, - Certainty::CertaintyLevel certainty, - bool bugHunting); + Certainty::CertaintyLevel certainty); ErrorMessage(const ErrorPath &errorPath, const TokenList *tokenList, Severity::SeverityType severity, const char id[], const std::string &msg, const CWE &cwe, - Certainty::CertaintyLevel certainty, - bool bugHunting); + Certainty::CertaintyLevel certainty); ErrorMessage(); explicit ErrorMessage(const tinyxml2::XMLElement * const errmsg); @@ -283,8 +281,6 @@ public: reportErr(msg); } - virtual void bughuntingReport(const std::string &str) = 0; - /** * Report unmatched suppressions * @param unmatched list of unmatched suppressions (from Settings::Suppressions::getUnmatched(Local|Global)Suppressions) diff --git a/lib/exprengine.cpp b/lib/exprengine.cpp deleted file mode 100644 index 6866bea12..000000000 --- a/lib/exprengine.cpp +++ /dev/null @@ -1,3174 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2022 Cppcheck team. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * @brief This is the ExprEngine component in Cppcheck. Its job is to - * convert the C/C++ code into expressions that the Z3 prover understands. - * We can then ask Z3 prover for instance if variable "x" can be 123 and - * the Z3 prover can tell us that. - * - * Overview - * ======== - * - * The ExprEngine performs a "abstract execution" of each function. - * - ExprEngine performs "forward" analysis only. It starts at the top - * of the functions. - * - There is a abstract program state `Data::memory`. - * - The constraints are stored in the vector `Data::constraints`. - * - * Abstract program state - * ====================== - * - * The map `Data::memory` contains the abstract values of all variables - * that are used in the current function scope. - * - * Use `--debug-bug-hunting --verbose` to dump out `Data::memory`. - * Example output: - * 2:5: { x=$1 y=$2} - * Explanation: - * At line 2, column 5: The memory has two variables. Variable x has the - * value $1. Variable y has the value $2. - * - * Different value names: - * - Typical abstract value has name that starts with "$". The number is - * just a incremented value. - * - If a variable has a known value then the concrete value is written. - * Example: `{ x=1 }`. - * - For an uninitialized value the output says "?". For example: `{ a=? }` - * - For buffers the output is something like `{ buf=($3,size=10,[:]=?,[$1]=$2) }` - * The first item "$3" is the name of the buffer value. - * The second item says that the size of this buffer is 10. - * After that comes `[index]=value` items that show what values buffer items have: - * `[:]=?` means that all items are uninitialized. - * `[$1]=$2` means that the buffer item at index "$1" has value "$2". - * - * Abstract execution - * ================== - * - * The function: - * static std::string execute(const Token *start, const Token *end, Data &data) - * - * Perform abstract execution of the code from `start` to `end`. The - * `data` is modified during the abstract execution. - * - * Each astTop token is executed. From that, operands are executed - * recursively in the "execute.." functions. The result of an operand is - * a abstract value. - * - * Branches - * -------- - * - * Imagine: - * code1 - * if (x > 0) - * code2 - * else - * code3 - * code4 - * - * When "if" is reached.. the current `data` is branched into `thenData` - * and `elseData`. - * For "thenData" a constraint is added: x>0 - * For "elseData" a constraint is added: !(x>0) - * - * Then analysis of `thenData` and `elseData` will continue separately, - * by recursive execution. The "code4" block will be analysed both with - * `thenData` and `elseData`. - * - * Z3 - * == - * - * The ExprEngine will not execute Z3 unless a check wants it to. - * - * The abstract values and all their constraints is added to a Z3 solver - * object and after that Z3 can tell us if some condition can be true. - * - * Z3 is a SMT solver: - * https://en.wikipedia.org/wiki/Satisfiability_modulo_theories - * - * In SMT: - * - all variables are "constant". A variable can not be changed or assigned. - * - There is no "execution". The solver considers all equations simultaneously. - * - * Simple example (TestExpr::expr6): - * - * void f(unsigned char x) - * { - * unsigned char y = 8 - x;\n" - * y > 1000; - * } - * - * If a check wants to know if "y > 1000" can be true, ExprEngine will - * generate this Z3 input: - * - * (declare-fun $1 () Int) - * (assert (and (>= $1 0) (<= $1 255))) - * (assert (> (- 8 $1) 1000)) - * - * A symbol "$1" is created. - * assert that "$1" is a value 0-255. - * assert that "8-$1" is greater than 1000. - * - * Z3 can now determine if these assertions are possible or not. In this - * case these assertions are not possible, there is no value for $1 between - * 0-255 that means that "8-$1" is greater than 1000. - */ - -#include "exprengine.h" - -#include "astutils.h" -#include "bughuntingchecks.h" -#include "errorlogger.h" -#include "library.h" -#include "mathlib.h" -#include "platform.h" -#include "settings.h" -#include "symboldatabase.h" -#include "token.h" -#include "tokenize.h" -#include "tokenlist.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef USE_Z3 -#include -#include -#define GET_VERSION_INT(A,B,C) ((A) * 10000 + (B) * 100 + (C)) -#define Z3_VERSION_INT GET_VERSION_INT(Z3_MAJOR_VERSION, Z3_MINOR_VERSION, Z3_BUILD_NUMBER) -#endif - -const uint32_t MAX_BUFFER_SIZE = ~0U >> 1; -#define CONTRACT 1 - -namespace { - struct ExprEngineException { - ExprEngineException(const Token *tok, const std::string &what) : tok(tok), what(what) {} - const Token *tok; - const std::string what; - }; - struct TerminateExpression {}; -} - -static std::string str(ExprEngine::ValuePtr val) -{ - const char *typestr = "???UnknownValueType???"; - switch (val->type) { - case ExprEngine::ValueType::AddressOfValue: - typestr = "AddressOfValue"; - break; - case ExprEngine::ValueType::ArrayValue: - typestr = "ArrayValue"; - break; - case ExprEngine::ValueType::UninitValue: - typestr = "UninitValue"; - break; - case ExprEngine::ValueType::IntRange: - typestr = "IntRange"; - break; - case ExprEngine::ValueType::FloatRange: - typestr = "FloatRange"; - break; - case ExprEngine::ValueType::ConditionalValue: - typestr = "ConditionalValue"; - break; - case ExprEngine::ValueType::StringLiteralValue: - typestr = "StringLiteralValue"; - break; - case ExprEngine::ValueType::StructValue: - typestr = "StructValue"; - break; - case ExprEngine::ValueType::BinOpResult: - typestr = "BinOpResult"; - break; - case ExprEngine::ValueType::IntegerTruncation: - typestr = "IntegerTruncation"; - break; - case ExprEngine::ValueType::FunctionCallArgumentValues: - typestr = "FunctionCallArgumentValues"; - break; - case ExprEngine::ValueType::BailoutValue: - typestr = "BailoutValue"; - break; - } - - return val->name + "=" + std::string(typestr) + "(" + val->getRange() + ")"; -} - -static size_t extfind(const std::string &str, const std::string &what, size_t pos) -{ - int indent = 0; - for (; pos < str.size(); ++pos) { - if (indent <= 0 && str[pos] == what[0]) - return pos; - else if (str[pos] == '\"') { - ++pos; - while (pos < str.size()) { - if (str[pos] == '\"') - break; - if (pos == '\\') - ++pos; - ++pos; - } - } else if (str[pos] == '(') - ++indent; - else if (str[pos] == ')') - --indent; - } - return std::string::npos; -} - -std::string ExprEngine::str(int128_t value) -{ - std::ostringstream ostr; -#ifdef __GNUC__ - if (value == (int)value) { - ostr << (int) value; - return ostr.str(); - } - if (value < 0) { - ostr << "-"; - value = -value; - } - - uint64_t high = value >> 64; - uint64_t low = value; - if (high > 0) - ostr << "h" << std::hex << high << "l"; - ostr << std::hex << low; -#else - ostr << value; -#endif - return ostr.str(); -} - -static ExprEngine::ValuePtr getValueRangeFromValueType(const std::string &name, const ValueType *vt, const cppcheck::Platform &platform); - -namespace { - class TrackExecution { - public: - TrackExecution() : mDataIndexCounter(0), mAbortLine(-1) {} - - int getNewDataIndex() { - return mDataIndexCounter++; - } - - void symbolRange(const Token *tok, ExprEngine::ValuePtr value) { - if (!tok || !value) - return; - if (tok->index() == 0) - return; - const std::string &symbolicExpression = value->getSymbolicExpression(); - if (std::isdigit(symbolicExpression[0]) || value->type == ExprEngine::ValueType::BinOpResult || value->type == ExprEngine::ValueType::UninitValue) - return; - if (mSymbols.find(symbolicExpression) != mSymbols.end()) - return; - mSymbols.insert(symbolicExpression); - mMap[tok].push_back(str(value)); - } - - void state(const Token *tok, const std::string &s) { - mMap[tok].push_back(s); - } - - void print(std::ostream &out) { - std::set> locations; - for (const auto& it : mMap) { - locations.insert(std::pair(it.first->linenr(), it.first->column())); - } - for (const std::pair &loc : locations) { - int lineNumber = loc.first; - int column = loc.second; - for (auto &it : mMap) { - const Token *tok = it.first; - if (lineNumber != tok->linenr()) - continue; - if (column != tok->column()) - continue; - const std::vector &dumps = it.second; - for (const std::string &dump : dumps) - out << lineNumber << ":" << column << ": " << dump << "\n"; - } - } - } - - void report(std::ostream &out, const Scope *functionScope) const { - int linenr = -1; - std::string code; - for (const Token *tok = functionScope->bodyStart->next(); tok != functionScope->bodyEnd; tok = tok->next()) { - if (tok->linenr() > linenr) { - if (!code.empty()) - out << getStatus(linenr) << " " << code << std::endl; - linenr = tok->linenr(); - code.clear(); - } - code += " " + tok->str(); - } - - out << getStatus(linenr) << " " << code << std::endl; - } - - void setAbortLine(int linenr) { - if (linenr > 0 && (mAbortLine == -1 || linenr < mAbortLine)) - mAbortLine = linenr; - } - - void addError(int linenr) { - mErrors.insert(linenr); - } - - bool isAllOk() const { - return mErrors.empty(); - } - - void addMissingContract(const std::string &f) { - mMissingContracts.insert(f); - } - - const std::set getMissingContracts() const { - return mMissingContracts; - } - - void ifSplit(const Token *tok, unsigned int thenIndex, unsigned int elseIndex) { - mMap[tok].push_back("D" + std::to_string(thenIndex) + ": Split. Then:D" + std::to_string(thenIndex) + " Else:D" + std::to_string(elseIndex)); - } - - private: - const char *getStatus(int linenr) const { - if (mErrors.find(linenr) != mErrors.end()) - return "ERROR"; - if (mAbortLine > 0 && linenr >= mAbortLine) - return "--"; - return "ok"; - } - - std::map> mMap; - - int mDataIndexCounter; - int mAbortLine; - std::set mSymbols; - std::set mErrors; - std::set mMissingContracts; - }; - - class Data : public ExprEngine::DataBase { - public: - Data(int *symbolValueIndex, ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings, const std::string ¤tFunction, const std::vector &callbacks, TrackExecution *trackExecution) - : DataBase(currentFunction, settings) - , symbolValueIndex(symbolValueIndex) - , errorLogger(errorLogger) - , tokenizer(tokenizer) - , callbacks(callbacks) - , recursion(0) - , startTime(std::time(nullptr)) - , mTrackExecution(trackExecution) - , mDataIndex(trackExecution->getNewDataIndex()) {} - - Data(const Data &old) - : DataBase(old.currentFunction, old.settings) - , memory(old.memory) - , symbolValueIndex(old.symbolValueIndex) - , errorLogger(old.errorLogger) - , tokenizer(old.tokenizer) - , callbacks(old.callbacks) - , constraints(old.constraints) - , recursion(old.recursion) - , startTime(old.startTime) - , mTrackExecution(old.mTrackExecution) - , mDataIndex(mTrackExecution->getNewDataIndex()) { - for (auto &it: memory) { - if (!it.second) - continue; - if (auto oldValue = std::dynamic_pointer_cast(it.second)) - it.second = std::make_shared(getNewSymbolName(), *oldValue); - } - } - - using Memory = std::map; - Memory memory; - int * const symbolValueIndex; - ErrorLogger *errorLogger; - const Tokenizer * const tokenizer; - const std::vector &callbacks; - std::vector constraints; - int recursion; - std::time_t startTime; - - bool isC() const override { - return tokenizer->isC(); - } - bool isCPP() const override { - return tokenizer->isCPP(); - } - -#ifdef CONTRACT - ExprEngine::ValuePtr executeContract(const Function *function, ExprEngine::ValuePtr (*executeExpression)(const Token*, Data&)) { - const auto it = settings->functionContracts.find(function->fullName()); - if (it == settings->functionContracts.end()) - return ExprEngine::ValuePtr(); - const std::string &expects = it->second; - TokenList tokenList(settings); - std::istringstream istr(expects); - tokenList.createTokens(istr); - tokenList.createAst(); - SymbolDatabase *symbolDatabase = const_cast(tokenizer->getSymbolDatabase()); - for (Token *tok = tokenList.front(); tok; tok = tok->next()) { - for (const Variable &arg: function->argumentList) { - if (arg.name() == tok->str()) { - tok->variable(&arg); - tok->varId(arg.declarationId()); - } - } - } - symbolDatabase->setValueTypeInTokenList(false, tokenList.front()); - return executeExpression(tokenList.front()->astTop(), *this); - } - - void contractConstraints(const Function *function, ExprEngine::ValuePtr (*executeExpression)(const Token*, Data&)) { - auto value = executeContract(function, executeExpression); - if (value) - constraints.push_back(value); - } -#endif - - void assignValue(const Token *tok, unsigned int varId, ExprEngine::ValuePtr value) { - if (varId == 0) - return; - mTrackExecution->symbolRange(tok, value); - if (value) { - if (auto arr = std::dynamic_pointer_cast(value)) { - for (const auto &dim: arr->size) - mTrackExecution->symbolRange(tok, dim); - for (const auto &indexAndValue: arr->data) - mTrackExecution->symbolRange(tok, indexAndValue.value); - } else if (auto s = std::dynamic_pointer_cast(value)) { - for (const auto &m: s->member) - mTrackExecution->symbolRange(tok, m.second); - } - } - memory[varId] = value; - } - - void assignStructMember(const Token *tok, ExprEngine::StructValue *structVal, const std::string &memberName, ExprEngine::ValuePtr value) { - mTrackExecution->symbolRange(tok, value); - structVal->member[memberName] = value; - } - - void functionCall() { - // Remove values for global variables - const SymbolDatabase *symbolDatabase = tokenizer->getSymbolDatabase(); - for (std::map::iterator it = memory.begin(); it != memory.end();) { - unsigned int varid = it->first; - const Variable *var = symbolDatabase->getVariableFromVarId(varid); - if (var && var->isGlobal()) - it = memory.erase(it); - else - ++it; - } - } - - std::string getNewSymbolName() final { - return "$" + std::to_string(++(*symbolValueIndex)); - } - - std::shared_ptr getArrayValue(const Token *tok) { - const Memory::iterator it = memory.find(tok->varId()); - if (it != memory.end()) - return std::dynamic_pointer_cast(it->second); - if (tok->varId() == 0 || !tok->variable()) - return std::shared_ptr(); - auto val = std::make_shared(this, tok->variable()); - assignValue(tok, tok->varId(), val); - return val; - } - - ExprEngine::ValuePtr getValue(unsigned int varId, const ValueType *valueType, const Token *tok) { - const Memory::const_iterator it = memory.find(varId); - if (it != memory.end()) - return it->second; - if (!valueType) - return ExprEngine::ValuePtr(); - - // constant value.. - const Variable *var = tokenizer->getSymbolDatabase()->getVariableFromVarId(varId); - if (var && valueType->constness == 1 && Token::Match(var->nameToken(), "%var% =")) { - const Token *initExpr = var->nameToken()->next()->astOperand2(); - if (initExpr && initExpr->hasKnownIntValue()) { - auto intval = initExpr->getKnownIntValue(); - return std::make_shared(std::to_string(intval), intval, intval); - } - } - - ExprEngine::ValuePtr value = getValueRangeFromValueType(getNewSymbolName(), valueType, *settings); - if (value) { - if (tok->variable() && tok->variable()->nameToken()) - addConstraints(value, tok->variable()->nameToken()); - assignValue(tok, varId, value); - } - return value; - } - - void trackCheckContract(const Token *tok, const std::string &solverOutput) { - std::ostringstream os; - os << "checkContract:{\n"; - - std::string line; - std::istringstream istr(solverOutput); - while (std::getline(istr, line)) - os << " " << line << "\n"; - - os << "}"; - - mTrackExecution->state(tok, os.str()); - } - - void trackProgramState(const Token *tok) { - if (memory.empty()) - return; - const SymbolDatabase * const symbolDatabase = tokenizer->getSymbolDatabase(); - std::ostringstream s; - s << "D" << mDataIndex << ":" << "memory:{"; - bool first = true; - for (const auto &mem : memory) { - ExprEngine::ValuePtr value = mem.second; - const Variable *var = symbolDatabase->getVariableFromVarId(mem.first); - if (!var) - continue; - if (!first) - s << " "; - first = false; - s << var->name() << "="; - if (!value) - s << "(null)"; - else if (value->name[0] == '$' && value->getSymbolicExpression() != value->name) - s << "(" << value->name << "," << value->getSymbolicExpression() << ")"; - else - s << value->name; - } - s << "}"; - - if (!constraints.empty()) { - s << " constraints:{"; - first = true; - for (const auto &constraint: constraints) { - if (!first) - s << " "; - first = false; - s << constraint->getSymbolicExpression(); - } - s << "}"; - } - mTrackExecution->state(tok, s.str()); - } - - void addMissingContract(const std::string &f) { - mTrackExecution->addMissingContract(f); - } - - ExprEngine::ValuePtr notValue(ExprEngine::ValuePtr v) { - auto b = std::dynamic_pointer_cast(v); - if (b) { - std::string binop; - if (b->binop == "==") - binop = "!="; - else if (b->binop == "!=") - binop = "=="; - else if (b->binop == ">=") - binop = "<"; - else if (b->binop == "<=") - binop = ">"; - else if (b->binop == ">") - binop = "<="; - else if (b->binop == "<") - binop = ">="; - if (!binop.empty()) - return std::make_shared(binop, b->op1, b->op2); - } - if (std::dynamic_pointer_cast(v)) { - auto zero = std::make_shared("0.0", 0.0, 0.0); - return std::make_shared("==", v, zero); - } - auto zero = std::make_shared("0", 0, 0); - return std::make_shared("==", v, zero); - } - - void addConstraint(ExprEngine::ValuePtr condValue, bool trueCond) { - if (!condValue) - return; - if (trueCond) - constraints.push_back(condValue); - else - constraints.push_back(notValue(condValue)); - } - - void addConstraint(ExprEngine::ValuePtr lhsValue, ExprEngine::ValuePtr rhsValue, bool equals) { - if (!lhsValue || !rhsValue) - return; - constraints.push_back(std::make_shared(equals?"==":"!=", lhsValue, rhsValue)); - } - - void addConstraints(ExprEngine::ValuePtr value, const Token *tok) { -#ifdef CONTRACT - MathLib::bigint low; - if (tok->getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, &low)) - addConstraint(std::make_shared(">=", value, std::make_shared(std::to_string(low), low, low)), true); - - MathLib::bigint high; - if (tok->getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, &high)) - addConstraint(std::make_shared("<=", value, std::make_shared(std::to_string(high), high, high)), true); -#endif - } - - void reportError(const Token *tok, - Severity::SeverityType severity, - const char id[], - const std::string &text, - CWE cwe, - bool inconclusive, - bool incomplete, - const std::string &functionName) override { - if (errorPath.empty()) - mTrackExecution->addError(tok->linenr()); - - ErrorPath e = errorPath; - e.push_back(ErrorPathItem(tok, text)); - ErrorMessage errmsg(e, &tokenizer->list, severity, id, text, cwe, inconclusive ? Certainty::inconclusive : Certainty::normal, true); - errmsg.incomplete = incomplete; - errmsg.function = functionName.empty() ? currentFunction : functionName; - errorLogger->reportErr(errmsg); - } - - std::string str() const { - std::ostringstream ret; - std::map vars; - for (const auto &mem: memory) { - if (!mem.second) - continue; - const Variable *var = tokenizer->getSymbolDatabase()->getVariableFromVarId(mem.first); - if (var && var->isLocal()) - continue; - ret << " @" << mem.first << ":" << mem.second->name; - getSymbols(vars, mem.second); - } - for (const auto &var: vars) { - if (var.second->name[0] == '$') - ret << " " << ::str(var.second); - } - for (const auto &c: constraints) - ret << " (" << c->getSymbolicExpression() << ")"; - ret << std::endl; - return ret.str(); - } - - void load(const std::string &s) { - std::vector importData; - parsestr(s, &importData); - //simplify(importData); - - if (importData.empty()) - return; - - std::map symbols; - for (const auto &mem: memory) { - getSymbols(symbols, mem.second); - } - - // TODO: combined symbolvalue - std::map combinedMemory; - for (const ImportData &d: importData) { - for (const auto &mem: d.mem) { - auto c = combinedMemory.find(mem.first); - if (c == combinedMemory.end()) { - combinedMemory[mem.first] = mem.second; - continue; - } - if (c->second == mem.second) - continue; - if (c->second == "?" || mem.second == "?") - c->second = "?"; - else - c->second.clear(); - } - } - - for (const auto &mem: combinedMemory) { - int varid = mem.first; - const std::string &name = mem.second; - auto it = memory.find(varid); - if (it != memory.end() && it->second && it->second->name == name) - continue; - if (name.empty()) { - if (it != memory.end()) - memory.erase(it); - continue; - } - auto it2 = symbols.find(name); - if (it2 != symbols.end()) { - memory[varid] = it2->second; - continue; - } - if (name == "?") { - auto uninitValue = std::make_shared(); - symbols[name] = uninitValue; - memory[varid] = uninitValue; - continue; - } - if (std::isdigit(name[0])) { - long long v = std::stoi(name); - auto intRange = std::make_shared(name, v, v); - symbols[name] = intRange; - memory[varid] = intRange; - continue; - } - // TODO: handle this value.. - if (it != memory.end()) - memory.erase(it); - } - } - - static void ifSplit(const Token *tok, const Data& thenData, const Data& elseData) { - thenData.mTrackExecution->ifSplit(tok, thenData.mDataIndex, elseData.mDataIndex); - } - - private: - TrackExecution * const mTrackExecution; - const int mDataIndex; - - struct ImportData { - std::map mem; - std::map sym; - std::vector constraints; - }; - - static void parsestr(const std::string &s, std::vector *importData) { - std::string line; - std::istringstream istr(s); - while (std::getline(istr, line)) { - if (line.empty()) - continue; - line += " "; - ImportData d; - for (std::string::size_type pos = 0; pos < line.size();) { - pos = line.find_first_not_of(" ", pos); - if (pos == std::string::npos) - break; - if (line[pos] == '@') { - ++pos; - std::string::size_type colon = line.find(":", pos); - std::string::size_type end = line.find(" ", colon); - const std::string lhs = line.substr(pos, colon-pos); - pos = colon + 1; - const std::string rhs = line.substr(pos, end-pos); - d.mem[std::stoi(lhs)] = rhs; - pos = end; - } else if (line[pos] == '$') { - const std::string::size_type eq = line.find("=", pos); - const std::string lhs = line.substr(pos, eq-pos); - pos = eq + 1; - const std::string::size_type end = extfind(line, " ", pos); - const std::string rhs = line.substr(pos, end-pos); - pos = end; - d.sym[lhs] = rhs; - } else if (line[pos] == '(') { - const std::string::size_type end = extfind(line, " ", pos); - const std::string c = line.substr(pos, end-pos); - pos = end; - d.constraints.push_back(c); - } else { - throw ExprEngineException(nullptr, "Internal Error: Data::parsestr(), line:" + line); - } - } - importData->push_back(d); - } - } - - void getSymbols(std::map &symbols, ExprEngine::ValuePtr val) const { - if (!val) - return; - symbols[val->name] = val; - if (auto arrayValue = std::dynamic_pointer_cast(val)) { - for (const auto &sizeValue: arrayValue->size) - getSymbols(symbols, sizeValue); - for (const auto &indexValue: arrayValue->data) { - getSymbols(symbols, indexValue.index); - getSymbols(symbols, indexValue.value); - } - } - if (auto structValue = std::dynamic_pointer_cast(val)) { - for (const auto &memberNameValue: structValue->member) - getSymbols(symbols, memberNameValue.second); - } - } - }; -} - -#ifdef __clang__ -// work around "undefined reference to `__muloti4'" linker error - see https://bugs.llvm.org/show_bug.cgi?id=16404 -__attribute__((no_sanitize("undefined"))) -#endif -static ExprEngine::ValuePtr simplifyValue(ExprEngine::ValuePtr origValue) -{ - auto b = std::dynamic_pointer_cast(origValue); - if (!b) - return origValue; - if (!b->op1 || !b->op2) - return origValue; - auto intRange1 = std::dynamic_pointer_cast(b->op1); - auto intRange2 = std::dynamic_pointer_cast(b->op2); - if (intRange1 && intRange2 && intRange1->minValue == intRange1->maxValue && intRange2->minValue == intRange2->maxValue) { - const std::string &binop = b->binop; - int128_t v; - if (binop == "+") - v = intRange1->minValue + intRange2->minValue; - else if (binop == "-") - v = intRange1->minValue - intRange2->minValue; - else if (binop == "*") - v = intRange1->minValue * intRange2->minValue; - else if (binop == "/" && intRange2->minValue != 0) - v = intRange1->minValue / intRange2->minValue; - else if (binop == "%" && intRange2->minValue != 0) - v = intRange1->minValue % intRange2->minValue; - else - return origValue; - return std::make_shared(ExprEngine::str(v), v, v); - } - return origValue; -} - -static ExprEngine::ValuePtr translateUninitValueToRange(ExprEngine::ValuePtr value, const ::ValueType *valueType, Data &data) -{ - if (!value) - return value; - if (value->type == ExprEngine::ValueType::UninitValue) { - auto rangeValue = getValueRangeFromValueType(data.getNewSymbolName(), valueType, *data.settings); - if (rangeValue) - return rangeValue; - } - if (auto conditionalValue = std::dynamic_pointer_cast(value)) { - if (conditionalValue->values.size() == 1 && conditionalValue->values[0].second && conditionalValue->values[0].second->type == ExprEngine::ValueType::UninitValue) { - auto rangeValue = getValueRangeFromValueType(data.getNewSymbolName(), valueType, *data.settings); - if (rangeValue) - return rangeValue; - } - } - return value; -} - -static int128_t truncateInt(int128_t value, int bits, char sign) -{ - value = value & (((int128_t)1 << bits) - 1); - // Sign extension - if (sign == 's' && value & (1ULL << (bits - 1))) - value |= ~(((int128_t)1 << bits) - 1); - return value; -} - -ExprEngine::ArrayValue::ArrayValue(const std::string &name, ExprEngine::ValuePtr size, ExprEngine::ValuePtr value, bool pointer, bool nullPointer, bool uninitPointer) - : Value(name, ExprEngine::ValueType::ArrayValue) - , pointer(pointer), nullPointer(nullPointer), uninitPointer(uninitPointer) -{ - this->size.push_back(size); - assign(ExprEngine::ValuePtr(), value); -} - -ExprEngine::ArrayValue::ArrayValue(DataBase *data, const Variable *var) - : Value(data->getNewSymbolName(), ExprEngine::ValueType::ArrayValue) - , pointer(var && var->isPointer()), nullPointer(var && var->isPointer()), uninitPointer(var && var->isPointer()) -{ - if (var) { - for (const auto &dim : var->dimensions()) { - if (dim.known) - size.push_back(std::make_shared(std::to_string(dim.num), dim.num, dim.num)); - else - size.push_back(std::make_shared(data->getNewSymbolName(), 1, ExprEngine::ArrayValue::MAXSIZE)); - } - } else { - size.push_back(std::make_shared(data->getNewSymbolName(), 1, ExprEngine::ArrayValue::MAXSIZE)); - } - - const Token *initToken = var ? var->nameToken() : nullptr; - while (initToken && initToken->str() != "=") - initToken = initToken->astParent(); - - ValuePtr val; - if (var && !var->isGlobal() && !var->isStatic() && !(var->isArgument() && var->isConst()) && !initToken) - val = std::make_shared(); - else if (var && var->valueType()) { - ::ValueType vt(*var->valueType()); - vt.pointer = 0; - val = getValueRangeFromValueType(data->getNewSymbolName(), &vt, *data->settings); - } - assign(ExprEngine::ValuePtr(), val); -} - -ExprEngine::ArrayValue::ArrayValue(const std::string &name, const ExprEngine::ArrayValue &arrayValue) - : Value(name, ExprEngine::ValueType::ArrayValue) - , pointer(arrayValue.pointer), nullPointer(arrayValue.nullPointer), uninitPointer(arrayValue.uninitPointer) - , data(arrayValue.data), size(arrayValue.size) -{} - - -std::string ExprEngine::ArrayValue::getRange() const -{ - std::string r = getSymbolicExpression(); - if (nullPointer) - r += std::string(r.empty() ? "" : ",") + "null"; - if (uninitPointer) - r += std::string(r.empty() ? "" : ",") + "->?"; - return r; -} - -void ExprEngine::ArrayValue::assign(ExprEngine::ValuePtr index, ExprEngine::ValuePtr value) -{ - if (!index) - data.clear(); - if (value) { - if (index) { - // Remove old item that will be "overwritten" - for (size_t i = 0; i < data.size(); ++i) { - if (data[i].index && data[i].index->name == index->name) { - data.erase(data.begin() + i); - break; - } - } - } - - ExprEngine::ArrayValue::IndexAndValue indexAndValue = {index, value}; - data.push_back(indexAndValue); - } -} - -void ExprEngine::ArrayValue::clear() -{ - data.clear(); - ExprEngine::ArrayValue::IndexAndValue indexAndValue = { - ExprEngine::ValuePtr(), std::make_shared("0", 0, 0) - }; - data.push_back(indexAndValue); -} - -static bool isEqual(ExprEngine::ValuePtr v1, ExprEngine::ValuePtr v2) -{ - if (!v1 || !v2) - return !v1 && !v2; - return v1->name == v2->name; -} - -static bool isNonOverlapping(ExprEngine::ValuePtr v1, ExprEngine::ValuePtr v2) -{ - if (!v1 || !v2) - return false; // Don't know! - auto intRange1 = std::dynamic_pointer_cast(v1); - auto intRange2 = std::dynamic_pointer_cast(v2); - if (intRange1 && intRange2 && (intRange1->minValue > intRange2->maxValue || intRange1->maxValue < intRange2->maxValue)) - return true; - return false; -} - -ExprEngine::ConditionalValue::Vector ExprEngine::ArrayValue::read(ExprEngine::ValuePtr index) const -{ - ExprEngine::ConditionalValue::Vector ret; - if (!index) - return ret; - for (const auto &indexAndValue : data) { - if (::isEqual(index, indexAndValue.index)) - ret.clear(); - if (isNonOverlapping(index, indexAndValue.index)) - continue; - // Array contains string literal data... - if (!indexAndValue.index && indexAndValue.value->type == ExprEngine::ValueType::StringLiteralValue) { - auto stringLiteral = std::dynamic_pointer_cast(indexAndValue.value); - if (!stringLiteral) { - ret.push_back(std::pair(indexAndValue.index, std::make_shared("", -128, 128))); - continue; - } - if (auto i = std::dynamic_pointer_cast(index)) { - if (i->minValue >= 0 && i->minValue == i->maxValue) { - int c = 0; - if (i->minValue < stringLiteral->size()) - c = stringLiteral->string[i->minValue]; - ret.push_back(std::pair(indexAndValue.index, std::make_shared(std::to_string(c), c, c))); - continue; - } - } - int cmin = 0, cmax = 0; - for (char c : stringLiteral->string) { - if (c < cmin) - cmin = c; - else if (c > cmax) - cmax = c; - } - ret.push_back(std::pair(indexAndValue.index, std::make_shared("", cmin, cmax))); - continue; - } - - // Rename IntRange - if (auto i = std::dynamic_pointer_cast(indexAndValue.value)) { - ret.push_back(std::pair(indexAndValue.index, std::make_shared(indexAndValue.value->name + ":" + index->name, i->minValue, i->maxValue))); - continue; - } - - ret.push_back(std::pair(indexAndValue.index, indexAndValue.value)); - } - - if (ret.size() == 1) - ret[0].first = ExprEngine::ValuePtr(); - else if (ret.size() == 2 && !ret[0].first) { - ret[0].first = std::make_shared("!=", index, ret[1].first); - ret[1].first = std::make_shared("==", index, ret[1].first); - } else { - // FIXME!! - ret.clear(); - } - - return ret; -} - -std::string ExprEngine::ConditionalValue::getSymbolicExpression() const -{ - std::ostringstream ostr; - ostr << "{"; - bool first = true; - for (const auto& condvalue : values) { - ValuePtr cond = condvalue.first; - ValuePtr value = condvalue.second; - - if (!first) - ostr << ","; - first = false; - ostr << "{" - << (cond ? cond->getSymbolicExpression() : std::string("(null)")) - << "," - << value->getSymbolicExpression() - << "}"; - } - ostr << "}"; - return ostr.str(); -} - -std::string ExprEngine::ArrayValue::getSymbolicExpression() const -{ - std::ostringstream ostr; - if (size.empty()) - ostr << "(null)"; - else { - for (const auto &dim: size) - ostr << "[" << (dim ? dim->name : std::string("(null)")) << "]"; - } - for (const auto &indexAndValue : data) { - ostr << ",[" - << (!indexAndValue.index ? std::string(":") : indexAndValue.index->name) - << "]="; - if (indexAndValue.value->type == ExprEngine::ValueType::StructValue) - ostr << "(" - << indexAndValue.value->name - << "," - << indexAndValue.value->getSymbolicExpression() - << ")"; - else - ostr << indexAndValue.value->name; - } - return ostr.str(); -} - -std::string ExprEngine::StructValue::getSymbolicExpression() const -{ - std::ostringstream ostr; - ostr << "{"; - bool first = true; - for (const auto& m: member) { - const std::string &memberName = m.first; - auto memberValue = m.second; - if (!first) - ostr << ","; - first = false; - ostr << memberName << "=" << (memberValue ? memberValue->getSymbolicExpression() : std::string("(null)")); - } - ostr << "}"; - return ostr.str(); -} - -std::string ExprEngine::IntegerTruncation::getSymbolicExpression() const -{ - return sign + std::to_string(bits) + "(" + inputValue->getSymbolicExpression() + ")"; -} - -#ifdef USE_Z3 - -class ExprData { -public: - using ValueExpr = std::map; - using AssertionList = std::vector; - - class BailoutValueException : public ExprEngineException { - public: - BailoutValueException() : ExprEngineException(nullptr, "Incomplete analysis") {} - }; - - z3::context context; - ValueExpr valueExpr; - AssertionList assertionList; - - void addAssertions(z3::solver &solver) const { - for (const auto &assertExpr : assertionList) - solver.add(assertExpr); - } - - void addConstraints(z3::solver &solver, const Data* data) { - for (const auto &constraint : data->constraints) { - try { - solver.add(getConstraintExpr(constraint)); - } catch (const BailoutValueException &) {} - } - } - - z3::expr addInt(const std::string &name, int128_t minValue, int128_t maxValue) { - z3::expr e = context.int_const(name.c_str()); - valueExpr.emplace(name, e); - if (minValue >= INT_MIN && maxValue <= INT_MAX) - assertionList.push_back(e >= int(minValue) && e <= int(maxValue)); - else if (maxValue <= INT_MAX) - assertionList.push_back(e <= int(maxValue)); - else if (minValue >= INT_MIN) - assertionList.push_back(e >= int(minValue)); - return e; - } - - z3::expr addFloat(const std::string &name) { - z3::expr e = z3_fp_const(name); - valueExpr.emplace(name, e); - return e; - } - - z3::expr getExpr(const ExprEngine::BinOpResult *b) { - auto op1 = getExpr(b->op1); - auto op2 = getExpr(b->op2); - - // floating point promotion - if (b->binop != "&&" && b->binop != "||" && b->binop != "<<" && b->binop != ">>") { - if (z3_is_fp(op1) || z3_is_fp(op2)) { - z3_to_fp(op1); - z3_to_fp(op2); - } - } - - if (b->binop == "+") - return op1 + op2; - if (b->binop == "-") - return op1 - op2; - if (b->binop == "*") - return op1 * op2; - if (b->binop == "/") - return op1 / op2; - if (b->binop == "%") -#if Z3_VERSION_INT >= GET_VERSION_INT(4,8,5) - return op1 % op2; -#else - return op1 - (op1 / op2) * op2; -#endif - if (b->binop == "==") - return int_expr(op1) == int_expr(op2); - if (b->binop == "!=") - return op1 != op2; - if (b->binop == ">=") - return op1 >= op2; - if (b->binop == "<=") - return op1 <= op2; - if (b->binop == ">") - return op1 > op2; - if (b->binop == "<") - return op1 < op2; - if (b->binop == "&&") - return bool_expr(op1) && bool_expr(op2); - if (b->binop == "||") - return bool_expr(op1) || bool_expr(op2); - if (b->binop == "<<") - return op1 * z3::pw(context.int_val(2), op2); - if (b->binop == ">>") - return op1 / z3::pw(context.int_val(2), op2); - throw ExprEngineException(nullptr, "Internal error: Unhandled operator " + b->binop); - } - - z3::expr getExpr(ExprEngine::ValuePtr v) { - if (!v) - throw ExprEngineException(nullptr, "Can not solve expressions, operand value is null"); - if (v->type == ExprEngine::ValueType::BailoutValue) - throw BailoutValueException(); - if (auto intRange = std::dynamic_pointer_cast(v)) { - if (intRange->name[0] != '$') - return z3_int_val(intRange->minValue); - auto it = valueExpr.find(v->name); - if (it != valueExpr.end()) - return it->second; - return addInt(v->name, intRange->minValue, intRange->maxValue); - } - - if (auto floatRange = std::dynamic_pointer_cast(v)) { - if (floatRange->name[0] != '$') - return z3_fp_val(floatRange->minValue, floatRange->name); - - auto it = valueExpr.find(v->name); - if (it != valueExpr.end()) - return it->second; - return addFloat(v->name); - } - - if (auto b = std::dynamic_pointer_cast(v)) { - return getExpr(b.get()); - } - - if (auto c = std::dynamic_pointer_cast(v)) { - if (c->values.empty()) - throw ExprEngineException(nullptr, "ConditionalValue is empty"); - - if (c->values.size() == 1) - return getExpr(c->values[0].second); - - return z3::ite(getExpr(c->values[1].first), - getExpr(c->values[1].second), - getExpr(c->values[0].second)); - } - - if (auto integerTruncation = std::dynamic_pointer_cast(v)) { - return getExpr(integerTruncation->inputValue); - //return getExpr(integerTruncation->inputValue) & ((1 << integerTruncation->bits) - 1); - } - - if (v->type == ExprEngine::ValueType::UninitValue) - return context.int_val(0); - - throw ExprEngineException(nullptr, "Internal error: Unhandled value type"); - } - - z3::expr getConstraintExpr(ExprEngine::ValuePtr v) { - if (v->type == ExprEngine::ValueType::IntRange) - return (getExpr(v) != 0); - return bool_expr(getExpr(v)); - } - - z3::expr bool_expr(z3::expr e) { - if (e.is_bool()) - return e; - - // Workaround for z3 bug: https://github.com/Z3Prover/z3/issues/4905 - if (z3_is_fp(e)) - return e != z3_fp_val(0.0, "0.0"); - - return e != 0; - } - - z3::expr int_expr(z3::expr e) { - if (e.is_bool()) - return z3::ite(e, context.int_val(1), context.int_val(0)); - return e; - } - - // Wrapper functions for Z3 interface. Instead of having ifdefs embedded - // in the code we have wrapper functions with ifdefs. The code that use - // these will be cleaner and hopefully more robust. - - z3::expr z3_fp_const(const std::string &name) { - return context.real_const(name.c_str()); - } - - z3::expr z3_fp_val(long double value, std::string name) { - (void)value; - while (name.size() > 1 && (name.back() == 'f' || name.back() == 'F' || name.back() == 'l' || name.back() == 'L')) - name.erase(name.size() - 1); - return context.real_val(name.c_str()); - } - - bool z3_is_fp(z3::expr e) const { - return e.is_real(); - } - - void z3_to_fp(z3::expr &e) { - if (e.is_int()) - e = z3::to_real(e); - } - - - z3::expr z3_int_val(int128_t value) { -#if Z3_VERSION_INT >= GET_VERSION_INT(4,7,1) - return context.int_val(int64_t(value)); -#else - return context.int_val((long long)(value)); -#endif - } -}; -#endif - -bool ExprEngine::UninitValue::isUninit(const DataBase *dataBase) const { - const Data *data = dynamic_cast(dataBase); - if (data->constraints.empty()) - return true; -#ifdef USE_Z3 - // Check the value against the constraints - ExprData exprData; - z3::solver solver(exprData.context); - try { - exprData.addConstraints(solver, data); - exprData.addAssertions(solver); - return solver.check() == z3::sat; - } catch (const z3::exception &exception) { - std::cerr << "z3: " << exception << std::endl; - return true; // Safe option is to return true - } catch (const ExprData::BailoutValueException &) { - return true; // Safe option is to return true - } catch (const ExprEngineException &) { - return true; // Safe option is to return true - } -#else - // The value may or may not be uninitialized - return false; -#endif -} - -bool ExprEngine::IntRange::isEqual(const DataBase *dataBase, int value) const -{ - if (value < minValue || value > maxValue) - return false; - - const Data *data = dynamic_cast(dataBase); - if (data->constraints.empty()) - return true; -#ifdef USE_Z3 - // Check the value against the constraints - ExprData exprData; - z3::solver solver(exprData.context); - try { - z3::expr e = exprData.addInt(name, minValue, maxValue); - exprData.addConstraints(solver, data); - exprData.addAssertions(solver); - solver.add(e == value); - return solver.check() == z3::sat; - } catch (const z3::exception &exception) { - std::cerr << "z3: " << exception << std::endl; - return true; // Safe option is to return true - } catch (const ExprData::BailoutValueException &) { - return true; // Safe option is to return true - } catch (const ExprEngineException &) { - return true; // Safe option is to return true - } -#else - // The value may or may not be in range - return false; -#endif -} - -bool ExprEngine::IntRange::isGreaterThan(const DataBase *dataBase, int value) const -{ - if (maxValue <= value) - return false; - - const Data *data = dynamic_cast(dataBase); - if (data->constraints.empty()) - return true; -#ifdef USE_Z3 - // Check the value against the constraints - ExprData exprData; - z3::solver solver(exprData.context); - try { - z3::expr e = exprData.addInt(name, minValue, maxValue); - exprData.addConstraints(solver, data); - exprData.addAssertions(solver); - solver.add(e > value); - return solver.check() == z3::sat; - } catch (const z3::exception &exception) { - std::cerr << "z3: " << exception << std::endl; - return true; // Safe option is to return true - } catch (const ExprData::BailoutValueException &) { - return true; // Safe option is to return true - } catch (const ExprEngineException &) { - return true; // Safe option is to return true - } -#else - // The value may or may not be in range - return false; -#endif -} - -bool ExprEngine::IntRange::isLessThan(const DataBase *dataBase, int value) const -{ - if (minValue >= value) - return false; - - const Data *data = dynamic_cast(dataBase); - if (data->constraints.empty()) - return true; -#ifdef USE_Z3 - // Check the value against the constraints - ExprData exprData; - z3::solver solver(exprData.context); - try { - z3::expr e = exprData.addInt(name, minValue, maxValue); - exprData.addConstraints(solver, data); - exprData.addAssertions(solver); - solver.add(e < value); - return solver.check() == z3::sat; - } catch (const z3::exception &exception) { - std::cerr << "z3: " << exception << std::endl; - return true; // Safe option is to return true - } catch (const ExprData::BailoutValueException &) { - return true; // Safe option is to return true - } catch (const ExprEngineException &) { - return true; // Safe option is to return true - } -#else - // The value may or may not be in range - return false; -#endif -} - -bool ExprEngine::FloatRange::isEqual(const DataBase *dataBase, int value) const -{ - if (MathLib::isFloat(name)) { - float f = MathLib::toDoubleNumber(name); - return value >= f - 0.00001 && value <= f + 0.00001; - } - const Data *data = dynamic_cast(dataBase); - if (data->constraints.empty()) - return true; -#ifdef USE_Z3 - // Check the value against the constraints - ExprData exprData; - z3::solver solver(exprData.context); - try { - z3::expr e = exprData.addFloat(name); - exprData.addConstraints(solver, data); - exprData.addAssertions(solver); - // Workaround for z3 bug: https://github.com/Z3Prover/z3/issues/4905 -#if Z3_VERSION_INT >= GET_VERSION_INT(4,8,0) - z3::expr val_e = exprData.context.fpa_val(static_cast(value)); -#else - z3::expr val_e = exprData.context.real_val(value); -#endif // Z3_VERSION_INT - solver.add(e == val_e); - return solver.check() != z3::unsat; - } catch (const z3::exception &exception) { - std::cerr << "z3: " << exception << std::endl; - return true; // Safe option is to return true - } catch (const ExprData::BailoutValueException &) { - return true; // Safe option is to return true - } catch (const ExprEngineException &) { - return true; // Safe option is to return true - } -#else - // The value may or may not be in range - return false; -#endif -} - -bool ExprEngine::FloatRange::isGreaterThan(const DataBase *dataBase, int value) const -{ - if (value < minValue || value > maxValue) - return false; - - const Data *data = dynamic_cast(dataBase); - if (data->constraints.empty()) - return true; - if (MathLib::isFloat(name)) - return value > MathLib::toDoubleNumber(name); -#ifdef USE_Z3 - // Check the value against the constraints - ExprData exprData; - z3::solver solver(exprData.context); - try { - z3::expr e = exprData.addFloat(name); - exprData.addConstraints(solver, data); - exprData.addAssertions(solver); - solver.add(e > value); - return solver.check() == z3::sat; - } catch (const z3::exception &exception) { - std::cerr << "z3: " << exception << std::endl; - return true; // Safe option is to return true - } catch (const ExprData::BailoutValueException &) { - return true; // Safe option is to return true - } catch (const ExprEngineException &) { - return true; // Safe option is to return true - } -#else - // The value may or may not be in range - return false; -#endif -} - -bool ExprEngine::FloatRange::isLessThan(const DataBase *dataBase, int value) const -{ - if (value < minValue || value > maxValue) - return false; - - const Data *data = dynamic_cast(dataBase); - if (data->constraints.empty()) - return true; - if (MathLib::isFloat(name)) - return value < MathLib::toDoubleNumber(name); -#ifdef USE_Z3 - // Check the value against the constraints - ExprData exprData; - z3::solver solver(exprData.context); - try { - z3::expr e = exprData.addFloat(name); - exprData.addConstraints(solver, data); - exprData.addAssertions(solver); - solver.add(e < value); - return solver.check() == z3::sat; - } catch (const z3::exception &exception) { - std::cerr << "z3: " << exception << std::endl; - return true; // Safe option is to return true - } catch (const ExprData::BailoutValueException &) { - return true; // Safe option is to return true - } catch (const ExprEngineException &) { - return true; // Safe option is to return true - } -#else - // The value may or may not be in range - return false; -#endif -} - - -bool ExprEngine::BinOpResult::isEqual(const ExprEngine::DataBase *dataBase, int value) const -{ -#ifdef USE_Z3 - try { - ExprData exprData; - z3::solver solver(exprData.context); - z3::expr e = exprData.getExpr(this); - exprData.addConstraints(solver, dynamic_cast(dataBase)); - exprData.addAssertions(solver); - solver.add(exprData.int_expr(e) == value); - return solver.check() == z3::sat; - } catch (const z3::exception &exception) { - std::cerr << "z3:" << exception << std::endl; - return true; // Safe option is to return true - } catch (const ExprData::BailoutValueException &) { - return true; // Safe option is to return true - } catch (const ExprEngineException &) { - return true; // Safe option is to return true - } -#else - (void)dataBase; - (void)value; - return false; -#endif -} - -bool ExprEngine::BinOpResult::isGreaterThan(const ExprEngine::DataBase *dataBase, int value) const -{ -#ifdef USE_Z3 - try { - ExprData exprData; - z3::solver solver(exprData.context); - z3::expr e = exprData.getExpr(this); - exprData.addConstraints(solver, dynamic_cast(dataBase)); - exprData.addAssertions(solver); - solver.add(e > value); - return solver.check() == z3::sat; - } catch (const z3::exception &exception) { - std::cerr << "z3:" << exception << std::endl; - return true; // Safe option is to return true - } catch (const ExprData::BailoutValueException &) { - return true; // Safe option is to return true - } catch (const ExprEngineException &) { - return true; // Safe option is to return true - } -#else - (void)dataBase; - (void)value; - return false; -#endif -} - -bool ExprEngine::BinOpResult::isLessThan(const ExprEngine::DataBase *dataBase, int value) const -{ -#ifdef USE_Z3 - try { - ExprData exprData; - z3::solver solver(exprData.context); - z3::expr e = exprData.getExpr(this); - exprData.addConstraints(solver, dynamic_cast(dataBase)); - exprData.addAssertions(solver); - solver.add(e < value); - return solver.check() == z3::sat; - } catch (const z3::exception &exception) { - std::cerr << "z3:" << exception << std::endl; - return true; // Safe option is to return true - } catch (const ExprData::BailoutValueException &) { - return true; // Safe option is to return true - } catch (const ExprEngineException &) { - return true; // Safe option is to return true - } -#else - (void)dataBase; - (void)value; - return false; -#endif -} - -bool ExprEngine::BinOpResult::isTrue(const ExprEngine::DataBase *dataBase) const -{ -#ifdef USE_Z3 - try { - ExprData exprData; - z3::solver solver(exprData.context); - z3::expr e = exprData.getExpr(this); - exprData.addConstraints(solver, dynamic_cast(dataBase)); - exprData.addAssertions(solver); - solver.add(exprData.int_expr(e) != 0); - return solver.check() == z3::sat; - } catch (const z3::exception &exception) { - std::cerr << "z3:" << exception << std::endl; - return true; // Safe option is to return true - } catch (const ExprData::BailoutValueException &) { - return true; // Safe option is to return true - } catch (const ExprEngineException &) { - return true; // Safe option is to return true - } -#else - (void)dataBase; - return false; -#endif -} - -std::string ExprEngine::BinOpResult::getExpr(ExprEngine::DataBase *dataBase) const -{ -#ifdef USE_Z3 - try { - ExprData exprData; - z3::solver solver(exprData.context); - z3::expr e = exprData.getExpr(this); - exprData.addConstraints(solver, dynamic_cast(dataBase)); - exprData.addAssertions(solver); - solver.add(e); - std::ostringstream os; - os << solver; - switch (solver.check()) { - case z3::sat: - os << "\nz3::sat\n"; - break; - case z3::unsat: - os << "\nz3::unsat\n"; - break; - case z3::unknown: - os << "\nz3::unknown\n"; - break; - } - return os.str(); - } catch (const z3::exception &exception) { - std::ostringstream os; - os << "\nz3:" << exception << "\n"; - return os.str(); - } -#else - (void)dataBase; - return ""; -#endif -} - - -// Todo: This is taken from ValueFlow and modified.. we should reuse it -static int getIntBitsFromValueType(const ValueType *vt, const cppcheck::Platform &platform) -{ - if (!vt) - return 0; - - switch (vt->type) { - case ValueType::Type::BOOL: - return 1; - case ValueType::Type::CHAR: - return platform.char_bit; - case ValueType::Type::SHORT: - return platform.short_bit; - case ValueType::Type::INT: - return platform.int_bit; - case ValueType::Type::LONG: - return platform.long_bit; - case ValueType::Type::LONGLONG: - return platform.long_long_bit; - default: - return 0; - } -} - -static ExprEngine::ValuePtr getValueRangeFromValueType(const std::string &name, const ValueType *vt, const cppcheck::Platform &platform) -{ - if (!vt || !(vt->isIntegral() || vt->isFloat()) || vt->pointer) - return ExprEngine::ValuePtr(); - - int bits = getIntBitsFromValueType(vt, platform); - if (bits == 1) { - return std::make_shared(name, 0, 1); - } else if (bits > 1) { - if (vt->sign == ValueType::Sign::UNSIGNED) { - return std::make_shared(name, 0, ((int128_t)1 << bits) - 1); - } else { - return std::make_shared(name, -((int128_t)1 << (bits - 1)), ((int128_t)1 << (bits - 1)) - 1); - } - } - - if (vt->isFloat()) - return std::make_shared(name, -std::numeric_limits::infinity(), std::numeric_limits::infinity()); - - return ExprEngine::ValuePtr(); -} - -static ExprEngine::ValuePtr getValueRangeFromValueType(const ValueType *valueType, Data &data) -{ - if (valueType && valueType->pointer) { - ExprEngine::ValuePtr val = std::make_shared(); - auto bufferSize = std::make_shared(data.getNewSymbolName(), 1, ExprEngine::ArrayValue::MAXSIZE); - return std::make_shared(data.getNewSymbolName(), bufferSize, val, true, true, false); - } - - if (!valueType || valueType->pointer) - return ExprEngine::ValuePtr(); - if (valueType->container) { - ExprEngine::ValuePtr value; - if (valueType->container->stdStringLike) - value = std::make_shared(data.getNewSymbolName(), -128, 127); - else if (valueType->containerTypeToken) { - ValueType vt = ValueType::parseDecl(valueType->containerTypeToken, data.settings); - value = getValueRangeFromValueType(&vt, data); - } else - return ExprEngine::ValuePtr(); - auto bufferSize = std::make_shared(data.getNewSymbolName(), 0, ExprEngine::ArrayValue::MAXSIZE); - return std::make_shared(data.getNewSymbolName(), bufferSize, value, false, false, false); - } - return getValueRangeFromValueType(data.getNewSymbolName(), valueType, *data.settings); -} - -static void call(const std::vector &callbacks, const Token *tok, ExprEngine::ValuePtr value, Data *dataBase) -{ - if (value) { - for (const ExprEngine::Callback& f : callbacks) { - try { - f(tok, *value, dataBase); - } catch (const ExprEngineException &e) { - throw ExprEngineException(tok, e.what); - } - } - } -} - -static ExprEngine::ValuePtr executeExpression(const Token *tok, Data &data); -static ExprEngine::ValuePtr executeExpression1(const Token *tok, Data &data); -static std::string execute(const Token *start, const Token *end, Data &data); - -static ExprEngine::ValuePtr calculateArrayIndex(const Token *tok, Data &data, const ExprEngine::ArrayValue &arrayValue) -{ - int nr = 1; - const Token *tok2 = tok; - while (Token::simpleMatch(tok2->astOperand1(), "[")) { - tok2 = tok2->astOperand1(); - nr++; - } - - ExprEngine::ValuePtr totalIndex; - ExprEngine::ValuePtr dim; - while (Token::simpleMatch(tok, "[")) { - auto rawIndex = executeExpression(tok->astOperand2(), data); - - ExprEngine::ValuePtr index; - if (dim) - index = simplifyValue(std::make_shared("*", dim, rawIndex)); - else - index = rawIndex; - - if (!totalIndex) - totalIndex = index; - else - totalIndex = simplifyValue(std::make_shared("+", index, totalIndex)); - - if (arrayValue.size.size() >= nr) { - if (arrayValue.size[nr-1]) { - if (!dim) - dim = arrayValue.size[nr-1]; - else - dim = simplifyValue(std::make_shared("*", dim, arrayValue.size[nr-1])); - } - } - - nr--; - tok = tok->astOperand1(); - } - - return totalIndex; -} - -static ExprEngine::ValuePtr executeReturn(const Token *tok, Data &data) -{ - ExprEngine::ValuePtr retval = executeExpression(tok->astOperand1(), data); - call(data.callbacks, tok, retval, &data); - return retval; -} - -static ExprEngine::ValuePtr truncateValue(ExprEngine::ValuePtr val, const ValueType *valueType, Data &data) -{ - if (!valueType) - return val; - if (valueType->pointer != 0) - return val; - if (!valueType->isIntegral()) - return val; // TODO - - int bits = getIntBitsFromValueType(valueType, *data.settings); - if (bits == 0) - // TODO - return val; - - if (auto range = std::dynamic_pointer_cast(val)) { - if (range->minValue == range->maxValue) { - int128_t newValue = truncateInt(range->minValue, bits, valueType->sign == ValueType::Sign::SIGNED ? 's' : 'u'); - if (newValue == range->minValue) - return val; - return std::make_shared(ExprEngine::str(newValue), newValue, newValue); - } - if (auto typeRange = getValueRangeFromValueType("", valueType, *data.settings)) { - auto typeIntRange = std::dynamic_pointer_cast(typeRange); - if (typeIntRange) { - if (range->minValue >= typeIntRange->minValue && range->maxValue <= typeIntRange->maxValue) - return val; - } - } - - return std::make_shared(data.getNewSymbolName(), val, bits, valueType->sign == ValueType::Sign::SIGNED ? 's' : 'u'); - } - // TODO - return val; -} - -static void assignExprValue(const Token *expr, ExprEngine::ValuePtr value, Data &data) -{ - if (!expr) - return; - if (expr->varId() > 0) { - data.assignValue(expr, expr->varId(), value); - } else if (expr->str() == "[") { - // Find array token - const Token *arrayToken = expr; - while (Token::simpleMatch(arrayToken, "[")) - arrayToken = arrayToken->astOperand1(); - if (!arrayToken) - return; - if (auto arrayValue = data.getArrayValue(arrayToken)) { - // Is it array initialization? - if (arrayToken->variable() && arrayToken->variable()->nameToken() == arrayToken) { - if (value->type == ExprEngine::ValueType::StringLiteralValue) - arrayValue->assign(ExprEngine::ValuePtr(), value); - } else { - auto indexValue = calculateArrayIndex(expr, data, *arrayValue); - bool loopAssign = false; - if (auto loopValue = std::dynamic_pointer_cast(indexValue)) { - if (loopValue->loopScope == expr->scope()) { - loopAssign = true; - for (auto i = loopValue->minValue; i <= loopValue->maxValue; ++i) - arrayValue->assign(std::make_shared(ExprEngine::str(i), i, i), value); - } - } - if (!loopAssign) - arrayValue->assign(indexValue, value); - } - } else { - const Token * const indexToken = expr->astOperand2(); - auto indexValue = executeExpression(indexToken, data); - call(data.callbacks, indexToken, indexValue, &data); - } - } else if (expr->isUnaryOp("*")) { - auto pval = executeExpression(expr->astOperand1(), data); - if (pval && pval->type == ExprEngine::ValueType::AddressOfValue) { - auto val = std::dynamic_pointer_cast(pval); - if (val) - data.assignValue(expr, val->varId, value); - } else if (pval && pval->type == ExprEngine::ValueType::ArrayValue) { - auto arrayValue = std::dynamic_pointer_cast(pval); - auto indexValue = std::make_shared("0", 0, 0); - arrayValue->assign(indexValue, value); - } else if (pval && pval->type == ExprEngine::ValueType::BinOpResult) { - auto b = std::dynamic_pointer_cast(pval); - if (b && b->binop == "+") { - std::shared_ptr arr; - ExprEngine::ValuePtr offset; - if (b->op1->type == ExprEngine::ValueType::ArrayValue) { - arr = std::dynamic_pointer_cast(b->op1); - offset = b->op2; - } else { - arr = std::dynamic_pointer_cast(b->op2); - offset = b->op1; - } - if (arr && offset) { - arr->assign(offset, value); - } - } - } - } else if (Token::Match(expr, ". %name%")) { - auto structVal = executeExpression(expr->astOperand1(), data); - if (structVal && structVal->type == ExprEngine::ValueType::StructValue) - data.assignStructMember(expr, &*std::static_pointer_cast(structVal), expr->next()->str(), value); - } -} - - -static ExprEngine::ValuePtr executeAssign(const Token *tok, Data &data) -{ - ExprEngine::ValuePtr rhsValue = executeExpression(tok->astOperand2(), data); - - if (!rhsValue) { - const ValueType * const vt1 = tok->astOperand1() ? tok->astOperand1()->valueType() : nullptr; - const ValueType * const vt2 = tok->astOperand2() ? tok->astOperand2()->valueType() : nullptr; - - rhsValue = getValueRangeFromValueType(vt1, data); - if (!rhsValue && vt2 && vt2->pointer == 0) { - rhsValue = getValueRangeFromValueType(vt2, data); - if (rhsValue) - call(data.callbacks, tok->astOperand2(), rhsValue, &data); - } - if (!rhsValue) - rhsValue = std::make_shared(); - } - - ExprEngine::ValuePtr assignValue; - if (tok->str() == "=") - assignValue = rhsValue; - else { - // "+=" => "+" - std::string binop(tok->str()); - binop = binop.substr(0, binop.size() - 1); - ExprEngine::ValuePtr lhsValue = executeExpression(tok->astOperand1(), data); - assignValue = simplifyValue(std::make_shared(binop, lhsValue, rhsValue)); - } - - const Token *lhsToken = tok->astOperand1(); - if (lhsToken) - assignValue = truncateValue(assignValue, lhsToken->valueType(), data); - call(data.callbacks, tok, assignValue, &data); - - assignExprValue(lhsToken, assignValue, data); - - return assignValue; -} - -static ExprEngine::ValuePtr executeIncDec(const Token *tok, Data &data) -{ - ExprEngine::ValuePtr beforeValue = executeExpression(tok->astOperand1(), data); - ExprEngine::ValuePtr assignValue = simplifyValue(std::make_shared(tok->str().substr(0,1), beforeValue, std::make_shared("1", 1, 1))); - assignExprValue(tok->astOperand1(), assignValue, data); - auto retVal = (precedes(tok, tok->astOperand1())) ? assignValue : beforeValue; - auto binOp = std::dynamic_pointer_cast(retVal); - if (binOp && !binOp->op1) - retVal.reset(); - call(data.callbacks, tok, retVal, &data); - return retVal; -} - -#ifdef USE_Z3 -static void checkContract(Data &data, const Token *tok, const Function *function, const std::vector &argValues) -{ -#ifdef CONTRACT - ExprData exprData; - z3::solver solver(exprData.context); - try { - // Invert contract, we want to know if the contract might not be met - try { - solver.add(z3::ite(exprData.getConstraintExpr(data.executeContract(function, executeExpression1)), exprData.context.bool_val(false), exprData.context.bool_val(true))); - } catch (const ExprData::BailoutValueException &) { - throw ExprEngineException(tok, "Internal error: Bailout value used"); - } - - bool bailoutValue = false; - for (nonneg int i = 0; i < argValues.size(); ++i) { - const Variable *argvar = function->getArgumentVar(i); - if (!argvar || !argvar->nameToken()) - continue; - - ExprEngine::ValuePtr argValue = argValues[i]; - if (!argValue || argValue->type == ExprEngine::ValueType::BailoutValue) { - bailoutValue = true; - break; - } - - if (argValue && argValue->type == ExprEngine::ValueType::IntRange) { - solver.add(exprData.getExpr(data.getValue(argvar->declarationId(), nullptr, nullptr)) == exprData.getExpr(argValue)); - } - } - - if (!bailoutValue) { - for (const auto &constraint : data.constraints) - solver.add(exprData.getConstraintExpr(constraint)); - - exprData.addAssertions(solver); - - // Log solver expressions for debugging/testing purposes - std::ostringstream os; - os << solver; - data.trackCheckContract(tok, os.str()); - } - - if (bailoutValue || solver.check() == z3::sat) { - const char id[] = "bughuntingFunctionCall"; - const auto contractIt = data.settings->functionContracts.find(function->fullName()); - const std::string functionName = contractIt->first; - const std::string functionExpects = contractIt->second; - data.reportError(tok, - Severity::SeverityType::error, - id, - "Function '" + function->name() + "' is called, can not determine that its contract '" + functionExpects + "' is always met.", - CWE(0), - false, - bailoutValue, - functionName); - } - } catch (const z3::exception &exception) { - std::cerr << "z3: " << exception << std::endl; - } catch (const ExprEngineException &) { - const char id[] = "internalErrorInExprEngine"; - const auto contractIt = data.settings->functionContracts.find(function->fullName()); - const std::string functionName = contractIt->first; - const std::string functionExpects = contractIt->second; - data.reportError(tok, - Severity::SeverityType::error, - id, - "Function '" + function->name() + "' is called, can not determine that its contract '" + functionExpects + "' is always met.", - CWE(0), - false, - true, - functionName); - } -#endif -} -#endif - -static ExprEngine::ValuePtr executeFunctionCall(const Token *tok, Data &data) -{ - if (Token::simpleMatch(tok->previous(), "sizeof (")) { - ExprEngine::ValuePtr retVal; - if (tok->hasKnownIntValue()) { - const MathLib::bigint value = tok->getKnownIntValue(); - retVal = std::make_shared(std::to_string(value), value, value); - } else { - retVal = std::make_shared(data.getNewSymbolName(), 1, 0x7fffffff); - } - call(data.callbacks, tok, retVal, &data); - return retVal; - } - - bool hasBody = tok->astOperand1()->function() && tok->astOperand1()->function()->hasBody(); - if (hasBody) { - const Scope *functionScope = tok->scope(); - while (functionScope->isExecutable() && functionScope->type != Scope::ScopeType::eFunction) - functionScope = functionScope->nestedIn; - if (functionScope == tok->astOperand1()->function()->functionScope) - hasBody = false; - for (const auto &errorPathItem: data.errorPath) { - if (errorPathItem.first == tok) { - hasBody = false; - break; - } - } - } - - const std::vector &argTokens = getArguments(tok); - std::vector argValues; - for (const Token *argtok : argTokens) { - auto val = hasBody ? executeExpression1(argtok, data) : executeExpression(argtok, data); - argValues.push_back(val); - if (hasBody) - continue; - if (!argtok->valueType() || (argtok->valueType()->constness & 1) == 1) - continue; - if (auto arrayValue = std::dynamic_pointer_cast(val)) { - ValueType vt(*argtok->valueType()); - vt.pointer = 0; - auto anyVal = getValueRangeFromValueType(&vt, data); - arrayValue->assign(ExprEngine::ValuePtr(), anyVal); - } else if (auto addressOf = std::dynamic_pointer_cast(val)) { - ValueType vt(*argtok->valueType()); - vt.pointer = 0; - if (vt.isIntegral() && argtok->valueType()->pointer == 1) - data.assignValue(argtok, addressOf->varId, getValueRangeFromValueType(&vt, data)); - } - } - - call(data.callbacks, tok, std::make_shared(argValues), &data); - - if (tok->astOperand1()->function()) { - const Function *function = tok->astOperand1()->function(); - const std::string &functionName = function->fullName(); -#ifdef CONTRACT - const auto contractIt = data.settings->functionContracts.find(functionName); - if (contractIt != data.settings->functionContracts.end()) { -#ifdef USE_Z3 - checkContract(data, tok, function, argValues); -#endif - } else if (!argValues.empty()) { - bool bailout = false; - for (const auto &v: argValues) - bailout |= (v && v->type == ExprEngine::ValueType::BailoutValue); - if (!bailout) - data.addMissingContract(functionName); - } -#endif - - // Execute subfunction.. - if (hasBody) { - const Scope * const functionScope = function->functionScope; - int argnr = 0; - std::map refs; - for (const Variable &arg: function->argumentList) { - if (argnr < argValues.size() && arg.declarationId() > 0) { - if (arg.isReference()) - refs[argTokens[argnr]] = arg.declarationId(); - else - argValues[argnr] = translateUninitValueToRange(argValues[argnr], arg.valueType(), data); - data.assignValue(function->functionScope->bodyStart, arg.declarationId(), argValues[argnr]); - } - // TODO default values! - argnr++; - } - data.contractConstraints(function, executeExpression1); - data.errorPath.push_back(ErrorPathItem(tok, "Calling " + function->name())); - try { - data.load(execute(functionScope->bodyStart, functionScope->bodyEnd, data)); - for (auto ref: refs) { - auto v = data.getValue(ref.second, nullptr, nullptr); - assignExprValue(ref.first, v, data); - } - } catch (ExprEngineException &e) { - data.errorPath.pop_back(); - e.tok = tok; - throw e; - } - data.errorPath.pop_back(); - } - } - - else if (const auto *f = data.settings->library.getAllocFuncInfo(tok->astOperand1())) { - if (!f->initData) { - const std::string name = data.getNewSymbolName(); - auto size = std::make_shared(data.getNewSymbolName(), 1, MAX_BUFFER_SIZE); - auto val = std::make_shared(); - auto result = std::make_shared(name, size, val, false, false, false); - call(data.callbacks, tok, result, &data); - data.functionCall(); - return result; - } - } - - auto result = getValueRangeFromValueType(tok->valueType(), data); - call(data.callbacks, tok, result, &data); - data.functionCall(); - return result; -} - -static ExprEngine::ValuePtr executeArrayIndex(const Token *tok, Data &data) -{ - if (tok->tokType() == Token::eLambda) - throw ExprEngineException(tok, "FIXME: lambda"); - const Token *tok2 = tok; - while (Token::simpleMatch(tok2->astOperand1(), "[")) - tok2 = tok2->astOperand1(); - auto arrayValue = data.getArrayValue(tok2->astOperand1()); - if (arrayValue) { - auto indexValue = calculateArrayIndex(tok, data, *arrayValue); - auto conditionalValues = arrayValue->read(indexValue); - for (const auto& value: conditionalValues) - call(data.callbacks, tok, value.second, &data); - if (conditionalValues.size() == 1 && !conditionalValues[0].first) - return conditionalValues[0].second; - return std::make_shared(data.getNewSymbolName(), conditionalValues); - } - - // TODO: Pointer value.. - executeExpression(tok->astOperand1(), data); - executeExpression(tok->astOperand2(), data); - - return ExprEngine::ValuePtr(); -} - -static ExprEngine::ValuePtr executeCast(const Token *tok, Data &data) -{ - const Token *expr = tok->astOperand2() ? tok->astOperand2() : tok->astOperand1(); - - auto val = executeExpression(expr, data); - - if (expr->valueType() && expr->valueType()->type == ::ValueType::Type::VOID && expr->valueType()->pointer > 0) { - if (!tok->valueType() || expr->valueType()->pointer < tok->valueType()->pointer) - return std::make_shared(); - - auto range = std::make_shared(); - - if (tok->valueType()->pointer == 0) - return range; - - bool uninitPointer = false, nullPointer = false; - if (val && val->type == ExprEngine::ValueType::ArrayValue) { - nullPointer = std::static_pointer_cast(val)->nullPointer; - uninitPointer = std::static_pointer_cast(val)->uninitPointer; - } - - auto bufferSize = std::make_shared(data.getNewSymbolName(), 1, MAX_BUFFER_SIZE); - return std::make_shared(data.getNewSymbolName(), bufferSize, range, true, nullPointer, uninitPointer); - } - - if (val) { - // TODO: Cast this.. - call(data.callbacks, tok, val, &data); - return val; - } - - val = getValueRangeFromValueType(tok->valueType(), data); - call(data.callbacks, tok, val, &data); - return val; -} - -static ExprEngine::ValuePtr executeDot(const Token *tok, Data &data) -{ - if (!tok->astOperand1()) { - auto v = std::make_shared(); - call(data.callbacks, tok, v, &data); - return v; - } - std::shared_ptr structValue = std::dynamic_pointer_cast(executeExpression(tok->astOperand1(), data)); - if (!structValue) { - if (tok->originalName() == "->") { - std::shared_ptr pointerValue = std::dynamic_pointer_cast(data.getValue(tok->astOperand1()->varId(), nullptr, nullptr)); - if (pointerValue && pointerValue->pointer && !pointerValue->data.empty()) { - call(data.callbacks, tok->astOperand1(), pointerValue, &data); - auto indexValue = std::make_shared("0", 0, 0); - ExprEngine::ValuePtr ret; - for (const auto& val: pointerValue->read(indexValue)) { - structValue = std::dynamic_pointer_cast(val.second); - if (structValue) { - auto memberValue = structValue->getValueOfMember(tok->astOperand2()->str()); - call(data.callbacks, tok, memberValue, &data); - if (!ret) - ret = memberValue; - } - } - return ret; - } else { - call(data.callbacks, tok->astOperand1(), data.getValue(tok->astOperand1()->varId(), nullptr, nullptr), &data); - } - } - - auto v = getValueRangeFromValueType(tok->valueType(), data); - if (!v) - v = std::make_shared(); - call(data.callbacks, tok, v, &data); - return v; - } - call(data.callbacks, tok->astOperand1(), structValue, &data); - ExprEngine::ValuePtr memberValue = structValue->getValueOfMember(tok->astOperand2()->str()); - call(data.callbacks, tok, memberValue, &data); - return memberValue; -} - -static void streamReadSetValue(const Token *tok, Data &data) -{ - if (!tok || !tok->valueType()) - return; - if (tok->varId() > 0 && tok->valueType()->pointer) { - const auto oldValue = data.getValue(tok->varId(), tok->valueType(), tok); - if (oldValue && (oldValue->isUninit(&data))) - call(data.callbacks, tok, oldValue, &data); - } - auto rangeValue = getValueRangeFromValueType(tok->valueType(), data); - if (rangeValue) - assignExprValue(tok, rangeValue, data); -} - -static ExprEngine::ValuePtr executeStreamRead(const Token *tok, Data &data) -{ - tok = tok->astOperand2(); - while (Token::simpleMatch(tok, ">>")) { - streamReadSetValue(tok->astOperand1(), data); - tok = tok->astOperand2(); - } - streamReadSetValue(tok, data); - return ExprEngine::ValuePtr(); -} - -static ExprEngine::ValuePtr executeBinaryOp(const Token *tok, Data &data) -{ - ExprEngine::ValuePtr v1 = executeExpression(tok->astOperand1(), data); - ExprEngine::ValuePtr v2; - - if (tok->str() == "?") { - if (tok->astOperand1()->hasKnownIntValue()) { - if (tok->astOperand1()->getKnownIntValue()) - v2 = executeExpression(tok->astOperand2()->astOperand1(), data); - else - v2 = executeExpression(tok->astOperand2()->astOperand2(), data); - call(data.callbacks, tok, v2, &data); - return v2; - } - - Data trueData(data); - trueData.addConstraint(v1, true); - auto trueValue = simplifyValue(executeExpression(tok->astOperand2()->astOperand1(), trueData)); - - Data falseData(data); - falseData.addConstraint(v1, false); - auto falseValue = simplifyValue(executeExpression(tok->astOperand2()->astOperand2(), falseData)); - - auto result = simplifyValue(std::make_shared("?", v1, std::make_shared(":", trueValue, falseValue))); - call(data.callbacks, tok, result, &data); - return result; - - } else if (tok->str() == "&&" || tok->str() == "||") { - Data data2(data); - data2.addConstraint(v1, tok->str() == "&&"); - v2 = executeExpression(tok->astOperand2(), data2); - } else { - v2 = executeExpression(tok->astOperand2(), data); - } - - if (v1 && v2) { - auto result = simplifyValue(std::make_shared(tok->str(), v1, v2)); - call(data.callbacks, tok, result, &data); - return result; - } - if (tok->str() == "&&" && (v1 || v2)) { - auto result = v1 ? v1 : v2; - call(data.callbacks, tok, result, &data); - return result; - } - return ExprEngine::ValuePtr(); -} - -static ExprEngine::ValuePtr executeAddressOf(const Token *tok, Data &data) -{ - auto addr = std::make_shared(data.getNewSymbolName(), tok->astOperand1()->varId()); - call(data.callbacks, tok, addr, &data); - return addr; -} - -static ExprEngine::ValuePtr executeDeref(const Token *tok, Data &data) -{ - ExprEngine::ValuePtr pval = executeExpression(tok->astOperand1(), data); - if (!pval) { - auto v = getValueRangeFromValueType(tok->valueType(), data); - if (tok->astOperand1()->varId()) { - pval = std::make_shared(data.getNewSymbolName(), ExprEngine::ValuePtr(), v, true, false, false); - data.assignValue(tok->astOperand1(), tok->astOperand1()->varId(), pval); - } - call(data.callbacks, tok, v, &data); - return v; - } - auto addressOf = std::dynamic_pointer_cast(pval); - if (addressOf) { - auto val = data.getValue(addressOf->varId, tok->valueType(), tok); - call(data.callbacks, tok, val, &data); - return val; - } - auto pointer = std::dynamic_pointer_cast(pval); - if (pointer) { - auto indexValue = std::make_shared("0", 0, 0); - auto conditionalValues = pointer->read(indexValue); - for (const auto& value: conditionalValues) - call(data.callbacks, tok, value.second, &data); - if (conditionalValues.size() == 1 && !conditionalValues[0].first) - return conditionalValues[0].second; - return std::make_shared(data.getNewSymbolName(), conditionalValues); - } - return ExprEngine::ValuePtr(); -} - -static ExprEngine::ValuePtr executeNot(const Token *tok, Data &data) -{ - ExprEngine::ValuePtr v = executeExpression(tok->astOperand1(), data); - if (!v) - return v; - ExprEngine::ValuePtr zero = std::make_shared("0", 0, 0); - auto result = simplifyValue(std::make_shared("==", v, zero)); - call(data.callbacks, tok, result, &data); - return result; -} - -static ExprEngine::ValuePtr executeVariable(const Token *tok, Data &data) -{ - auto val = data.getValue(tok->varId(), tok->valueType(), tok); - call(data.callbacks, tok, val, &data); - return val; -} - -static ExprEngine::ValuePtr executeKnownMacro(const Token *tok, Data &data) -{ - const auto intval = tok->getKnownIntValue(); - auto val = std::make_shared(std::to_string(intval), intval, intval); - call(data.callbacks, tok, val, &data); - return val; -} - -static ExprEngine::ValuePtr executeNumber(const Token *tok, Data &data) -{ - if (tok->valueType()->isFloat()) { - long double value = MathLib::toDoubleNumber(tok->str()); - auto v = std::make_shared(tok->str(), value, value); - call(data.callbacks, tok, v, &data); - return v; - } - int128_t value = MathLib::toLongNumber(tok->str()); - auto v = std::make_shared(tok->str(), value, value); - call(data.callbacks, tok, v, &data); - return v; -} - -static ExprEngine::ValuePtr executeStringLiteral(const Token *tok, Data &data) -{ - const std::string& s = tok->str(); - return std::make_shared(data.getNewSymbolName(), s.substr(1, s.size()-2)); -} - -static ExprEngine::ValuePtr executeExpression1(const Token *tok, Data &data) -{ - if (Settings::terminated()) - throw TerminateExpression(); - - if (tok->str() == "return") - return executeReturn(tok, data); - - if (tok->isAssignmentOp()) - // TODO: Handle more operators - return executeAssign(tok, data); - - if (tok->tokType() == Token::Type::eIncDecOp) - return executeIncDec(tok, data); - - if (tok->astOperand1() && tok->astOperand2() && tok->str() == "[") - return executeArrayIndex(tok, data); - - if (tok->str() == "(") { - if (!tok->isCast()) - return executeFunctionCall(tok, data); - return executeCast(tok, data); - } - - if (tok->str() == ".") - return executeDot(tok, data); - - if (tok->str() == "::" && tok->hasKnownIntValue()) { // TODO handle :: better - auto v = tok->getKnownIntValue(); - return std::make_shared(std::to_string(v), v, v); - } - - if (data.tokenizer->isCPP() && tok->str() == ">>" && !tok->astParent() && tok->isBinaryOp() && Token::Match(tok->astOperand1(), "%name%|::")) - return executeStreamRead(tok, data); - - if (tok->astOperand1() && tok->astOperand2()) - return executeBinaryOp(tok, data); - - if (tok->isUnaryOp("&") && Token::Match(tok->astOperand1(), "%var%")) - return executeAddressOf(tok, data); - - if (tok->isUnaryOp("*")) - return executeDeref(tok, data); - - if (tok->isUnaryOp("!")) - return executeNot(tok, data); - - if (tok->varId()) - return executeVariable(tok, data); - - if (tok->isName() && tok->hasKnownIntValue()) - return executeKnownMacro(tok, data); - - if (tok->isNumber() || tok->tokType() == Token::Type::eChar) - return executeNumber(tok, data); - - if (tok->tokType() == Token::Type::eString) - return executeStringLiteral(tok, data); - - return ExprEngine::ValuePtr(); -} - -static ExprEngine::ValuePtr executeExpression(const Token *tok, Data &data) -{ - return translateUninitValueToRange(executeExpression1(tok, data), tok->valueType(), data); -} - -static ExprEngine::ValuePtr createVariableValue(const Variable &var, Data &data); - -static std::tuple checkConditionBranches(const ExprEngine::ValuePtr &condValue, const Data &data) -{ - bool canBeFalse = true; - bool canBeTrue = true; - if (auto b = std::dynamic_pointer_cast(condValue)) { - canBeFalse = b->isEqual(&data, 0); - canBeTrue = b->isTrue(&data); - } else if (auto i = std::dynamic_pointer_cast(condValue)) { - canBeFalse = i->isEqual(&data, 0); - canBeTrue = ExprEngine::BinOpResult("!=", i, std::make_shared("0", 0, 0)).isTrue(&data); - } else if (std::dynamic_pointer_cast(condValue)) { - canBeFalse = false; - canBeTrue = true; - } else if (auto f = std::dynamic_pointer_cast(condValue)) { - canBeFalse = f->isEqual(&data, 0); - canBeTrue = ExprEngine::BinOpResult("!=", f, std::make_shared("0.0", 0.0, 0.0)).isTrue(&data); - } - return std::make_tuple(canBeFalse, canBeTrue); -} - -static std::string execute(const Token *start, const Token *end, Data &data) -{ - if (data.recursion > 20) - // FIXME - return data.str(); - - // Update data.recursion - struct Recursion { - Recursion(int *var, int value) : var(var), value(value) { - *var = value + 1; - } - ~Recursion() { - if (*var >= value) *var = value; - } - int *var; - int value; - }; - Recursion updateRecursion(&data.recursion, data.recursion); - - const std::time_t stopTime = data.startTime + data.settings->bugHuntingCheckFunctionMaxTime; - - for (const Token *tok = start; tok != end; tok = tok->next()) { - if (Token::Match(tok, "[;{}]")) { - data.trackProgramState(tok); - if (tok->str() == ";") { - const Token *prev = tok->previous(); - while (prev && !Token::Match(prev, "[;{}]")) - prev = prev->previous(); - if (Token::Match(prev, "[;{}] return|throw")) - return data.str(); - } - while (Token::simpleMatch(tok, "} catch (") && Token::simpleMatch(tok->linkAt(2), ") {")) { - tok = tok->linkAt(2)->next()->link(); - } - if (std::time(nullptr) > stopTime) - return ""; - } - - if (Token::simpleMatch(tok, "__CPPCHECK_BAILOUT__ ;")) - // This is intended for testing - throw ExprEngineException(tok, "__CPPCHECK_BAILOUT__"); - - if (Token::simpleMatch(tok, "while (") && Token::simpleMatch(tok->linkAt(1), ") ;") && tok->next()->astOperand1()->hasKnownIntValue() && tok->next()->astOperand1()->getKnownIntValue() == 0) { - tok = tok->tokAt(4); - continue; - } - - if (tok->str() == "break") { - const Scope *scope = tok->scope(); - while (scope->type == Scope::eIf || scope->type == Scope::eElse) - scope = scope->nestedIn; - tok = scope->bodyEnd; - if (!precedes(tok,end)) - return data.str(); - } - - if (Token::simpleMatch(tok, "try {") && Token::simpleMatch(tok->linkAt(1), "} catch (")) { - const Token *catchTok = tok->linkAt(1); - while (Token::simpleMatch(catchTok, "} catch (")) { - Data catchData(data); - catchTok = catchTok->linkAt(2)->next(); - execute(catchTok, end, catchData); - catchTok = catchTok->link(); - } - } - - // Variable declaration.. - if (tok->variable() && tok->variable()->nameToken() == tok) { - if (Token::Match(tok, "%varid% ; %varid% =", tok->varId())) { - // if variable is not used in assignment rhs then we do not need to create a "confusing" variable value.. - bool foundInRhs = false; - visitAstNodes(tok->tokAt(3)->astOperand2(), [&](const Token *rhs) { - if (rhs->varId()==tok->varId()) { - foundInRhs = true; - return ChildrenToVisit::done; - } - return ChildrenToVisit::op1_and_op2; - }); - if (!foundInRhs) { - tok = tok->tokAt(2); - continue; - } - data.assignValue(tok, tok->varId(), createVariableValue(*tok->variable(), data)); - } else if (tok->variable()->isArray()) { - data.assignValue(tok, tok->varId(), std::make_shared(&data, tok->variable())); - if (Token::Match(tok, "%name% [")) - tok = tok->linkAt(1); - } else if (Token::Match(tok, "%var% ;")) - data.assignValue(tok, tok->varId(), createVariableValue(*tok->variable(), data)); - } else if (!tok->astParent() && (tok->astOperand1() || tok->astOperand2())) { - executeExpression(tok, data); - if (Token::Match(tok, "throw|return")) - return data.str(); - } - - else if (Token::simpleMatch(tok, "if (")) { - const Token *cond = tok->next()->astOperand2(); // TODO: C++17 condition - const ExprEngine::ValuePtr condValue = executeExpression(cond, data); - - bool canBeFalse, canBeTrue; - std::tie(canBeFalse, canBeTrue) = checkConditionBranches(condValue, data); - - Data &thenData(data); - Data elseData(data); - if (canBeFalse && canBeTrue) { // Avoid that constraints are overspecified - thenData.addConstraint(condValue, true); - elseData.addConstraint(condValue, false); - } - - Data::ifSplit(tok, thenData, elseData); - - const Token *thenStart = tok->linkAt(1)->next(); - const Token *thenEnd = thenStart->link(); - - const Token *exceptionToken = nullptr; - std::string exceptionMessage; - auto exec = [&](const Token *tok1, const Token *tok2, Data& data) { - try { - execute(tok1, tok2, data); - } catch (ExprEngineException &e) { - if (!exceptionToken || (e.tok && precedes(e.tok, exceptionToken))) { - exceptionToken = e.tok; - exceptionMessage = e.what; - } - } - }; - - if (canBeTrue) - exec(thenStart->next(), end, thenData); - - if (canBeFalse) { - if (Token::simpleMatch(thenEnd, "} else {")) { - const Token *elseStart = thenEnd->tokAt(2); - exec(elseStart->next(), end, elseData); - } else { - exec(thenEnd, end, elseData); - } - } - - if (exceptionToken) - throw ExprEngineException(exceptionToken, exceptionMessage); - - return (canBeTrue ? thenData.str() : std::string()) + - (canBeFalse ? elseData.str() : std::string()); - } - - else if (Token::simpleMatch(tok, "switch (")) { - auto condValue = executeExpression(tok->next()->astOperand2(), data); // TODO: C++17 condition - const Token *bodyStart = tok->linkAt(1)->next(); - const Token *bodyEnd = bodyStart->link(); - const Token *defaultStart = nullptr; - Data defaultData(data); - const Token *exceptionToken = nullptr; - std::string exceptionMessage; - std::ostringstream ret; - auto exec = [&](const Token *tok1, const Token *tok2, Data& data) { - try { - execute(tok1, tok2, data); - ret << data.str(); - } catch (ExprEngineException &e) { - if (!exceptionToken || (e.tok && precedes(e.tok, exceptionToken))) { - exceptionToken = e.tok; - exceptionMessage = e.what; - } - } - }; - for (const Token *tok2 = bodyStart->next(); tok2 != bodyEnd; tok2 = tok2->next()) { - if (tok2->str() == "{") - tok2 = tok2->link(); - else if (Token::Match(tok2, "case %char%|%num% :")) { - const MathLib::bigint caseValue1 = tok2->next()->getKnownIntValue(); - auto caseValue = std::make_shared(MathLib::toString(caseValue1), caseValue1, caseValue1); - Data caseData(data); - caseData.addConstraint(condValue, caseValue, true); - defaultData.addConstraint(condValue, caseValue, false); - exec(tok2->tokAt(2), end, caseData); - } else if (Token::Match(tok2, "case %name% :") && !Token::Match(tok2->tokAt(3), ";| case")) { - Data caseData(data); - exec(tok2->tokAt(2), end, caseData); - } else if (Token::simpleMatch(tok2, "default :")) - defaultStart = tok2; - } - exec(defaultStart ? defaultStart : bodyEnd, end, defaultData); - if (exceptionToken) - throw ExprEngineException(exceptionToken, exceptionMessage); - return ret.str(); - } - - if (Token::simpleMatch(tok, "for (")) { - nonneg int varid; - bool hasKnownInitValue, partialCond; - MathLib::bigint initValue, stepValue, lastValue; - if (extractForLoopValues(tok, &varid, &hasKnownInitValue, &initValue, &partialCond, &stepValue, &lastValue) && hasKnownInitValue && !partialCond) { - auto loopValues = std::make_shared(data.getNewSymbolName(), initValue, lastValue); - data.assignValue(tok, varid, loopValues); - tok = tok->linkAt(1); - if (tok->next()) { - loopValues->loopScope = tok->next()->scope(); - // Check whether the condition expression is always false - if (initValue > lastValue) { - tok = tok->next()->link(); - } - } - continue; - } - } - - if (Token::Match(tok, "for|while (") && Token::simpleMatch(tok->linkAt(1), ") {")) { - const Token *cond = tok->next()->astOperand2(); - const ExprEngine::ValuePtr condValue = executeExpression(cond, data); - - bool canBeFalse = false, canBeTrue = true; - if (tok->str() == "while") - std::tie(canBeFalse, canBeTrue) = checkConditionBranches(condValue, data); - - Data &bodyData(data); - Data noexecData(data); - if (canBeFalse && canBeTrue) { // Avoid that constraints are overspecified - bodyData.addConstraint(condValue, true); - } - - Data::ifSplit(tok, bodyData, noexecData); - - const Token *bodyStart = tok->linkAt(1)->next(); - const Token *bodyEnd = bodyStart->link(); - - // TODO this is very rough code - if (canBeTrue) { - std::set changedVariables; - for (const Token *tok2 = tok; tok2 != bodyEnd; tok2 = tok2->next()) { - if (Token::Match(tok2, "%assign%")) { - const Token *lhs = tok2->astOperand1(); - while (Token::simpleMatch(lhs, "[")) - lhs = lhs->astOperand1(); - if (!lhs) - throw ExprEngineException(tok2, "Unhandled assignment in loop"); - if (Token::Match(lhs, ". %name% =|[") && Token::simpleMatch(lhs->astOperand1(), ".")) { - const Token *structToken = lhs; - while (Token::Match(structToken, ".|[")) - structToken = structToken->astOperand1(); - if (Token::Match(structToken, "%var%")) { - bodyData.assignValue(structToken, structToken->varId(), std::make_shared()); - changedVariables.insert(structToken->varId()); - continue; - } - } - if (Token::Match(lhs, ". %name% =|[") && lhs->astOperand1() && lhs->astOperand1()->valueType()) { - const Token *structToken = lhs->astOperand1(); - if (!structToken->valueType() || !structToken->varId()) - throw ExprEngineException(tok2, "Unhandled assignment in loop"); - const Scope *structScope = structToken->valueType()->typeScope; - if (!structScope) - throw ExprEngineException(tok2, "Unhandled assignment in loop"); - const std::string &memberName = tok2->previous()->str(); - ExprEngine::ValuePtr memberValue; - for (const Variable &member : structScope->varlist) { - if (memberName == member.name() && member.valueType()) { - memberValue = createVariableValue(member, bodyData); - break; - } - } - if (!memberValue) - throw ExprEngineException(tok2, "Unhandled assignment in loop"); - - ExprEngine::ValuePtr structVal1 = bodyData.getValue(structToken->varId(), structToken->valueType(), structToken); - if (!structVal1) - structVal1 = createVariableValue(*structToken->variable(), bodyData); - auto structVal = std::dynamic_pointer_cast(structVal1); - if (!structVal) { - // Handle pointer to a struct - if (auto structPtr = std::dynamic_pointer_cast(structVal1)) { - if (structPtr->pointer && !structPtr->data.empty()) { - auto indexValue = std::make_shared("0", 0, 0); - for (const auto &val: structPtr->read(indexValue)) { - structVal = std::dynamic_pointer_cast(val.second); - } - } - } - if (!structVal) - throw ExprEngineException(tok2, "Unhandled assignment in loop"); - } - - bodyData.assignStructMember(tok2, &*structVal, memberName, memberValue); - continue; - } - if (lhs->isUnaryOp("*") && lhs->astOperand1()->varId()) { - const Token *varToken = tok2->astOperand1()->astOperand1(); - ExprEngine::ValuePtr val = bodyData.getValue(varToken->varId(), varToken->valueType(), varToken); - if (val && val->type == ExprEngine::ValueType::ArrayValue) { - // Try to assign "any" value - auto arrayValue = std::dynamic_pointer_cast(val); - arrayValue->assign(std::make_shared("0", 0, 0), std::make_shared()); - continue; - } - } - if (!lhs->variable()) - throw ExprEngineException(tok2, "Unhandled assignment in loop"); - // give variable "any" value - int varid = lhs->varId(); - if (changedVariables.find(varid) != changedVariables.end()) - continue; - changedVariables.insert(varid); - auto oldValue = bodyData.getValue(varid, nullptr, nullptr); - if (oldValue && oldValue->isUninit(&bodyData)) - call(bodyData.callbacks, lhs, oldValue, &bodyData); - if (oldValue && oldValue->type == ExprEngine::ValueType::ArrayValue) { - // Try to assign "any" value - auto arrayValue = std::dynamic_pointer_cast(oldValue); - arrayValue->assign(std::make_shared(bodyData.getNewSymbolName(), 0, MAX_BUFFER_SIZE), std::make_shared()); - continue; - } - bodyData.assignValue(tok2, varid, getValueRangeFromValueType(lhs->valueType(), bodyData)); - continue; - } else if (Token::Match(tok2, "++|--") && tok2->astOperand1() && tok2->astOperand1()->variable()) { - // give variable "any" value - const Token *vartok = tok2->astOperand1(); - int varid = vartok->varId(); - if (changedVariables.find(varid) != changedVariables.end()) - continue; - changedVariables.insert(varid); - auto oldValue = bodyData.getValue(varid, nullptr, nullptr); - if (oldValue && oldValue->type == ExprEngine::ValueType::UninitValue) - call(bodyData.callbacks, tok2, oldValue, &bodyData); - bodyData.assignValue(tok2, varid, getValueRangeFromValueType(vartok->valueType(), bodyData)); - } - } - } - - const Token *exceptionToken = nullptr; - std::string exceptionMessage; - auto exec = [&](const Token *tok1, const Token *tok2, Data& data) { - try { - execute(tok1, tok2, data); - } catch (ExprEngineException &e) { - if (!exceptionToken || (e.tok && precedes(e.tok, exceptionToken))) { - exceptionToken = e.tok; - exceptionMessage = e.what; - } - } - }; - - if (canBeTrue) - exec(bodyStart->next(), end, bodyData); - if (canBeFalse) - exec(bodyEnd, end, noexecData); - - if (exceptionToken) - throw ExprEngineException(exceptionToken, exceptionMessage); - - return (canBeTrue ? bodyData.str() : std::string()) + - (canBeFalse ? noexecData.str() : std::string()); - } - - if (Token::simpleMatch(tok, "} else {")) - tok = tok->linkAt(2); - } - - return data.str(); -} - -void ExprEngine::executeAllFunctions(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings, const std::vector &callbacks, std::ostream &report) -{ - const SymbolDatabase *symbolDatabase = tokenizer->getSymbolDatabase(); - for (const Scope *functionScope : symbolDatabase->functionScopes) { - try { - executeFunction(functionScope, errorLogger, tokenizer, settings, callbacks, report); - } catch (const ExprEngineException &e) { - // FIXME.. there should not be exceptions - std::string functionName = functionScope->function->name(); - std::cout << "Verify: Aborted analysis of function '" << functionName << "':" << e.tok->linenr() << ": " << e.what << std::endl; - } catch (const std::exception &e) { - // FIXME.. there should not be exceptions - std::string functionName = functionScope->function->name(); - std::cout << "Verify: Aborted analysis of function '" << functionName << "': " << e.what() << std::endl; - } catch (const TerminateExpression &) { - break; - } - } -} - -static ExprEngine::ValuePtr createStructVal(const Token *tok, const Scope *structScope, bool uninitData, Data &data) -{ - if (!structScope) - return ExprEngine::ValuePtr(); - std::shared_ptr structValue = std::make_shared(data.getNewSymbolName()); - auto uninitValue = std::make_shared(); - for (const Variable &member : structScope->varlist) { - if (uninitData && !member.isInit()) { - if (member.isPointer()) { - structValue->member[member.name()] = uninitValue; - continue; - } - if (member.valueType() && member.valueType()->type >= ::ValueType::Type::CHAR) { - structValue->member[member.name()] = uninitValue; - continue; - } - } - if (member.valueType() && member.valueType()->isIntegral()) { - ExprEngine::ValuePtr memberValue = createVariableValue(member, data); - if (memberValue) - data.assignStructMember(tok, structValue.get(), member.name(), memberValue); - } - } - return structValue; -} - -static ExprEngine::ValuePtr createVariableValue(const Variable &var, Data &data) -{ - if (!var.nameToken()) - return ExprEngine::ValuePtr(); - const ValueType *valueType = var.valueType(); - if (!valueType || valueType->type == ValueType::Type::UNKNOWN_TYPE) - valueType = var.nameToken()->valueType(); - if (!valueType || valueType->type == ValueType::Type::UNKNOWN_TYPE) { - // variable with unknown type - if (var.isLocal() && var.isPointer() && !var.isArray()) - return std::make_shared(); - return ExprEngine::ValuePtr(); - } - - if (valueType->pointer > 0) { - if (var.isLocal()) - return std::make_shared(); - auto bufferSize = std::make_shared(data.getNewSymbolName(), 1, MAX_BUFFER_SIZE); - ExprEngine::ValuePtr pointerValue; - if (valueType->type == ValueType::Type::RECORD) - pointerValue = createStructVal(var.nameToken(), valueType->typeScope, var.isLocal() && !var.isStatic(), data); - else { - ValueType vt(*valueType); - vt.pointer = 0; - if (vt.constness & 1) - pointerValue = getValueRangeFromValueType(&vt, data); - else - pointerValue = std::make_shared(); - } - return std::make_shared(data.getNewSymbolName(), bufferSize, pointerValue, true, true, var.isLocal() && !var.isStatic()); - } - if (var.isArray()) - return std::make_shared(&data, &var); - if (valueType->isIntegral() || valueType->isFloat()) { - ExprEngine::ValuePtr value; - if (var.isLocal() && !var.isStatic()) - value = std::make_shared(); - else - value = getValueRangeFromValueType(valueType, data); - data.addConstraints(value, var.nameToken()); - return value; - } - if (valueType->type == ValueType::Type::RECORD) { - bool uninitData = true; - if (var.isLocal() && !var.isStatic()) { - uninitData = !valueType->typeScope || - !valueType->typeScope->definedType || - valueType->typeScope->definedType->needInitialization != Type::NeedInitialization::False; - } - if (var.isArgument() && var.isConst()) - uninitData = false; - return createStructVal(var.nameToken(), valueType->typeScope, uninitData, data); - } - if (valueType->smartPointerType) { - auto structValue = createStructVal(var.nameToken(), valueType->smartPointerType->classScope, var.isLocal() && !var.isStatic(), data); - auto size = std::make_shared(data.getNewSymbolName(), 1, MAX_BUFFER_SIZE); - return std::make_shared(data.getNewSymbolName(), size, structValue, true, true, false); - } - return getValueRangeFromValueType(valueType, data); -} - -void ExprEngine::executeFunction(const Scope *functionScope, ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings, const std::vector &callbacks, std::ostream &report) -{ - if (!functionScope->bodyStart) - return; - const Function *function = functionScope->function; - if (!function) - return; - if (functionScope->bodyStart->fileIndex() > 0) - // TODO.. what about functions in headers? - return; - - const std::string currentFunction = function->fullName(); - - int symbolValueIndex = 0; - TrackExecution trackExecution; - Data data(&symbolValueIndex, errorLogger, tokenizer, settings, currentFunction, callbacks, &trackExecution); - - for (const Variable &arg : function->argumentList) - data.assignValue(functionScope->bodyStart, arg.declarationId(), createVariableValue(arg, data)); - -#ifdef CONTRACT - data.contractConstraints(function, executeExpression1); -#endif - - const std::time_t stopTime = data.startTime + data.settings->bugHuntingCheckFunctionMaxTime; - - try { - execute(functionScope->bodyStart, functionScope->bodyEnd, data); - } catch (const ExprEngineException &e) { - if (settings->debugBugHunting) - report << "ExprEngineException " << e.tok->linenr() << ":" << e.tok->column() << ": " << e.what << "\n"; - trackExecution.setAbortLine(e.tok->linenr()); - auto bailoutValue = std::make_shared(); - for (const Token *tok = e.tok; tok != functionScope->bodyEnd; tok = tok->next()) { - if (std::time(nullptr) >= stopTime) - break; - if (Token::Match(tok, "return|throw|while|if|for (")) { - tok = tok->next(); - continue; - } - call(callbacks, tok, bailoutValue, &data); - } - } - - const bool bugHuntingReport = !settings->bugHuntingReport.empty(); - - if (settings->debugBugHunting && (settings->verbose || callbacks.empty() || !trackExecution.isAllOk())) { - if (bugHuntingReport) - report << "[debug]" << std::endl; - trackExecution.print(report); - if (!callbacks.empty()) { - if (bugHuntingReport) - report << "[details]" << std::endl; - trackExecution.report(report, functionScope); - } - } - - // Write a report - if (bugHuntingReport) { - std::set intvars; - for (const Scope &scope: tokenizer->getSymbolDatabase()->scopeList) { - if (scope.isExecutable()) - continue; - std::string path; - bool valid = true; - for (const Scope *s = &scope; s->type != Scope::ScopeType::eGlobal; s = s->nestedIn) { - if (s->isExecutable()) { - valid = false; - break; - } - path = s->className + "::" + path; - } - if (!valid) - continue; - for (const Variable &var: scope.varlist) { - if (var.nameToken() && !var.nameToken()->hasCppcheckAttributes() && var.valueType() && var.valueType()->pointer == 0 && var.valueType()->constness == 0 && var.valueType()->isIntegral()) - intvars.insert(path + var.name()); - } - } - for (const std::string &v: intvars) - report << "[intvar] " << v << std::endl; - for (const std::string &f: trackExecution.getMissingContracts()) - report << "[missing contract] " << f << std::endl; - } -} - -void ExprEngine::runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings) -{ - - std::vector callbacks; - addBughuntingChecks(&callbacks); - - std::ostringstream report; - ExprEngine::executeAllFunctions(errorLogger, tokenizer, settings, callbacks, report); - if (settings->bugHuntingReport.empty()) - std::cout << report.str(); - else if (errorLogger) - errorLogger->bughuntingReport(report.str()); -} - -static void dumpRecursive(ExprEngine::ValuePtr val) -{ - if (!val) { - std::cout << "NULL"; - return; - } - switch (val->type) { - case ExprEngine::ValueType::AddressOfValue: - std::cout << "AddressOfValue(" << std::dynamic_pointer_cast(val)->varId << ")"; - break; - case ExprEngine::ValueType::ArrayValue: - std::cout << "ArrayValue"; - break; - case ExprEngine::ValueType::BailoutValue: - std::cout << "BailoutValue"; - break; - case ExprEngine::ValueType::BinOpResult: { - auto b = std::dynamic_pointer_cast(val); - std::cout << "("; - dumpRecursive(b->op1); - std::cout << " " << b->binop << " "; - dumpRecursive(b->op2); - std::cout << ")"; - } - break; - case ExprEngine::ValueType::ConditionalValue: - std::cout << "ConditionalValue"; - break; - case ExprEngine::ValueType::FloatRange: - std::cout << "FloatRange"; - break; - case ExprEngine::ValueType::FunctionCallArgumentValues: { - std::cout << "FunctionCallArgumentValues("; - const char *sep = ""; - for (const auto &arg: std::dynamic_pointer_cast(val)->argValues) { - std::cout << sep; - sep = ","; - if (!arg) - std::cout << "NULL"; - else - dumpRecursive(arg); - } - std::cout << ")"; - } - break; - case ExprEngine::ValueType::IntRange: - std::cout << "IntRange"; - break; - case ExprEngine::ValueType::IntegerTruncation: - std::cout << "IntegerTruncation("; - dumpRecursive(std::dynamic_pointer_cast(val)->inputValue); - std::cout << ")"; - break; - case ExprEngine::ValueType::StringLiteralValue: - std::cout << "StringLiteralValue"; - break; - case ExprEngine::ValueType::StructValue: - std::cout << "StructValue"; - break; - case ExprEngine::ValueType::UninitValue: - std::cout << "UninitValue"; - break; - } -} - -void ExprEngine::dump(ExprEngine::ValuePtr val) -{ - dumpRecursive(val); - std::cout << "\n"; -} - - diff --git a/lib/exprengine.h b/lib/exprengine.h deleted file mode 100644 index 55a04ebd0..000000000 --- a/lib/exprengine.h +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2022 Cppcheck team. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -//--------------------------------------------------------------------------- -#ifndef exprengineH -#define exprengineH -//--------------------------------------------------------------------------- - -#include "config.h" -#include "errortypes.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -class ErrorLogger; -class Tokenizer; -class Scope; -class Settings; -class Token; -class Variable; - -#if defined(__GNUC__) && defined (__SIZEOF_INT128__) -typedef __int128_t int128_t; -#else -typedef long long int128_t; -#ifdef _MSC_VER -#pragma message(__FILE__ "(" _CRT_STRINGIZE(__LINE__) ")" ": warning: TODO No 128-bit integer type is available => Limited analysis of large integers...") -#else -#warning TODO No 128-bit integer type is available => Limited analysis of large integers -#endif -#endif - -namespace ExprEngine { - std::string str(int128_t); - - // TODO we need to handle floats, containers, pointers, aliases and structs and stuff - enum class ValueType { - UninitValue, - IntRange, - FloatRange, - ConditionalValue, - ArrayValue, - StringLiteralValue, - StructValue, - AddressOfValue, - BinOpResult, - IntegerTruncation, - FunctionCallArgumentValues, - BailoutValue - }; - - class Value; - typedef std::shared_ptr ValuePtr; - - class DataBase { - public: - explicit DataBase(const std::string ¤tFunction, const Settings *settings) - : currentFunction(currentFunction) - , settings(settings) {} - virtual std::string getNewSymbolName() = 0; - const std::string currentFunction; - const Settings * const settings; - virtual bool isC() const = 0; - virtual bool isCPP() const = 0; - virtual void reportError(const Token *tok, - Severity::SeverityType severity, - const char id[], - const std::string &text, - CWE cwe, - bool inconclusive, - bool incomplete=false, - const std::string &functionName = std::string()) = 0; - ErrorPath errorPath; - }; - - class Value { - public: - Value(const std::string &name, const ValueType type) : name(name), type(type) {} - virtual ~Value() {} - virtual std::string getRange() const { - return name; - } - virtual std::string getSymbolicExpression() const { - return name; - } - virtual bool isEqual(const DataBase *dataBase, int value) const { - (void)dataBase; - (void)value; - return false; - } - virtual bool isGreaterThan(const DataBase *dataBase, int value) const { - (void)dataBase; - (void)value; - return false; - } - virtual bool isLessThan(const DataBase *dataBase, int value) const { - (void)dataBase; - (void)value; - return false; - } - virtual bool isUninit(const DataBase *dataBase) const { - (void)dataBase; - return false; - } - - const std::string name; - ValueType type; - }; - - class UninitValue : public Value { - public: - UninitValue() : Value("?", ValueType::UninitValue) {} - bool isEqual(const DataBase *dataBase, int value) const override { - (void)dataBase; - (void)value; - return true; - } - bool isUninit(const DataBase *dataBase) const override; - }; - - class IntRange : public Value { - public: - IntRange(const std::string &name, int128_t minValue, int128_t maxValue) - : Value(name, ValueType::IntRange) - , minValue(minValue) - , maxValue(maxValue) - , loopScope(nullptr) {} - std::string getRange() const override { - if (minValue == maxValue) - return str(minValue); - return str(minValue) + ":" + str(maxValue); - } - bool isEqual(const DataBase *dataBase, int value) const override; - bool isGreaterThan(const DataBase *dataBase, int value) const override; - bool isLessThan(const DataBase *dataBase, int value) const override; - - int128_t minValue; - int128_t maxValue; - const Scope *loopScope; - }; - - class FloatRange : public Value { - public: - FloatRange(const std::string &name, long double minValue, long double maxValue) - : Value(name, ValueType::FloatRange) - , minValue(minValue) - , maxValue(maxValue) {} - - std::string getRange() const override { - return std::to_string(minValue) + ":" + std::to_string(maxValue); - } - - bool isEqual(const DataBase *dataBase, int value) const override; - bool isGreaterThan(const DataBase *dataBase, int value) const override; - bool isLessThan(const DataBase *dataBase, int value) const override; - - long double minValue; - long double maxValue; - }; - - class ConditionalValue : public Value { - public: - typedef std::vector> Vector; - - ConditionalValue(const std::string &name, const Vector &values) : Value(name, ValueType::ConditionalValue), values(values) {} - - std::string getSymbolicExpression() const override; - - Vector values; - }; - - // Array or pointer - class ArrayValue : public Value { - public: - enum { MAXSIZE = 0x7fffffff }; - - ArrayValue(const std::string &name, ValuePtr size, ValuePtr value, bool pointer, bool nullPointer, bool uninitPointer); - ArrayValue(DataBase *data, const Variable *var); - ArrayValue(const std::string &name, const ArrayValue &arrayValue); - - std::string getRange() const override; - std::string getSymbolicExpression() const override; - - void assign(ValuePtr index, ValuePtr value); - void clear(); - ConditionalValue::Vector read(ValuePtr index) const; - - bool pointer; - bool nullPointer; - bool uninitPointer; - - struct IndexAndValue { - ValuePtr index; - ValuePtr value; - }; - std::vector data; - std::vector size; - }; - - class StringLiteralValue : public Value { - public: - StringLiteralValue(const std::string &name, const std::string &s) : Value(name, ValueType::StringLiteralValue), string(s) {} - - std::string getRange() const override { - return "\"" + string + "\""; - } - - int size() const { - return string.size(); - } - const std::string string; - }; - - class StructValue : public Value { - public: - explicit StructValue(const std::string &name) : Value(name, ValueType::StructValue) {} - - std::string getSymbolicExpression() const override; - - std::string getRange() const override { - return getSymbolicExpression(); - } - - ValuePtr getValueOfMember(const std::string &n) const { - auto it = member.find(n); - return (it == member.end()) ? ValuePtr() : it->second; - } - - std::string getUninitStructMember(const DataBase *dataBase) const { - for (auto memberNameValue: member) { - if (memberNameValue.second && memberNameValue.second->isUninit(dataBase)) - return memberNameValue.first; - } - return std::string(); - } - - std::map member; - }; - - class AddressOfValue : public Value { - public: - AddressOfValue(const std::string &name, int varId) - : Value(name, ValueType::AddressOfValue) - , varId(varId) - {} - - std::string getRange() const override { - return "&@" + std::to_string(varId); - } - - int varId; - }; - - class BinOpResult : public Value { - public: - BinOpResult(const std::string &binop, ValuePtr op1, ValuePtr op2) - : Value(getName(binop, op1, op2), ValueType::BinOpResult) - , binop(binop) - , op1(op1) - , op2(op2) {} - - bool isEqual(const DataBase *dataBase, int value) const override; - bool isGreaterThan(const DataBase *dataBase, int value) const override; - virtual bool isLessThan(const DataBase *dataBase, int value) const override; - bool isTrue(const DataBase *dataBase) const; - - std::string getExpr(DataBase *dataBase) const; - - std::string binop; - ValuePtr op1; - ValuePtr op2; - private: - static std::string getName(const std::string& binop, ValuePtr op1, ValuePtr op2) { - std::string name1 = op1 ? op1->name : std::string("null"); - std::string name2 = op2 ? op2->name : std::string("null"); - return "(" + name1 + ")" + binop + "(" + name2 + ")"; - } - }; - - class IntegerTruncation : public Value { - public: - IntegerTruncation(const std::string &name, ValuePtr inputValue, int bits, char sign) - : Value(name, ValueType::IntegerTruncation) - , inputValue(inputValue) - , bits(bits) - , sign(sign) {} - - std::string getSymbolicExpression() const override; - - ExprEngine::ValuePtr inputValue; - int bits; - char sign; - }; - - class FunctionCallArgumentValues : public Value { - public: - explicit FunctionCallArgumentValues(const std::vector &argValues) - : Value("argValues", ValueType::FunctionCallArgumentValues) - , argValues(argValues) - {} - - const std::vector argValues; - }; - - class BailoutValue : public Value { - public: - BailoutValue() : Value("bailout", ValueType::BailoutValue) {} - bool isEqual(const DataBase * /*dataBase*/, int /*value*/) const override { - return true; - } - bool isUninit(const DataBase *dataBase) const override { - (void)dataBase; - return true; - } - }; - - typedef std::function Callback; - - /** Execute all functions */ - void CPPCHECKLIB executeAllFunctions(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings, const std::vector &callbacks, std::ostream &report); - void executeFunction(const Scope *functionScope, ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings, const std::vector &callbacks, std::ostream &report); - - void runChecks(ErrorLogger *errorLogger, const Tokenizer *tokenizer, const Settings *settings); - - void dump(ExprEngine::ValuePtr val); -} -#endif // exprengineH diff --git a/lib/importproject.cpp b/lib/importproject.cpp index dded586de..63317284b 100644 --- a/lib/importproject.cpp +++ b/lib/importproject.cpp @@ -1168,7 +1168,7 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti temp.basePaths.push_back(joinRelativePath(path, node->Attribute(CppcheckXml::RootPathNameAttrib))); temp.relativePaths = true; } else if (strcmp(node->Name(), CppcheckXml::BugHunting) == 0) - temp.bugHunting = true; + ; else if (strcmp(node->Name(), CppcheckXml::BuildDirElementName) == 0) temp.buildDir = joinRelativePath(path, node->GetText() ? node->GetText() : ""); else if (strcmp(node->Name(), CppcheckXml::IncludeDirElementName) == 0) @@ -1184,26 +1184,11 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti paths = readXmlStringList(node, path, CppcheckXml::PathName, CppcheckXml::PathNameAttrib); else if (strcmp(node->Name(), CppcheckXml::ExcludeElementName) == 0) guiProject.excludedPaths = readXmlStringList(node, "", CppcheckXml::ExcludePathName, CppcheckXml::ExcludePathNameAttrib); - else if (strcmp(node->Name(), CppcheckXml::FunctionContracts) == 0) { - for (const tinyxml2::XMLElement *child = node->FirstChildElement(); child; child = child->NextSiblingElement()) { - if (strcmp(child->Name(), CppcheckXml::FunctionContract) == 0) { - const char *function = child->Attribute(CppcheckXml::ContractFunction); - const char *expects = child->Attribute(CppcheckXml::ContractExpects); - if (function && expects) - temp.functionContracts[function] = expects; - } - } - } else if (strcmp(node->Name(), CppcheckXml::VariableContractsElementName) == 0) { - for (const tinyxml2::XMLElement *child = node->FirstChildElement(); child; child = child->NextSiblingElement()) { - if (strcmp(child->Name(), CppcheckXml::VariableContractItemElementName) == 0) { - const char *name = child->Attribute(CppcheckXml::VariableContractVarName); - const char *min = child->Attribute(CppcheckXml::VariableContractMin); - const char *max = child->Attribute(CppcheckXml::VariableContractMax); - if (name) - temp.variableContracts[name] = Settings::VariableContracts{min?min:"", max?max:""}; - } - } - } else if (strcmp(node->Name(), CppcheckXml::IgnoreElementName) == 0) + else if (strcmp(node->Name(), CppcheckXml::FunctionContracts) == 0) + ; + else if (strcmp(node->Name(), CppcheckXml::VariableContractsElementName) == 0) + ; + else if (strcmp(node->Name(), CppcheckXml::IgnoreElementName) == 0) guiProject.excludedPaths = readXmlStringList(node, "", CppcheckXml::IgnorePathName, CppcheckXml::IgnorePathNameAttrib); else if (strcmp(node->Name(), CppcheckXml::LibrariesElementName) == 0) guiProject.libraries = readXmlStringList(node, "", CppcheckXml::LibraryElementName, nullptr); @@ -1289,8 +1274,6 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti settings->maxCtuDepth = temp.maxCtuDepth; settings->maxTemplateRecursion = temp.maxTemplateRecursion; settings->safeChecks = temp.safeChecks; - settings->bugHunting = temp.bugHunting; - settings->functionContracts = temp.functionContracts; return true; } diff --git a/lib/importproject.h b/lib/importproject.h index d88a523c7..5dc87b5d2 100644 --- a/lib/importproject.h +++ b/lib/importproject.h @@ -153,14 +153,7 @@ namespace CppcheckXml { const char ExcludePathName[] = "path"; const char ExcludePathNameAttrib[] = "name"; const char FunctionContracts[] = "function-contracts"; - const char FunctionContract[] = "contract"; - const char ContractFunction[] = "function"; - const char ContractExpects[] = "expects"; const char VariableContractsElementName[] = "variable-contracts"; - const char VariableContractItemElementName[] = "var"; - const char VariableContractVarName[] = "name"; - const char VariableContractMin[] = "min"; - const char VariableContractMax[] = "max"; const char LibrariesElementName[] = "libraries"; const char LibraryElementName[] = "library"; const char PlatformElementName[] = "platform"; diff --git a/lib/lib.pri b/lib/lib.pri index b2c957825..694e3037f 100644 --- a/lib/lib.pri +++ b/lib/lib.pri @@ -5,7 +5,6 @@ include($$PWD/../externals/externals.pri) INCLUDEPATH += $$PWD HEADERS += $${PWD}/analyzerinfo.h \ $${PWD}/astutils.h \ - $${PWD}/bughuntingchecks.h \ $${PWD}/check.h \ $${PWD}/check64bit.h \ $${PWD}/checkassert.h \ @@ -38,7 +37,6 @@ HEADERS += $${PWD}/analyzerinfo.h \ $${PWD}/ctu.h \ $${PWD}/errorlogger.h \ $${PWD}/errortypes.h \ - $${PWD}/exprengine.h \ $${PWD}/forwardanalyzer.h \ $${PWD}/importproject.h \ $${PWD}/infer.h \ @@ -65,7 +63,6 @@ HEADERS += $${PWD}/analyzerinfo.h \ SOURCES += $${PWD}/analyzerinfo.cpp \ $${PWD}/astutils.cpp \ - $${PWD}/bughuntingchecks.cpp \ $${PWD}/check.cpp \ $${PWD}/check64bit.cpp \ $${PWD}/checkassert.cpp \ @@ -98,7 +95,6 @@ SOURCES += $${PWD}/analyzerinfo.cpp \ $${PWD}/ctu.cpp \ $${PWD}/errorlogger.cpp \ $${PWD}/errortypes.cpp \ - $${PWD}/exprengine.cpp \ $${PWD}/forwardanalyzer.cpp \ $${PWD}/importproject.cpp \ $${PWD}/infer.cpp \ diff --git a/lib/library.cpp b/lib/library.cpp index 2faf4b910..f2a3c7e46 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -61,7 +61,7 @@ static void gettokenlistfromvalid(const std::string& valid, TokenList& tokenList } } -Library::Library() : bugHunting(false), mAllocId(0) +Library::Library() : mAllocId(0) {} Library::Error Library::load(const char exename[], const char path[]) @@ -892,56 +892,6 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co return Error(ErrorCode::OK); } -std::vector Library::getInvalidArgValues(const std::string &validExpr) -{ - std::vector valid; - TokenList tokenList(nullptr); - gettokenlistfromvalid(validExpr, tokenList); - for (const Token *tok = tokenList.front(); tok; tok = tok ? tok->next() : nullptr) { - if (tok->str() == ",") - continue; - if (Token::Match(tok, ": %num%")) { - valid.push_back(InvalidArgValue{InvalidArgValue::Type::le, tok->next()->str(), std::string()}); - tok = tok->tokAt(2); - } else if (Token::Match(tok, "%num% : %num%")) { - valid.push_back(InvalidArgValue{InvalidArgValue::Type::range, tok->str(), tok->strAt(2)}); - tok = tok->tokAt(3); - } else if (Token::Match(tok, "%num% :")) { - valid.push_back(InvalidArgValue{InvalidArgValue::Type::ge, tok->str(), std::string()}); - tok = tok->tokAt(2); - } else if (Token::Match(tok, "%num%")) { - valid.push_back(InvalidArgValue{InvalidArgValue::Type::eq, tok->str(), std::string()}); - tok = tok->next(); - } - } - - std::vector invalid; - if (valid.empty()) - return invalid; - - if (valid[0].type == InvalidArgValue::Type::ge || valid[0].type == InvalidArgValue::Type::eq) - invalid.push_back(InvalidArgValue{InvalidArgValue::Type::lt, valid[0].op1, std::string()}); - if (valid.back().type == InvalidArgValue::Type::le || valid.back().type == InvalidArgValue::Type::eq) - invalid.push_back(InvalidArgValue{InvalidArgValue::Type::gt, valid[0].op1, std::string()}); - for (int i = 0; i + 1 < valid.size(); i++) { - const InvalidArgValue &v1 = valid[i]; - const InvalidArgValue &v2 = valid[i + 1]; - if (v1.type == InvalidArgValue::Type::le && v2.type == InvalidArgValue::Type::ge) { - if (v1.isInt()) { - MathLib::bigint op1 = MathLib::toLongNumber(v1.op1); - MathLib::bigint op2 = MathLib::toLongNumber(v2.op1); - if (op1 + 1 == op2 - 1) - invalid.push_back(InvalidArgValue{InvalidArgValue::Type::eq, MathLib::toString(op1 + 1), std::string()}); - else - invalid.push_back(InvalidArgValue{InvalidArgValue::Type::range, MathLib::toString(op1 + 1), MathLib::toString(op2 - 1)}); - } - } - } - - return invalid; -} - - bool Library::isIntArgValid(const Token *ftok, int argnr, const MathLib::bigint argvalue) const { const ArgumentChecks *ac = getarg(ftok, argnr); @@ -1484,7 +1434,7 @@ bool Library::isnoreturn(const Token *ftok) const if (it == mNoReturn.end()) return false; if (it->second == FalseTrueMaybe::Maybe) - return !bugHunting; // in bugHunting "maybe" means function is not noreturn + return true; return it->second == FalseTrueMaybe::True; } @@ -1498,7 +1448,7 @@ bool Library::isnotnoreturn(const Token *ftok) const if (it == mNoReturn.end()) return false; if (it->second == FalseTrueMaybe::Maybe) - return bugHunting; // in bugHunting "maybe" means function is not noreturn + return false; return it->second == FalseTrueMaybe::False; } diff --git a/lib/library.h b/lib/library.h index 3e64983cc..9243e2d55 100644 --- a/lib/library.h +++ b/lib/library.h @@ -409,7 +409,6 @@ public: return MathLib::isInt(op1); } }; - static std::vector getInvalidArgValues(const std::string &validExpr); const ArgumentChecks::IteratorInfo *getArgIteratorInfo(const Token *ftok, int argnr) const { const ArgumentChecks *arg = getarg(ftok, argnr); @@ -557,8 +556,6 @@ public: enum class TypeCheck { def, check, suppress }; TypeCheck getTypeCheck(const std::string &check, const std::string &typeName) const; - bool bugHunting; - private: // load a xml node Error loadFunction(const tinyxml2::XMLElement * const node, const std::string &name, std::set &unknown_elements); diff --git a/lib/settings.cpp b/lib/settings.cpp index 53f9486fc..94c5fd38d 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -35,9 +35,7 @@ const char Settings::SafeChecks::XmlInternalFunctions[] = "internal-functions"; const char Settings::SafeChecks::XmlExternalVariables[] = "external-variables"; Settings::Settings() - : bugHunting(false), - bugHuntingCheckFunctionMaxTime(60), - checkAllConfigurations(true), + : checkAllConfigurations(true), checkConfiguration(false), checkHeaders(true), checkLibrary(false), @@ -46,7 +44,6 @@ Settings::Settings() clangExecutable("clang"), clangTidy(false), daca(false), - debugBugHunting(false), debugnormal(false), debugSimplified(false), debugtemplate(false), diff --git a/lib/settings.h b/lib/settings.h index 0b3abd7e4..371a2de84 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -108,16 +108,6 @@ public: /** @brief Paths used as base for conversion to relative paths. */ std::vector basePaths; - /** @brief Bug hunting */ - bool bugHunting; - - /** @brief Max time for bug hunting analysis in seconds, after - * timeout the analysis will just stop. */ - int bugHuntingCheckFunctionMaxTime; - - /** Filename for bug hunting report */ - std::string bugHuntingReport; - /** @brief --cppcheck-build-dir. Always uses / as path separator. No trailing path separator. */ std::string buildDir; @@ -162,9 +152,6 @@ public: /** @brief Are we running from DACA script? */ bool daca; - /** @brief Debug bug hunting */ - bool debugBugHunting; - /** @brief Is --debug-normal given? */ bool debugnormal; @@ -204,14 +191,6 @@ public: /** @brief Force checking the files with "too many" configurations (--force). */ bool force; - std::map functionContracts; - - struct VariableContracts { - std::string minValue; - std::string maxValue; - }; - std::map variableContracts; - /** @brief List of include paths, e.g. "my/includes/" which should be used for finding include files inside source files. (-I) */ std::list includePaths; diff --git a/lib/token.cpp b/lib/token.cpp index 22cfa84ee..6046cda26 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -2409,21 +2409,6 @@ const ValueFlow::Value* Token::getKnownValue(ValueFlow::Value::ValueType t) cons return it == mImpl->mValues->end() ? nullptr : &*it; } -bool Token::isImpossibleIntValue(const MathLib::bigint val) const -{ - if (!mImpl->mValues) - return false; - for (const auto& v : *mImpl->mValues) { - if (v.isIntValue() && v.isImpossible() && v.intvalue == val) - return true; - if (v.isIntValue() && v.bound == ValueFlow::Value::Bound::Lower && val > v.intvalue) - return true; - if (v.isIntValue() && v.bound == ValueFlow::Value::Bound::Upper && val < v.intvalue) - return true; - } - return false; -} - const ValueFlow::Value* Token::getValue(const MathLib::bigint val) const { if (!mImpl->mValues) diff --git a/lib/token.h b/lib/token.h index a037b6ae4..05809f6e9 100644 --- a/lib/token.h +++ b/lib/token.h @@ -1170,8 +1170,6 @@ public: return mImpl->mValues->front().intvalue; } - bool isImpossibleIntValue(const MathLib::bigint val) const; - const ValueFlow::Value* getValue(const MathLib::bigint val) const; const ValueFlow::Value* getMaxValue(bool condition, MathLib::bigint path = 0) const; diff --git a/oss-fuzz/CMakeLists.txt b/oss-fuzz/CMakeLists.txt index e3117b05a..dbb28562a 100644 --- a/oss-fuzz/CMakeLists.txt +++ b/oss-fuzz/CMakeLists.txt @@ -21,9 +21,6 @@ if (ENABLE_OSS_FUZZ AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") if (HAVE_RULES) target_link_libraries(fuzz-client PRIVATE ${PCRE_LIBRARY}) endif() - if (USE_Z3) - target_link_libraries(fuzz-client PRIVATE ${Z3_LIBRARIES}) - endif() if(tinyxml2_FOUND AND NOT USE_BUNDLED_TINYXML2) target_link_libraries(fuzz-client PRIVATE ${tinyxml2_LIBRARIES}) endif() diff --git a/oss-fuzz/main.cpp b/oss-fuzz/main.cpp index 97b17bf06..ccc5a4ced 100644 --- a/oss-fuzz/main.cpp +++ b/oss-fuzz/main.cpp @@ -50,9 +50,6 @@ public: (void)stage; (void)value; } - void bughuntingReport(const std::string &str) override { - (void)str; - } }; diff --git a/readme.txt b/readme.txt index 5db9da769..ce2238b39 100644 --- a/readme.txt +++ b/readme.txt @@ -22,14 +22,6 @@ Compiling While building the command line tool, PCRE is optional. It is used if you build with rules. - For "bug hunting" you need Z3. Installing Z3: - * debian: "sudo apt-get install libz3-dev - * windows: - 32-bit: https://github.com/Z3Prover/z3/releases/download/z3-4.8.7/z3-4.8.7-x86-win.zip - 64-bit: https://github.com/Z3Prover/z3/releases/download/z3-4.8.7/z3-4.8.7-x64-win.zip - If you do not want to install z3 in some "system" include/lib paths you can put the files in - cppcheck/externals/z3/include and cppcheck/externals/z3/bin - There are multiple compilation choices: * qmake - cross platform build tool * cmake - cross platform build tool diff --git a/test/testbughuntingchecks.cpp b/test/testbughuntingchecks.cpp deleted file mode 100644 index 3df321dba..000000000 --- a/test/testbughuntingchecks.cpp +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2022 Cppcheck team. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "errortypes.h" -#include "exprengine.h" -#include "library.h" -#include "platform.h" -#include "settings.h" -#include "tokenize.h" -#include "testsuite.h" - -#include - -class TestBughuntingChecks : public TestFixture { -public: - TestBughuntingChecks() : TestFixture("TestBughuntingChecks") { - settings.platform(cppcheck::Platform::Unix64); - } - -private: - Settings settings; - - void run() override { -#ifdef USE_Z3 - settings.certainty.setEnabled(Certainty::inconclusive, true); - LOAD_LIB_2(settings.library, "std.cfg"); - TEST_CASE(checkAssignment); - TEST_CASE(arrayIndexOutOfBounds1); - TEST_CASE(arrayIndexOutOfBounds2); - TEST_CASE(arrayIndexOutOfBounds3); - TEST_CASE(arrayIndexOutOfBounds4); - TEST_CASE(arrayIndexOutOfBounds5); - TEST_CASE(arrayIndexOutOfBounds6); - TEST_CASE(arrayIndexOutOfBoundsDim1); - TEST_CASE(bufferOverflowMemCmp1); - TEST_CASE(bufferOverflowMemCmp2); - TEST_CASE(bufferOverflowStrcpy1); - TEST_CASE(bufferOverflowStrcpy2); - - TEST_CASE(divisionByZeroNoReturn); - - TEST_CASE(uninit); - TEST_CASE(uninit_array); - TEST_CASE(uninit_function_par); - TEST_CASE(uninit_malloc); - TEST_CASE(uninit_struct); - TEST_CASE(uninit_bailout); - TEST_CASE(uninit_fp_smartptr); - TEST_CASE(uninit_fp_struct); - TEST_CASE(uninit_fp_struct_member_init_2); - TEST_CASE(uninit_fp_template_var); - TEST_CASE(ctu); -#endif - } - - void check(const char code[]) { - settings.bugHunting = settings.library.bugHunting = true; - Tokenizer tokenizer(&settings, this); - std::istringstream istr(code); - tokenizer.tokenize(istr, "test.cpp"); - errout.str(""); - ExprEngine::runChecks(this, &tokenizer, &settings); - } - - void checkAssignment() { - check("void foo(int any) { __cppcheck_low__(0) int x; x = any; }"); - ASSERT_EQUALS("[test.cpp:1]: (error) There is assignment, cannot determine that value is greater or equal with 0\n", errout.str()); - - check("struct S { __cppcheck_low__(0) int x; };\n" - "void foo(S *s, int any) { s->x = any; }"); - ASSERT_EQUALS("[test.cpp:2]: (error) There is assignment, cannot determine that value is greater or equal with 0\n", errout.str()); - } - - void arrayIndexOutOfBounds1() { - check("void foo(int x) {\n" - " int p[8];" - " p[x] = 0;\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (error) Array index out of bounds, cannot determine that x is less than 8\n" - "[test.cpp:2]: (error) Array index out of bounds, cannot determine that x is not negative\n", - errout.str()); - } - - void arrayIndexOutOfBounds2() { // loop - check("void foo(int n) {\n" - " int p[8];\n" - " for (int i = 0; i < n; i++)\n" - " p[i] = 0;\n" - "}"); - ASSERT_EQUALS("[test.cpp:4]: (error) Array index out of bounds, cannot determine that i is less than 8\n" - "[test.cpp:4]: (error) Array index out of bounds, cannot determine that i is not negative\n", - errout.str()); - - // .. with unknown expression - check("void foo(int n) {\n" - " int p[8];\n" - " crx_data_header_t *d =\n" - " &libraw_internal_data.unpacker_data.crx_header[framei];\n" - " for (int i = 0; i < n; i++)\n" - " p[i] = 0;\n" - "}"); - ASSERT_EQUALS("[test.cpp:6]: (error) Array index out of bounds, cannot determine that i is less than 8\n" - "[test.cpp:6]: (error) Array index out of bounds, cannot determine that i is not negative\n", - errout.str()); - } - - void arrayIndexOutOfBounds3() { // struct - check("struct S { int x; };\n" - "void foo(short i) {\n" - " S s[8];\n" - " if (s[i].x == 0) {}\n" - "}"); - ASSERT_EQUALS("[test.cpp:4]: (error) Array index out of bounds, cannot determine that i is less than 8\n" - "[test.cpp:4]: (error) Array index out of bounds, cannot determine that i is not negative\n" - "[test.cpp:4]: (error) Cannot determine that 's[i]' is initialized\n", - errout.str()); - } - - void arrayIndexOutOfBounds4() { // ensure there are warnings for bailout value - check("void foo(short i) {\n" - " int buf[8];\n" - "\n" - " data *d = x;\n" - " switch (d->layout) { case 0: break; }\n" - "\n" - " if (buf[i] > 0) {}\n" - "}"); - ASSERT_EQUALS("[test.cpp:7]: (error) Array index out of bounds, cannot determine that i is less than 8\n" - "[test.cpp:7]: (error) Array index out of bounds, cannot determine that i is not negative\n" - "[test.cpp:7]: (error) Cannot determine that 'buf[i]' is initialized\n", - errout.str()); - } - - void arrayIndexOutOfBounds5() { - check("struct {\n" - " struct { int z; } y;\n" - "} x;\n" - "\n" - "void foo(int i) {\n" - " for (int c = 0; c <= i; c++)\n" - " x.y.z = 13;\n" - " int buf[10];\n" - " if (buf[i] > 0) { }\n" - "}"); - ASSERT_EQUALS("[test.cpp:9]: (error) Array index out of bounds, cannot determine that i is less than 10\n" - "[test.cpp:9]: (error) Array index out of bounds, cannot determine that i is not negative\n" - "[test.cpp:9]: (error) Cannot determine that 'buf[i]' is initialized\n", - errout.str()); - } - - void arrayIndexOutOfBounds6() { - check("int buf[5];\n" - "uint16_t foo(size_t offset) {\n" - " uint8_t c = (offset & 0xc0) >> 6;\n" - " return 2 * buf[c];\n" - "}"); - ASSERT_EQUALS("[test.cpp:4]: (error) Array index out of bounds, cannot determine that c is less than 5\n", errout.str()); - } - - void arrayIndexOutOfBoundsDim1() { // itc test case - check("void overrun_st_008 () {\n" - " int buf[5][6];\n" - " buf[5][5] = 1;\n" - "}"); - ASSERT_EQUALS("[test.cpp:3]: (error) Array index out of bounds, cannot determine that 5 is less than 5\n", errout.str()); - } - - void bufferOverflowMemCmp1() { - // CVE-2020-24265 - check("void foo(const char *pktdata, int datalen) {\n" - " if (memcmp(pktdata, \"MGC\", 3)) {}\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (error) Buffer read/write, when calling 'memcmp' it cannot be determined that 1st argument is not overflowed\n", errout.str()); - } - - void bufferOverflowMemCmp2() { - check("void foo(const char *pktdata, unsigned int datalen) {\n" - " if (memcmp(pktdata, \"MGC\", datalen)) {}\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (error) Buffer read/write, when calling 'memcmp' it cannot be determined that 1st argument is not overflowed\n", errout.str()); - } - - void bufferOverflowStrcpy1() { - check("void foo(char *p) {\n" - " strcpy(p, \"hello\");\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (error) Buffer read/write, when calling 'strcpy' it cannot be determined that 1st argument is not overflowed\n", errout.str()); - } - - void bufferOverflowStrcpy2() { - check("void foo(char *p, const char *q) {\n" - " strcpy(p, q);\n" - "}"); - ASSERT_EQUALS("[test.cpp:2]: (error) Buffer read/write, when calling 'strcpy' it cannot be determined that 1st argument is not overflowed\n", errout.str()); - } - - - void divisionByZeroNoReturn() { - // Don't know if function is noreturn or not.. - check("int f(int leftarg, int rightarg) {\n" - " if (rightarg == 0)\n" - " raise (SIGFPE);\n" // <- maybe noreturn - " return leftarg / rightarg;\n" - "}"); - ASSERT_EQUALS("[test.cpp:4]: (error) There is division, cannot determine that there can't be a division by zero.\n", errout.str()); - } - - - void uninit() { - check("void foo() { int x; x = x + 1; }"); - ASSERT_EQUALS("[test.cpp:1]: (error) Cannot determine that 'x' is initialized\n", errout.str()); - - check("void foo() { int x; int y = x + 1; }"); - ASSERT_EQUALS("[test.cpp:1]: (error) Cannot determine that 'x' is initialized\n", errout.str()); - - check("void foo() { int x; x++; }"); - ASSERT_EQUALS("[test.cpp:1]: (error) Cannot determine that 'x' is initialized\n", errout.str()); - } - - void uninit_array() { - check("void foo(int x) {\n" - " int a[10];\n" - " if (x > 0) a[0] = 32;\n" - " return a[0];\n" - "}"); - ASSERT_EQUALS("[test.cpp:4]: (error) Cannot determine that 'a[0]' is initialized\n", errout.str()); - } - - void uninit_function_par() { - // non constant parameters may point at uninitialized data - // constant parameters should point at initialized data - - check("char foo(char id[]) { return id[0]; }"); - ASSERT_EQUALS("[test.cpp:1]: (error) Cannot determine that 'id[0]' is initialized (you can use 'const' to say data must be initialized)\n", errout.str()); - - check("char foo(const char id[]) { return id[0]; }"); - ASSERT_EQUALS("", errout.str()); - - check("char foo(const char id[]);\n" - "void bar() { char data[10]; foo(data); }"); - ASSERT_EQUALS("[test.cpp:2]: (error) Cannot determine that 'data[0]' is initialized\n", errout.str()); - - check("char foo(char id[]);\n" - "void bar() { char data[10]; foo(data); }"); - ASSERT_EQUALS("[test.cpp:2]: (error, inconclusive) Cannot determine that 'data[0]' is initialized. It is inconclusive if there would be a problem in the function call.\n", errout.str()); - - check("void foo(int *p) { if (p) *p=0; }"); - ASSERT_EQUALS("", errout.str()); - - check("class C {\n" - "public:\n" - " C();\n" - " int x;\n" - "};\n" - "\n" - "void foo(const C &c) { int x = c.x; }"); - ASSERT_EQUALS("", errout.str()); - } - - void uninit_malloc() { - check("void foo() { char *p = malloc(10); return *p; }"); - ASSERT_EQUALS("[test.cpp:1]: (error) Cannot determine that '*p' is initialized\n", errout.str()); - } - - void uninit_struct() { - // Assume that constructors initialize all members - // TODO whole program analysis - check("struct Data { Data(); int x; }\n" - "void foo() {\n" - " Data data;\n" - " x = data.x;\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - - void uninit_bailout() { - check("void foo() {\n" - " __CPPCHECK_BAILOUT__;\n" - " int values[5];\n" - " values[i] = 123;\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - check("void foo() {\n" - " __CPPCHECK_BAILOUT__;\n" - " std::ostringstream comm;\n" - " comm << 123;\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - - void ctu() { - check("void init(int &x) {\n" - " x = 1;\n" - "}\n" - "\n" - "void foo() {\n" - " int x;\n" - " init(x);\n" - " x++;\n" - "}"); - ASSERT_EQUALS("", errout.str()); - - check("void init(int a, int &x) {\n" - " if (a < 10)\n" - " x = 1;\n" - "}\n" - "\n" - "void foo(int a) {\n" - " int x;\n" - " init(a, x);\n" - " x++;\n" - "}"); - ASSERT_EQUALS("[test.cpp:9]: (error) Cannot determine that 'x' is initialized\n", errout.str()); - - check("void init(int a, int &x) {\n" - " if (a < 10)\n" - " x = 1;\n" - " else\n" - " x = 3;\n" - "}\n" - "\n" - "void foo(int a) {\n" - " int x;\n" - " init(a, x);\n" - " x++;\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - - void uninit_fp_smartptr() { - check("void foo() {\n" - " std::unique_ptr buffer;\n" - " try { } catch (std::exception& e) { }\n" - " doneCallback(std::move(buffer));\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - - void uninit_fp_struct() { - check("struct Pos {\n" - " int x {0};\n" - " int y {0};\n" - "};\n" - "\n" - "void dostuff() {\n" - " auto obj = C {};\n" - " Pos xy;\n" - " foo(xy);\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - - void uninit_fp_struct_member_init_2() { - check("struct A {\n" - " int x {0}; int y {0};\n" - "};\n" - "void foo(const A& a) {\n" - " bar(a);\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } - - void uninit_fp_template_var() { - check("void foo() {\n" - " X*x = DYNAMIC_CAST(X, p);\n" - " C c;\n" - " f(c);\n" - "}"); - ASSERT_EQUALS("", errout.str()); - } -}; - -REGISTER_TEST(TestBughuntingChecks) diff --git a/test/testcppcheck.cpp b/test/testcppcheck.cpp index 2b4a1a1a3..7ee19b370 100644 --- a/test/testcppcheck.cpp +++ b/test/testcppcheck.cpp @@ -39,7 +39,6 @@ private: std::list id; void reportOut(const std::string & /*outmsg*/, Color = Color::Reset) override {} - void bughuntingReport(const std::string & /*str*/) override {} void reportErr(const ErrorMessage &msg) override { id.push_back(msg.id); diff --git a/test/testexprengine.cpp b/test/testexprengine.cpp deleted file mode 100644 index d560f4fe4..000000000 --- a/test/testexprengine.cpp +++ /dev/null @@ -1,1076 +0,0 @@ -/* - * Cppcheck - A tool for static C/C++ code analysis - * Copyright (C) 2007-2022 Cppcheck team. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "exprengine.h" -#include "library.h" -#include "platform.h" -#include "settings.h" -#include "token.h" -#include "tokenize.h" -#include "testsuite.h" - -#include -#include -#include -#include -#include -#include - -class TestExprEngine : public TestFixture { -public: - TestExprEngine() : TestFixture("TestExprEngine") {} - -private: - void run() override { -#ifdef USE_Z3 - TEST_CASE(annotation1); - TEST_CASE(annotation2); - - TEST_CASE(expr1); - TEST_CASE(expr2); - TEST_CASE(expr3); - TEST_CASE(expr4); - TEST_CASE(expr5); - TEST_CASE(expr6); - TEST_CASE(expr7); - TEST_CASE(expr8); - TEST_CASE(expr9); - TEST_CASE(exprAssign1); - TEST_CASE(exprAssign2); // Truncation - TEST_CASE(exprNot); - - TEST_CASE(getValueConst1); - - TEST_CASE(inc1); - TEST_CASE(inc2); - TEST_CASE(inc3); - - TEST_CASE(if1); - TEST_CASE(if2); - TEST_CASE(if3); - TEST_CASE(if4); - TEST_CASE(if5); - TEST_CASE(ifAlwaysTrue1); - TEST_CASE(ifAlwaysTrue2); - TEST_CASE(ifAlwaysTrue3); - TEST_CASE(ifAlwaysFalse1); - TEST_CASE(ifAlwaysFalse2); - TEST_CASE(ifelse1); - TEST_CASE(ifif); - TEST_CASE(ifreturn); - TEST_CASE(ifIntRangeAlwaysFalse); - TEST_CASE(ifIntRangeAlwaysTrue); - - TEST_CASE(istream); - - TEST_CASE(switch1); - TEST_CASE(switch2); - - TEST_CASE(for1); - TEST_CASE(forAlwaysFalse1); - - TEST_CASE(while1); - TEST_CASE(while2); - TEST_CASE(while3); - TEST_CASE(while4); - TEST_CASE(while5); - - TEST_CASE(array1); - TEST_CASE(array2); - TEST_CASE(array3); - TEST_CASE(array4); - TEST_CASE(array5); - TEST_CASE(array6); - TEST_CASE(array7); - TEST_CASE(arrayInit1); - TEST_CASE(arrayInit2); - TEST_CASE(arrayInit3); - TEST_CASE(arrayUninit); - TEST_CASE(arrayInLoop); - - TEST_CASE(floatValue1); - TEST_CASE(floatValue2); - TEST_CASE(floatValue3); - TEST_CASE(floatValue4); - TEST_CASE(floatValue5); - - TEST_CASE(functionCall1); - TEST_CASE(functionCall2); - TEST_CASE(functionCall3); - TEST_CASE(functionCall4); - TEST_CASE(functionCall5); - - TEST_CASE(functionCallContract1); - TEST_CASE(functionCallContract2); - - TEST_CASE(int1); - - TEST_CASE(pointer1); - TEST_CASE(pointer2); - TEST_CASE(pointer3); - TEST_CASE(pointerAlias1); - TEST_CASE(pointerAlias2); - TEST_CASE(pointerAlias3); - TEST_CASE(pointerAlias4); - TEST_CASE(pointerNull1); - - TEST_CASE(structMember1); - TEST_CASE(structMember2); - TEST_CASE(structMember3); - - TEST_CASE(pointerToStructInLoop); - - TEST_CASE(ternaryOperator1); -#endif - } - - static void replace(std::string& str, const std::string& from, const std::string& to) { - size_t pos = 0; - while ((pos = str.find(from, pos)) != std::string::npos) - str.replace(pos, from.length(), to); - } - - static std::string cleanupExpr(std::string rawexpr) { - std::string ret; - std::istringstream istr(rawexpr); - std::string line; - while (std::getline(istr, line)) { - if (line.empty()) - continue; - line = line.substr(line.find_first_not_of(" ")); - if (line.compare(0,13,"(declare-fun ") == 0) - continue; - if (line == "(solver") - continue; - if (line.compare(0,9,"(assert (") == 0) { - line.erase(0,8); - line.erase(line.size()-1); - } - replace(line, "(fp.gt ", "(> "); - replace(line, "(fp.lt ", "(< "); - replace(line, "(_ +zero 11 53)", "0.0"); - replace(line, "(fp #b0 #b10000000010 #x899999999999a)", "12.3"); - replace(line, "(/ 123.0 10.0)", "12.3"); - int par = 0; - for (char pos : line) { - if (pos == '(') - par++; - else if (pos == ')') - --par; - } - if (par < 0) - line.erase(line.size() - 1); - ret += line + "\n"; - } - return ret; - } - -#define expr(code, binop) expr_(code, binop, __FILE__, __LINE__) - std::string expr_(const char code[], const std::string &binop, const char* file, int line) { - Settings settings; - settings.platform(cppcheck::Platform::Unix64); - Tokenizer tokenizer(&settings, this); - std::istringstream istr(code); - ASSERT_LOC(tokenizer.tokenize(istr, "test.cpp"), file, line); - std::string ret; - ExprEngine::Callback f = [&](const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase) { - if (tok->str() != binop) - return; - const auto *b = dynamic_cast(&value); - if (!b) - return; - ret += TestExprEngine::cleanupExpr(b->getExpr(dataBase)); - }; - std::vector callbacks; - callbacks.push_back(f); - std::ostringstream trace; - ExprEngine::executeAllFunctions(this, &tokenizer, &settings, callbacks, trace); - return ret; - } - -#define functionCallContractExpr(...) functionCallContractExpr_(code, s, __FILE__, __LINE__) - std::string functionCallContractExpr_(const char code[], const Settings &s, const char* file, int line) { - Settings settings; - settings.bugHunting = true; - settings.debugBugHunting = true; - settings.functionContracts = s.functionContracts; - settings.platform(cppcheck::Platform::Unix64); - Tokenizer tokenizer(&settings, this); - std::istringstream istr(code); - ASSERT_LOC(tokenizer.tokenize(istr, "test.cpp"), file, line); - std::vector callbacks; - std::ostringstream trace; - ExprEngine::executeAllFunctions(this, &tokenizer, &settings, callbacks, trace); - std::string ret = trace.str(); - std::string::size_type pos1 = ret.find("checkContract:{"); - std::string::size_type pos2 = ret.find("}", pos1); - if (pos2 == std::string::npos) - return "Error:" + ret; - return TestExprEngine::cleanupExpr(ret.substr(pos1, pos2+1-pos1)); - } - -#define getRange(...) getRange_(__FILE__, __LINE__, __VA_ARGS__) - std::string getRange_(const char* file, int line, const char code[], const std::string &str, int linenr = 0) { - Settings settings; - settings.platform(cppcheck::Platform::Unix64); - settings.library.smartPointers["std::shared_ptr"]; - Tokenizer tokenizer(&settings, this); - std::istringstream istr(code); - ASSERT_LOC(tokenizer.tokenize(istr, "test.cpp"), file, line); - std::string ret; - ExprEngine::Callback f = [&](const Token *tok, const ExprEngine::Value &value, ExprEngine::DataBase *dataBase) { - (void)dataBase; - if ((linenr == 0 || linenr == tok->linenr()) && tok->expressionString() == str) { - if (!ret.empty()) - ret += ","; - ret += (value.getRange)(); - } - }; - std::vector callbacks; - callbacks.push_back(f); - std::ostringstream trace; - ExprEngine::executeAllFunctions(this, &tokenizer, &settings, callbacks, trace); - return ret; - } - -#define trackExecution(...) trackExecution_(__FILE__, __LINE__, __VA_ARGS__) - std::string trackExecution_(const char* file, int line, const char code[], Settings *settings = nullptr) { - Settings s; - if (!settings) - settings = &s; - settings->bugHunting = true; - settings->debugBugHunting = true; - settings->platform(cppcheck::Platform::Unix64); - settings->library.smartPointers["std::shared_ptr"]; - Tokenizer tokenizer(settings, this); - std::istringstream istr(code); - ASSERT_LOC(tokenizer.tokenize(istr, "test.cpp"), file, line); - std::vector callbacks; - std::ostringstream ret; - ExprEngine::executeAllFunctions(this, &tokenizer, settings, callbacks, ret); - return ret.str(); - } - - void annotation1() { - const char code[] = "void f(__cppcheck_low__(100) short x) {\n" - " return x < 10;\n" - "}"; - - const char expected[] = "(>= $1 100)\n" // <- annotation - "(and (>= $1 (- 32768)) (<= $1 32767))\n" - "(< $1 10)\n" - "z3::unsat\n"; - - ASSERT_EQUALS(expected, expr(code, "<")); - } - - void annotation2() { - const char code[] = "__cppcheck_low__(100) short x;\n" - " void f() {\n" - " return x < 10;\n" - "}"; - - const char expected[] = "(>= $1 100)\n" // <- annotation - "(and (>= $1 (- 32768)) (<= $1 32767))\n" - "(< $1 10)\n" - "z3::unsat\n"; - - ASSERT_EQUALS(expected, expr(code, "<")); - } - - void expr1() { - ASSERT_EQUALS("-32768:32767", getRange("void f(short x) { a = x; }", "x")); - } - - void expr2() { - ASSERT_EQUALS("($1)+($1)", getRange("void f(short x) { a = x + x; }", "x+x")); - } - - void expr3() { - ASSERT_EQUALS("($1)+($1)", getRange("int f(short x) { int a = x + x; return a; }", "return a")); - } - - void expr4() { - ASSERT_EQUALS("($1)-($1)", getRange("int f(short x) { int a = x - x; return a; }", "return a")); - } - - void expr5() { - ASSERT_EQUALS("($1)+($2)", getRange("void f(short a, short b, short c, short d) { if (a+b 1000;" - "}"; - - ASSERT_EQUALS("(8)-($1)", getRange(code, "8-x")); - - ASSERT_EQUALS("(and (>= $1 0) (<= $1 255))\n" - "(> (- 8 $1) 1000)\n" - "z3::unsat\n", - expr(code, ">")); - } - - void expr7() { - const char code[] = "void f(bool a, bool b, int c) {\n" - " if (a||b) {}\n" - " c > 1000;" - "}"; - - ASSERT_EQUALS("(or (distinct $1 0) (distinct $2 0))\n" - "(and (>= $3 (- 2147483648)) (<= $3 2147483647))\n" - "(and (>= $1 0) (<= $1 1))\n" - "(and (>= $2 0) (<= $2 1))\n" - "(> $3 1000)\n" - "z3::sat\n" - "(= (ite (or (distinct $1 0) (distinct $2 0)) 1 0) 0)\n" - "(and (>= $3 (- 2147483648)) (<= $3 2147483647))\n" - "(and (>= $1 0) (<= $1 1))\n" - "(and (>= $2 0) (<= $2 1))\n" - "(> $3 1000)\n" - "z3::sat\n", - expr(code, ">")); - } - - void expr8() { - const char code[] = "void foo(int x, int y) {\n" - " if (x % 32) {}\n" - " y==3;\n" - "}"; - // Do not crash - expr(code, "=="); - } - - void expr9() { - Settings settings; - LOAD_LIB_2(settings.library, "std.cfg"); - - ASSERT_EQUALS("1:26: $4=ArrayValue([$3],[:]=$2)\n" - "1:26: $3=IntRange(0:2147483647)\n" - "1:26: $2=IntRange(-128:127)\n" - "1:27: D0:memory:{s=($4,[$3],[:]=$2)}\n", - trackExecution("void foo() { std::string s; }", &settings)); - - - ASSERT_EQUALS("1:52: $4=ArrayValue([$3],[:]=$2)\n" - "1:52: $3=IntRange(0:2147483647)\n" - "1:52: $2=IntRange(-128:127)\n" - "1:66: D0:memory:{s=($4,[$3],[:]=$2)}\n", - trackExecution("std::string getName(int); void foo() { std::string s = getName(1); }", &settings)); - } - - void exprAssign1() { - ASSERT_EQUALS("($1)+(1)", getRange("void f(unsigned char a) { a += 1; }", "a+=1")); - } - - void exprAssign2() { - ASSERT_EQUALS("2", getRange("void f(unsigned char x) { x = 258; int a = x }", "a=x")); - } - - void exprNot() { - ASSERT_EQUALS("($1)==(0)", getRange("void f(unsigned char a) { return !a; }", "!a")); - } - - void getValueConst1() { // Data::getValue - ASSERT_EQUALS("512", getRange("const int x=512; void func() { x=x }", "x=x")); - } - - - void inc1() { - ASSERT_EQUALS("(and (>= $1 (- 2147483648)) (<= $1 2147483647))\n" - "(= (+ $1 1) $1)\n" - "z3::unsat\n", - expr("void f(int x) { int y = x++; x == y; }", "==")); - - ASSERT_EQUALS("(and (>= $1 (- 2147483648)) (<= $1 2147483647))\n" - "(= (+ $1 1) (+ $1 1))\n" - "z3::sat\n", - expr("void f(int x) { int y = ++x; x == y; }", "==")); - } - - void inc2() { - ASSERT_EQUALS("(= 2 2)\n" - "z3::sat\n", - expr("void f() { unsigned char a[2]; a[0] = 1; a[0]++; a[0] == a[0]; }", "==")); - } - - void inc3() { // #10391 - don't crash - ASSERT_EQUALS("", - expr("void f(T* p, T t) { *p++ = 1; *p++ = t; *p == 0; }", "==")); - } - - void if1() { - ASSERT_EQUALS("(< $1 $2)\n" - "(and (>= $1 (- 2147483648)) (<= $1 2147483647))\n" - "(and (>= $2 (- 2147483648)) (<= $2 2147483647))\n" - "(= $1 $2)\n" - "z3::unsat\n", - expr("void f(int x, int y) { if (x < y) return x == y; }", "==")); - } - - void if2() { - const char code[] = "void foo(int x) {\n" - " if (x > 0 && x == 20) {}\n" - "}"; - // In expression "x + x < 20", "x" is greater than 0 - const char expected[] = "(> $1 0)\n" - "(and (>= $1 (- 2147483648)) (<= $1 2147483647))\n" - "(= $1 20)\n" - "z3::sat\n"; - ASSERT_EQUALS(expected, expr(code, "==")); - } - - void if3() { - const char code[] = "void foo(int x) {\n" - " if (x > 0 || x == 20) {}\n" - "}"; - // In expression "x + x < 20", "x" is greater than 0 - const char expected[] = "(<= $1 0)\n" - "(and (>= $1 (- 2147483648)) (<= $1 2147483647))\n" - "(= $1 20)\n" - "z3::unsat\n"; // "x == 20" is unsat - ASSERT_EQUALS(expected, expr(code, "==")); - } - - void if4() { - const char code[] = "void foo(unsigned int x, unsigned int y) {\n" - " unsigned int z = y;" - " if (x < z) { return z == 0; }\n" - "}"; - const char expected[] = "(< $1 $2)\n" - "(>= $2 0)\n" - "(>= $1 0)\n" - "(= $2 0)\n" - "z3::unsat\n"; - ASSERT_EQUALS(expected, expr(code, "==")); - } - - void if5() { - ASSERT_EQUALS("(> |$2:0| 12)\n" - "(and (>= |$2:0| (- 2147483648)) (<= |$2:0| 2147483647))\n" - "(= |$2:0| 5)\n" - "z3::unsat\n", - expr("void foo(const int *x) { if (f1() && *x > 12) dostuff(*x == 5); }", "==")); - } - - void ifAlwaysTrue1() { - const char code[] = "int foo() {\n" - " int a = 42;\n" - " if (1) {\n" - " a = 0;\n" - " }\n" - " return a == 0;\n" - "}"; - const char expected[] = "(= 0 0)\n" - "z3::sat\n"; - ASSERT_EQUALS(expected, expr(code, "==")); - } - - void ifAlwaysTrue2() { - const char code[] = "int foo() {\n" - " int a = 42;\n" - " if (12.3) {\n" - " a = 0;\n" - " }\n" - " return a == 0;\n" - "}"; - const char expected[] = "(= 0 0)\n" - "z3::sat\n"; - ASSERT_EQUALS(expected, expr(code, "==")); - } - - void ifAlwaysTrue3() { - const char code[] = "int foo() {\n" - " int a = 42;\n" - " if (\"test\") {\n" - " a = 0;\n" - " }\n" - " return a == 0;\n" - "}"; - // String literals are always true. z3 will not be involved. - ASSERT_EQUALS("(= 0 0)\n" - "z3::sat\n", - expr(code, "==")); - } - - void ifAlwaysFalse1() { - const char code[] = "int foo() {\n" - " int a = 42;\n" - " if (0) {\n" - " a = 0;\n" - " }\n" - " return a == 0;\n" - "}"; - const char expected[] = "(= 42 0)\n" - "z3::unsat\n"; - ASSERT_EQUALS(expected, expr(code, "==")); - } - - void ifAlwaysFalse2() { - const char code[] = "int foo() {\n" - " int a = 42;\n" - " if (0.0) {\n" - " a = 0;\n" - " }\n" - " return a == 0;\n" - "}"; - const char expected[] = "(= 42 0)\n" - "z3::unsat\n"; - ASSERT_EQUALS(expected, expr(code, "==")); - } - - void ifelse1() { - ASSERT_EQUALS("(<= $1 5)\n" - "(and (>= $1 (- 32768)) (<= $1 32767))\n" - "(= (+ $1 2) 40)\n" - "z3::unsat\n", - expr("void f(short x) { if (x > 5) ; else if (x+2==40); }", "==")); - } - - - void ifif() { - const char code[] = "void foo(unsigned char x) {\n" - " if (x > 5) {}\n" - " if (x > 5) {}\n" - " return x == 13;\n" - "}"; - - ASSERT_EQUALS("(> $1 5)\n" - "(and (>= $1 0) (<= $1 255))\n" - "(= $1 13)\n" - "z3::sat\n" - "(<= $1 5)\n" - "(and (>= $1 0) (<= $1 255))\n" - "(= $1 13)\n" - "z3::unsat\n", - expr(code, "==")); - } - - - void ifreturn() { // Early return - const char code[] = "void foo(unsigned char x) {\n" - " if (x > 5) { return; }\n" - " return x == 13;\n" - "}"; - - ASSERT_EQUALS("(<= $1 5)\n" - "(and (>= $1 0) (<= $1 255))\n" - "(= $1 13)\n" - "z3::unsat\n", - expr(code, "==")); - } - - void ifIntRangeAlwaysFalse() { - const char code[] = "void foo(unsigned char x) {\n" - " if (x > 0)\n" - " return;\n" - " if (x) {\n" // <-- condition should be "always false". - " x++;\n" - " }\n" - " return x == 0;\n" // <- sat - "}"; - ASSERT_EQUALS("(<= $1 0)\n" - "(and (>= $1 0) (<= $1 255))\n" - "(= $1 0)\n" - "z3::sat\n", - expr(code, "==")); - } - - void ifIntRangeAlwaysTrue() { - const char code[] = "void foo(unsigned char x) {\n" - " if (x < 1)\n" - " return;\n" - " if (x) {\n" // <-- condition should be "always true". - " x++;\n" - " }\n" - " return x == 0;\n" // <- unsat - "}"; - ASSERT_EQUALS("(>= $1 1)\n" - "(and (>= $1 0) (<= $1 255))\n" - "(= (+ $1 1) 0)\n" - "z3::unsat\n", - expr(code, "==")); - } - - void istream() { - const char code[] = "void foo(const std::string& in) {\n" - " std::istringstream istr(in);\n" - " unsigned short x=5;\n" - " istr >> x;\n" - " x==3;\n" - "}"; - - ASSERT_EQUALS("(and (>= $1 0) (<= $1 65535))\n" - "(= $1 3)\n" - "z3::sat\n", - expr(code, "==")); - } - - void switch1() { - const char code[] = "void f(int x) {\n" - " switch (x) {\n" - " case 1: x==3; break;\n" - " case 2: x>0; break;\n" - " };\n" - " x<=4;\n" - "}"; - ASSERT_EQUALS("(= $1 1)\n" - "(and (>= $1 (- 2147483648)) (<= $1 2147483647))\n" - "(= $1 3)\n" - "z3::unsat\n", - expr(code, "==")); - } - - void switch2() { - const char code[] = "void foo(char type, int mcc) {\n" - " switch (type) {\n" - " case '1':\n" - " case '3':\n" - " break;\n" - " default:\n" - " return false;\n" - " }\n" - " p[0] = mcc == 0;\n" - "}"; - ASSERT_EQUALS("(= $1 49)\n" - "(and (>= $2 (- 2147483648)) (<= $2 2147483647))\n" - "(and (>= $1 (- 128)) (<= $1 127))\n" - "(= $2 0)\n" - "z3::sat\n" - "(= $1 51)\n" - "(and (>= $2 (- 2147483648)) (<= $2 2147483647))\n" - "(and (>= $1 (- 128)) (<= $1 127))\n" - "(= $2 0)\n" - "z3::sat\n", - expr(code, "==")); - } - - - void for1() { - const char code[] = "void f() {\n" - " int x[10];\n" - " for (int i = 0; i < 10; i++) x[i] = 0;\n" - " x[4] == 67;\n" - "}"; - ASSERT_EQUALS("(= 0 67)\n" - "z3::unsat\n", - expr(code, "==")); - } - - void forAlwaysFalse1() { - const char code[] = "int f() {\n" - " int a = 19;\n" - " for (int i = 0; i < 0; i++)\n" - " a += 8;\n" - " for (int i = 0; i < 1; i++)\n" - " a += 23;\n" - " for (int i = 100; i >= 1; i--)\n" - " a += 23;\n" - " return a == 42;\n" - "}"; - const char expected[] = "(and (>= $4 (- 2147483648)) (<= $4 2147483647))\n" - "(= (+ $4 23) 42)\n" - "z3::sat\n"; - ASSERT_EQUALS(expected, expr(code, "==")); - } - - void while1() { - const char code[] = "void f(int y) {\n" - " int x = 0;\n" - " while (x < y)\n" - " x = x + 34;\n" - " x == 340;\n" - "}"; - const char expected[] = "(< 0 $1)\n" - "(and (>= $2 (- 2147483648)) (<= $2 2147483647))\n" - "(and (>= $1 (- 2147483648)) (<= $1 2147483647))\n" - "(= (+ $2 34) 340)\n" - "z3::sat\n" - "(= 0 340)\n" - "z3::unsat\n"; - ASSERT_EQUALS(expected, expr(code, "==")); - } - - void while2() { - const char code[] = "void f(int y) {\n" - " int x = 0;\n" - " while (x < y)\n" - " x++;\n" - " x == 1;\n" - "}"; - const char expected[] = "(< 0 $1)\n" - "(and (>= $2 (- 2147483648)) (<= $2 2147483647))\n" - "(and (>= $1 (- 2147483648)) (<= $1 2147483647))\n" - "(= (+ $2 1) 1)\n" - "z3::sat\n" - "(= 0 1)\n" - "z3::unsat\n"; - ASSERT_EQUALS(expected, expr(code, "==")); - } - - void while3() { - const char code[] = "struct AB {int a; int b;};\n" - "void f() {\n" - " struct AB ab;\n" - " while (1)\n" - " ab.a = 3;\n" - " ab.a == 0;\n" - "}"; - ASSERT_EQUALS("(= 3 0)\n" - "z3::unsat\n", - expr(code, "==")); - } - - void while4() { - const char code[] = "void f(const char *host, int *len) {\n" - " while (*host)\n" - " *len = 0;\n" - " *len == 0;\n" - "}"; - const char expected[] = "(distinct |$2:0| 0)\n" - "(and (>= |$2:0| (- 128)) (<= |$2:0| 127))\n" - "(= 0 0)\n" - "z3::sat\n" - "(and (>= $8 (- 2147483648)) (<= $8 2147483647))\n" - "(= $8 0)\n" - "z3::sat\n"; - ASSERT_EQUALS(expected, expr(code, "==")); - } - - void while5() { - const char code[] = "void f() {\n" - " int x;\n" - " while (cond)\n" - " x += 4;\n" - "}"; - ASSERT(getRange(code, "x", 4).find("?") != std::string::npos); - } - - - void array1() { - ASSERT_EQUALS("(= 5 0)\nz3::unsat\n", - expr("int f() { int arr[10]; arr[4] = 5; return arr[4]==0; }", "==")); - } - - void array2() { - ASSERT_EQUALS("(and (>= |$4:4| 0) (<= |$4:4| 255))\n" - "(= |$4:4| 365)\n" - "z3::unsat\n", - expr("void dostuff(unsigned char *); int f() { unsigned char arr[10] = \"\"; dostuff(arr); return arr[4] == 365; }", "==")); - } - - void array3() { - const char code[] = "void f(unsigned char x) { int arr[10]; arr[4] = 43; return arr[x] == 12; }"; - ASSERT_EQUALS("?,43", getRange(code, "arr[x]")); - ASSERT_EQUALS("(and (>= $1 0) (<= $1 255))\n" - "(= (ite (= $1 4) 43 0) 12)\n" - "z3::unsat\n", - expr(code, "==")); - } - - void array4() { - const char code[] = "int buf[10];\n" - "void f() { int x = buf[0]; }"; - ASSERT_EQUALS("2:16: $2:0=IntRange(-2147483648:2147483647)\n" - "2:20: $1=ArrayValue([10],[:]=$2)\n" - "2:20: $2=IntRange(-2147483648:2147483647)\n" - "2:26: D0:memory:{buf=($1,[10],[:]=$2) x=$2:0}\n", - trackExecution(code)); - } - - void array5() { - const char code[] = "int f(int x) {\n" - " int buf[3][4][5];\n" - " buf[x][1][2] = 10;\n" - " return buf[0][1][2];\n" - "}"; - ASSERT_EQUALS("1:14: $1=IntRange(-2147483648:2147483647)\n" - "1:14: D0:memory:{x=$1}\n" - "2:7: $2=ArrayValue([3][4][5],[:]=?)\n" - "2:19: D0:memory:{x=$1 buf=($2,[3][4][5],[:]=?)}\n" - "3:20: D0:memory:{x=$1 buf=($2,[3][4][5],[:]=?,[((20)*($1))+(7)]=10)}\n", - trackExecution(code)); - } - - void array6() { - const char code[] = "void foo(int *x) {\n" - " *x = 2;\n" - " if (*x == 21) {}" - "}"; - ASSERT_EQUALS("(= 2 21)\n" - "z3::unsat\n", - expr(code, "==")); - } - - void array7() { - const char code[] = "void foo(unsigned char *x) {\n" - " *x = 2;\n" - " *x = 1;\n" - "}"; - ASSERT_EQUALS("1:28: $2=ArrayValue([$1],[:]=?,null)\n" - "1:28: $1=IntRange(1:2147483647)\n" - "1:28: D0:memory:{x=($2,[$1],[:]=?)}\n" - "2:9: D0:memory:{x=($2,[$1],[:]=?,[0]=2)}\n" - "3:9: D0:memory:{x=($2,[$1],[:]=?,[0]=1)}\n", - trackExecution(code)); - } - - void arrayInit1() { - ASSERT_EQUALS("0", getRange("inf f() { char arr[10] = \"\"; return arr[4]; }", "arr[4]")); - } - - void arrayInit2() { - ASSERT_EQUALS("66", getRange("void f() { char str[] = \"hello\"; str[0] = \'B\'; }", "str[0]=\'B\'")); - } - - void arrayInit3() { - ASSERT_EQUALS("-32768:32767", getRange("void f() { short buf[5] = {2, 1, 0, 3, 4}; ret = buf[2]; }", "buf[2]")); - } - - void arrayUninit() { - ASSERT_EQUALS("?", getRange("int f() { int arr[10]; return arr[4]; }", "arr[4]")); - } - - void arrayInLoop() { - const char code[] = "void f() {\n" - " int arr[3][3];\n" - " for (int i = 0; i < 3; i++) arr[i][0] = arr[1][2];\n" - " return arr[0][0];" - "}"; - ASSERT_EQUALS("?", getRange(code, "arr[1][2]")); - } - - - void floatValue1() { - ASSERT_EQUALS("-inf:inf", getRange("float f; void func() { f=f; }", "f=f")); - } - - void floatValue2() { - ASSERT_EQUALS("(29.0)/(2.0)", getRange("void func() { float f = 29.0; f = f / 2.0; }", "f/2.0")); - } - - void floatValue3() { - const char code[] = "void foo(float f) { return f > 12.3; }"; - const char expected[] = "(> $1 12.3)\n" - "z3::sat\n"; - ASSERT_EQUALS(expected, expr(code, ">")); - } - - void floatValue4() { - const char code[] = "void foo(float f) { return f > 12.3f; }"; - const char expected[] = "(> $1 12.3)\n" - "z3::sat\n"; - ASSERT_EQUALS(expected, expr(code, ">")); - } - - void floatValue5() { // float < int - const char code[] = "void foo(float f) { if (f < 1){} }"; - const char expected[] = "(< $1 (to_real 1))\n" - "z3::sat\n"; - ASSERT_EQUALS(expected, expr(code, "<")); - } - - void functionCall1() { - ASSERT_EQUALS("-2147483648:2147483647", getRange("int atoi(const char *p); void f() { int x = atoi(a); x = x; }", "x=x")); - } - - void functionCall2() { - const char code[] = "namespace NS {\n" - " short getValue();\n" - "}" - "void f() {\n" - " short value = NS::getValue();\n" - " value = value;\n" - "}"; - ASSERT_EQUALS("-32768:32767", getRange(code, "value=value")); - } - - void functionCall3() { - ASSERT_EQUALS("-2147483648:2147483647", getRange("int fgets(int, const char *, void *); void f() { int x = -1; fgets(stdin, \"%d\", &x); x=x; }", "x=x")); - } - - void functionCall4() { - ASSERT_EQUALS("1:2147483647", getRange("void f() { sizeof(data); }", "sizeof(data)")); - } - - void functionCall5() { // unknown result from function, pointer type.. - ASSERT_EQUALS("1:36: $3=ArrayValue([$2],[:]=bailout,null)\n" - "1:36: $2=IntRange(1:2147483647)\n" - "1:36: bailout=BailoutValue(bailout)\n" - "1:46: D0:memory:{p=($3,[$2],[:]=bailout)}\n", - trackExecution("char *foo(int); void bar() { char *p = foo(1); }")); - } - - void functionCallContract1() { - const char code[] = "void foo(int x);\n" - "void bar(unsigned short x) { foo(x); }"; - - Settings s; - s.functionContracts["foo(x)"] = "x < 1000"; - - ASSERT_EQUALS("checkContract:{\n" - "(ite (< $2 1000) false true)\n" - "(= $2 $1)\n" - "(and (>= $2 (- 2147483648)) (<= $2 2147483647))\n" - "(and (>= $1 0) (<= $1 65535))\n" - "}\n", - functionCallContractExpr(code, s)); - } - - void functionCallContract2() { - const char code[] = "void foo(float x);\n" - "void bar(float x) { foo(x); }"; - - Settings s; - s.functionContracts["foo(x)"] = "x < 12.3"; - - ASSERT_EQUALS("checkContract:{\n" - "(ite (< $2 12.3) false true)\n" - "}\n", - functionCallContractExpr(code, s)); - } - - - void int1() { - ASSERT_EQUALS("(and (>= $1 (- 2147483648)) (<= $1 2147483647))\n" - "(= (+ 2 $1) 3)\n" - "z3::sat\n", - expr("void f(int x) { return 2+x==3; }", "==")); - } - - - void pointer1() { - const char code[] = "void f(unsigned char *p) { return *p == 7; }"; - ASSERT_EQUALS("[$1],[:]=?,null", getRange(code, "p")); - ASSERT_EQUALS("(and (>= $3 0) (<= $3 255))\n" - "(= $3 7)\n" - "z3::sat\n", - expr(code, "==")); - } - - void pointer2() { - const char code[] = "void f(unsigned char *p) { return p[2] == 7; }"; - ASSERT_EQUALS("(and (>= $3 0) (<= $3 255))\n" - "(= $3 7)\n" - "z3::sat\n", - expr(code, "==")); - } - - void pointer3() { - const char code[] = "void f(void *p) {\n" - " double *data = (double *)p;\n" - " return *data;" - "}"; - ASSERT_EQUALS("[$1],[:]=?,null", getRange(code, "p")); - ASSERT_EQUALS("[$4],[:]=?,null", getRange(code, "data")); - } - - void pointerAlias1() { - ASSERT_EQUALS("3", getRange("int f() { int x; int *p = &x; x = 3; return *p; }", "return*p")); - } - - void pointerAlias2() { - ASSERT_EQUALS("1", getRange("int f() { int x; int *p = &x; *p = 1; return *p; }", "return*p")); - } - - void pointerAlias3() { - ASSERT_EQUALS("7", getRange("int f() {\n" - " int x = 18;\n" - " int *p = &x;\n" - " *p = 7;\n" - " return x;\n" - "}", "x", 5)); - } - - void pointerAlias4() { - ASSERT_EQUALS("71", getRange("int f() { int x[10]; int *p = x+3; *p = 71; return x[3]; }", "x[3]")); - } - - void pointerNull1() { - ASSERT_EQUALS("1", getRange("void f(void *p) { p = NULL; p += 1; }", "p+=1")); - } - - - void structMember1() { - ASSERT_EQUALS("(and (>= $2 0) (<= $2 255))\n" - "(and (>= $3 0) (<= $3 255))\n" - "(= (+ $2 $3) 0)\n" - "z3::sat\n", - expr("struct S {\n" - " unsigned char a;\n" - " unsigned char b;\n" - "};\n" - "void f(struct S s) { return s.a + s.b == 0; }", "==")); - } - - void structMember2() { - const char code[] = "struct S { int x; };\n" - "void foo(struct S *s) { return s->x == 123; }"; - - const char expected[] = "(and (>= $3 (- 2147483648)) (<= $3 2147483647))\n" - "(= $3 123)\n" - "z3::sat\n"; - - ASSERT_EQUALS(expected, expr(code, "==")); - } - - void structMember3() { - const char code[] = "struct S { int x; };\n" - "void foo(struct S *s) {\n" - " s->x = iter->second.data;\n" // assign some unknown value - " return s->x == 1;\n" - "}"; - - const char expected[] = "(and (>= $3 (- 2147483648)) (<= $3 2147483647))\n" - "(= $3 1)\n" - "z3::sat\n"; - - ASSERT_EQUALS(expected, expr(code, "==")); - } - - void pointerToStructInLoop() { - const char code[] = "struct S { int x; };\n" - "void foo(struct S *s) {\n" - " while (1)\n" - " s->x = 42; \n" - "}"; - - const char expected[] = "(and (>= $3 (- 2147483648)) (<= $3 2147483647))\n" - "(= $3 42)\n" - "z3::sat\n"; - - TODO_ASSERT_EQUALS(expected, "", expr(code, "==")); - } - - - void ternaryOperator1() { - const char code[] = "void foo(signed char x) {\n" - " x = (x > 0) ? (0==x) : 0;\n" - "}"; - - const char expected[] = "(> $1 0)\n" - "(and (>= $1 (- 128)) (<= $1 127))\n" - "(= 0 $1)\n" - "z3::unsat\n"; - - ASSERT_EQUALS(expected, expr(code, "==")); - } -}; - -REGISTER_TEST(TestExprEngine) diff --git a/test/testrunner.vcxproj b/test/testrunner.vcxproj index 9dce50bcb..39da184bb 100755 --- a/test/testrunner.vcxproj +++ b/test/testrunner.vcxproj @@ -45,7 +45,6 @@ - @@ -313,4 +312,4 @@ - \ No newline at end of file + diff --git a/test/testrunner.vcxproj.filters b/test/testrunner.vcxproj.filters index dc6225262..b311a9d80 100644 --- a/test/testrunner.vcxproj.filters +++ b/test/testrunner.vcxproj.filters @@ -211,9 +211,6 @@ Source Files - - Source Files - Source Files diff --git a/test/testsuite.h b/test/testsuite.h index 13bbf7fde..d5078a609 100644 --- a/test/testsuite.h +++ b/test/testsuite.h @@ -104,7 +104,6 @@ protected: void processOptions(const options& args); public: - void bughuntingReport(const std::string & /*str*/) override {} void reportOut(const std::string &outmsg, Color c = Color::Reset) override; void reportErr(const ErrorMessage &msg) override; void run(const std::string &str); diff --git a/tools/dmake.cpp b/tools/dmake.cpp index 0d88b1eb7..88e79e18a 100644 --- a/tools/dmake.cpp +++ b/tools/dmake.cpp @@ -55,9 +55,6 @@ static std::string objfiles(const std::vector &files) static void getDeps(const std::string &filename, std::vector &depfiles) { - if (filename == "externals/z3_version.h") - return; - static const std::vector externalfolders{"externals", "externals/picojson", "externals/simplecpp", "externals/tinyxml2" }; // Is the dependency already included? @@ -239,13 +236,6 @@ int main(int argc, char **argv) fout << "# To compile with rules, use 'make HAVE_RULES=yes'\n"; makeConditionalVariable(fout, "HAVE_RULES", "no"); - // Z3 is an optional dependency now.. - makeConditionalVariable(fout, "USE_Z3", "no"); - fout << "ifeq ($(USE_Z3),yes)\n" - << " CPPFLAGS += -DUSE_Z3\n" - << " LIBS += -lz3\n" - << "endif\n"; - // use match compiler.. fout << "# use match compiler\n"; fout << "ifeq ($(SRCDIR),build)\n" diff --git a/win_installer/config.wxi b/win_installer/config.wxi index c08a42042..4b6853a91 100644 --- a/win_installer/config.wxi +++ b/win_installer/config.wxi @@ -8,7 +8,6 @@ - diff --git a/win_installer/cppcheck.wxs b/win_installer/cppcheck.wxs index 0f297499f..400063d68 100644 --- a/win_installer/cppcheck.wxs +++ b/win_installer/cppcheck.wxs @@ -20,9 +20,6 @@ - - - @@ -167,7 +164,6 @@ - @@ -188,7 +184,6 @@ Display='expand' Level='1' AllowAdvertise='no' ConfigurableDirectory='INSTALLDIR' > - diff --git a/win_installer/productInfo.wxi b/win_installer/productInfo.wxi index 48d7148b9..992efc985 100644 --- a/win_installer/productInfo.wxi +++ b/win_installer/productInfo.wxi @@ -10,7 +10,6 @@ -