diff --git a/.github/workflows/install-deps.sh b/.github/workflows/install-deps.sh index c9d37e56c9..37bf443384 100755 --- a/.github/workflows/install-deps.sh +++ b/.github/workflows/install-deps.sh @@ -2,11 +2,13 @@ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add - sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-14 main' -y +# Required for g++-13, as the latest LTS at the time of this change hasn't made it available. +sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get update -q sudo apt-get install \ - g++-9 \ + g++-13 \ gcc-multilib \ libc6-dev-i386 \ libpq-dev \ @@ -20,3 +22,4 @@ sudo apt-get install \ sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-14 9999 sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-14 9999 sudo update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-14 9999 +sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 9999 diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 70b5129feb..26836213a0 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -73,12 +73,12 @@ jobs: - name: "Install run-time dependencies (Linux)" if: ${{ matrix.os == 'ubuntu-20.04' }} run: - sudo apt-get update && sudo apt-get install g++ clang clang-tidy cppcheck + sudo apt-get update && sudo apt-get install g++-13 clang clang-tidy cppcheck - name: "Install run-time dependencies (OSX)" if: ${{ matrix.os == 'macos-10.15' }} run: - brew install llvm cppcheck + brew install llvm cppcheck g++-13 - name: "Install run-time dependencies (Windows)" if: ${{ matrix.os == 'windows-2019' }} diff --git a/analyzer/.coverage b/analyzer/.coverage new file mode 100644 index 0000000000..80261d58ae Binary files /dev/null and b/analyzer/.coverage differ diff --git a/analyzer/codechecker_analyzer/analyzers/analyzer_types.py b/analyzer/codechecker_analyzer/analyzers/analyzer_types.py index b1400b2258..943a11ee27 100644 --- a/analyzer/codechecker_analyzer/analyzers/analyzer_types.py +++ b/analyzer/codechecker_analyzer/analyzers/analyzer_types.py @@ -24,12 +24,14 @@ from .clangtidy.analyzer import ClangTidy from .clangsa.analyzer import ClangSA from .cppcheck.analyzer import Cppcheck +from .gcc.analyzer import Gcc LOG = get_logger('analyzer') supported_analyzers = {ClangSA.ANALYZER_NAME: ClangSA, ClangTidy.ANALYZER_NAME: ClangTidy, - Cppcheck.ANALYZER_NAME: Cppcheck} + Cppcheck.ANALYZER_NAME: Cppcheck, + Gcc.ANALYZER_NAME: Gcc} def is_ctu_capable(): diff --git a/analyzer/codechecker_analyzer/analyzers/gcc/__init__.py b/analyzer/codechecker_analyzer/analyzers/gcc/__init__.py new file mode 100644 index 0000000000..4259749345 --- /dev/null +++ b/analyzer/codechecker_analyzer/analyzers/gcc/__init__.py @@ -0,0 +1,7 @@ +# ------------------------------------------------------------------------- +# +# Part of the CodeChecker project, under the Apache License v2.0 with +# LLVM Exceptions. See LICENSE for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# ------------------------------------------------------------------------- diff --git a/analyzer/codechecker_analyzer/analyzers/gcc/analyzer.py b/analyzer/codechecker_analyzer/analyzers/gcc/analyzer.py new file mode 100644 index 0000000000..27d181c4e9 --- /dev/null +++ b/analyzer/codechecker_analyzer/analyzers/gcc/analyzer.py @@ -0,0 +1,274 @@ +# ------------------------------------------------------------------------- +# +# Part of the CodeChecker project, under the Apache License v2.0 with +# LLVM Exceptions. See LICENSE for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# ------------------------------------------------------------------------- +""" +""" +from collections import defaultdict +# TODO distutils will be removed in python3.12 +from distutils.version import StrictVersion +import os +import pickle +import shlex +import subprocess + +from codechecker_common.logger import get_logger + +from codechecker_analyzer import analyzer_context + +from .. import analyzer_base +from ..flag import has_flag + +from .config_handler import GccConfigHandler +from .result_handler import GccResultHandler + +LOG = get_logger('analyzer.gcc') + + +class Gcc(analyzer_base.SourceAnalyzer): + """ + Constructs the Gcc analyzer commands. + """ + + ANALYZER_NAME = 'gcc' + + @classmethod + def analyzer_binary(cls): + return analyzer_context.get_context() \ + .analyzer_binaries[cls.ANALYZER_NAME] + + @classmethod + def get_version(cls, env=None): + """ Get analyzer version information. """ + return cls.__get_analyzer_version(cls.analyzer_binary(), env) + + def add_checker_config(self, checker_cfg): + LOG.error("Checker configuration for Gcc is not implemented yet") + + def get_analyzer_mentioned_files(self, output): + """ + Return a collection of files that were mentioned by the analyzer in + its standard outputs, which should be analyzer_stdout or + analyzer_stderr from a result handler. + """ + pass + + def construct_analyzer_cmd(self, result_handler): + """ + Construct analyzer command for gcc. + """ + # TODO: This is not a try-catch block, like the other analyzers. Why + # should it? Should the others be? When can list creating list to have + # unforeseen exceptions where a general catch is justified? + config = self.config_handler + + # We don't want GCC do start linking, but -fsyntax-only stops the + # compilation process too early for proper diagnostics generation. + analyzer_cmd = [Gcc.analyzer_binary(), '-fanalyzer', '-c', + '-o/dev/null'] + + # Add extra arguments. + analyzer_cmd.extend(config.analyzer_extra_arguments) + + analyzer_cmd.extend(self.buildaction.analyzer_options) + + analyzer_cmd.append('-fdiagnostics-format=sarif-file') + + compile_lang = self.buildaction.lang + if not has_flag('-x', analyzer_cmd): + analyzer_cmd.extend(['-x', compile_lang]) + + analyzer_cmd.append(self.source_file) + + LOG.debug_analyzer("Running analysis command " + f"'{shlex.join(analyzer_cmd)}'") + + return analyzer_cmd + + @classmethod + def get_analyzer_checkers(cls): + """ + Return the list of the supported checkers. + """ + command = [cls.analyzer_binary(), "--help=warning"] + checker_list = [] + + try: + output = subprocess.check_output(command) + + # Still contains the help message we need to remove. + for entry in output.decode().split('\n'): + warning_name, _, description = entry.strip().partition(' ') + if warning_name.startswith('-Wanalyzer'): + checker_list.append((warning_name, description)) + return checker_list + except (subprocess.CalledProcessError) as e: + LOG.error(e.stderr) + except (OSError) as e: + LOG.error(e.errno) + return [] + + @classmethod + def get_analyzer_config(cls): + """ + Config options for gcc. + """ + # TODO + return [] + + @classmethod + def get_checker_config(cls): + """ + TODO add config options for gcc checkers. + """ + # TODO + return [] + + def analyze(self, analyzer_cmd, res_handler, proc_callback=None): + env = None + + original_env_file = os.environ.get( + 'CODECHECKER_ORIGINAL_BUILD_ENV') + if original_env_file: + with open(original_env_file, 'rb') as env_file: + env = pickle.load(env_file, encoding='utf-8') + + return super().analyze(analyzer_cmd, res_handler, proc_callback, env) + + def post_analyze(self, result_handler: GccResultHandler): + """ + Post process the reuslts after the analysis. + Will copy the sarif files created by gcc into the root of the reports + folder. + Renames the source plist files to *.plist.bak because + The report parsing of the Parse command is done recursively. + + """ + pass + + @classmethod + def resolve_missing_binary(cls, configured_binary, env): + """ + In case of the configured binary for the analyzer is not found in the + PATH, this method is used to find a callable binary. + """ + + LOG.error("%s not found in path for GCC!", configured_binary) + + # if os.path.isabs(configured_binary): + # # Do not autoresolve if the path is an absolute path as there + # # is nothing we could auto-resolve that way. + # return False + + # cppcheck = get_binary_in_path(['g++-13'], + # r'^cppcheck(-\d+(\.\d+){0,2})?$', + # env) + + # if cppcheck: + # LOG.debug("Using '%s' for Cppcheck!", cppcheck) + # return cppcheck + + @classmethod + def __get_analyzer_version(cls, analyzer_binary, env): + """ + Return the analyzer version. + """ + # --version outputs a lot of garbage as well (like copyright info), + # this only contains the version info. + version = [analyzer_binary, '-dumpfullversion'] + try: + output = subprocess.check_output(version, + env=env, + encoding="utf-8", + errors="ignore") + return output + except (subprocess.CalledProcessError, OSError) as oerr: + LOG.warning("Failed to get analyzer version: %s", + ' '.join(version)) + LOG.warning(oerr) + + return None + + @classmethod + def version_compatible(cls, configured_binary, environ): + """ + Check the version compatibility of the given analyzer binary. + """ + analyzer_version = \ + cls.__get_analyzer_version(configured_binary, environ) + + # The analyzer version should be above 13.0.0 because the + # '-fdiagnostics-format=sarif-file' argument was introduced in this + # release. + if analyzer_version >= StrictVersion("13.0.0"): + return True + + # FIXME: Maybe this isn't to place to emit an error, especially when + # we cycle over multiple binarier to find the correct one. + LOG.error("GCC binary found is too old at " + f"v{analyzer_version.strip()}; minimum version is 13.0.0.") + return False + + def construct_result_handler(self, buildaction, report_output, + skiplist_handler): + """ + See base class for docs. + """ + res_handler = GccResultHandler(buildaction, report_output, + self.config_handler.report_hash) + + res_handler.skiplist_handler = skiplist_handler + + return res_handler + + @classmethod + def construct_config_handler(cls, args): + context = analyzer_context.get_context() + handler = GccConfigHandler() + + analyzer_config = defaultdict(list) + + if 'analyzer_config' in args and \ + isinstance(args.analyzer_config, list): + for cfg in args.analyzer_config: + if cfg.analyzer == cls.ANALYZER_NAME: + analyzer_config[cfg.option].append(cfg.value) + + handler.analyzer_config = analyzer_config + + # check_env = context.analyzer_env + + # # Overwrite PATH to contain only the parent of the cppcheck binary. + # if os.path.isabs(Gcc.analyzer_binary()): + # check_env['PATH'] = os.path.dirname(Gcc.analyzer_binary()) + + checkers = cls.get_analyzer_checkers() + + # Cppcheck can and will report with checks that have a different + # name than marked in the --errorlist xml. To be able to suppress + # these reports, the checkerlist needs to be extended by those found + # in the label file. + checker_labels = context.checker_labels + checkers_from_label = checker_labels.checkers("gcc") + parsed_set = set([data[0] for data in checkers]) + for checker in set(checkers_from_label): + if checker not in parsed_set: + checkers.append((checker, "")) + + try: + cmdline_checkers = args.ordered_checkers + except AttributeError: + LOG.debug_analyzer('No checkers were defined in ' + 'the command line for %s', + cls.ANALYZER_NAME) + cmdline_checkers = [] + + handler.initialize_checkers( + checkers, + cmdline_checkers, + 'enable_all' in args and args.enable_all) + + return handler diff --git a/analyzer/codechecker_analyzer/analyzers/gcc/config_handler.py b/analyzer/codechecker_analyzer/analyzers/gcc/config_handler.py new file mode 100644 index 0000000000..0e88e50ee6 --- /dev/null +++ b/analyzer/codechecker_analyzer/analyzers/gcc/config_handler.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------------- +# +# Part of the CodeChecker project, under the Apache License v2.0 with +# LLVM Exceptions. See LICENSE for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# ------------------------------------------------------------------------- +""" +Config handler for Gcc analyzer. +""" +from .. import config_handler + + +class GccConfigHandler(config_handler.AnalyzerConfigHandler): + """ + Configuration handler for Gcc analyzer. + """ + pass diff --git a/analyzer/codechecker_analyzer/analyzers/gcc/result_handler.py b/analyzer/codechecker_analyzer/analyzers/gcc/result_handler.py new file mode 100644 index 0000000000..6a02648bf6 --- /dev/null +++ b/analyzer/codechecker_analyzer/analyzers/gcc/result_handler.py @@ -0,0 +1,88 @@ +# ------------------------------------------------------------------------- +# +# Part of the CodeChecker project, under the Apache License v2.0 with +# LLVM Exceptions. See LICENSE for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# ------------------------------------------------------------------------- +""" +Result handler for Gcc. +""" +from typing import Optional +from pathlib import Path +import shutil +import os + +from codechecker_report_converter.report.parser.base import AnalyzerInfo +from codechecker_report_converter.analyzers.gcc.analyzer_result import \ + AnalyzerResult +from codechecker_report_converter.report import report_file +from codechecker_report_converter.report.hash import get_report_hash, HashType + +from codechecker_common.logger import get_logger +from codechecker_common.skiplist_handler import SkipListHandlers + +from ..result_handler_base import ResultHandler + +LOG = get_logger('analyzer.gcc') + + +class GccResultHandler(ResultHandler): + """ + Create analyzer result file for Gcc output. + """ + + def __init__(self, *args, **kwargs): + self.analyzer_info = AnalyzerInfo(name=AnalyzerResult.TOOL_NAME) + self.gcc_analyzer_result = AnalyzerResult() + + super(GccResultHandler, self).__init__(*args, **kwargs) + + def postprocess_result(self, skip_handlers: Optional[SkipListHandlers]): + """ + Generate analyzer result output file which can be parsed and stored + into the database. + """ + LOG.debug_analyzer(self.analyzer_stdout) + gcc_output_file = self.analyzed_source_file + ".sarif" + + # Gcc doesn't create any files when there are no diagnostics. + # Unfortunately, we can't tell whethet the file missing was because of + # that or some other error, we need to bail out here. + if not os.path.exists(gcc_output_file): + return + + reports = report_file.get_reports( + gcc_output_file, self.checker_labels, + source_dir_path=self.source_dir_path) + + reports = [r for r in reports if not r.skip(skip_handlers)] + # for report in reports: + # # TODO check if prefix cascading still occurs. + # if not report.checker_name.startswith("gcc-"): + # report.checker_name = "gcc-" + report.checker_name + + hash_type = HashType.PATH_SENSITIVE + if self.report_hash_type == 'context-free-v2': + hash_type = HashType.CONTEXT_FREE + elif self.report_hash_type == 'diagnostic-message': + hash_type = HashType.DIAGNOSTIC_MESSAGE + + for report in reports: + report.report_hash = get_report_hash(report, hash_type) + + report_file.create( + self.analyzer_result_file, reports, self.checker_labels, + self.analyzer_info) + + # TODO Maybe move this to post_analyze? + gcc_out_folder = Path(self.workspace, "gcc") + gcc_out_folder.mkdir(exist_ok=True) + gcc_dest_file_name = \ + Path(gcc_out_folder, os.path.basename(self.analyzed_source_file) + + self.buildaction_hash + ".sarif.bak") + try: + shutil.move(gcc_output_file, gcc_dest_file_name) + except(OSError) as e: + LOG.error(f"Failed to move '{gcc_output_file}' to " + f"'{gcc_out_folder}': {e}") diff --git a/analyzer/codechecker_analyzer/cmd/analyzers.py b/analyzer/codechecker_analyzer/cmd/analyzers.py index d66a190340..d599695895 100644 --- a/analyzer/codechecker_analyzer/cmd/analyzers.py +++ b/analyzer/codechecker_analyzer/cmd/analyzers.py @@ -145,6 +145,8 @@ def main(args): elif args.dump_config == 'cppcheck': # TODO: Not supported by CppCheck yet! LOG.warning("'--dump-config cppcheck' is not supported.") + elif args.dump_config == 'gcc': + raise NotImplementedError('--dump-config') return diff --git a/analyzer/codechecker_analyzer/cmd/checkers.py b/analyzer/codechecker_analyzer/cmd/checkers.py index 273ac632e3..e55032dc8d 100644 --- a/analyzer/codechecker_analyzer/cmd/checkers.py +++ b/analyzer/codechecker_analyzer/cmd/checkers.py @@ -545,6 +545,10 @@ def __print_checker_config(args: argparse.Namespace): if analyzer != "cppcheck": analyzer_failures.append(analyzer) continue + # TODO + if analyzer != "gcc": + analyzer_failures.append(analyzer) + continue rows.extend((':'.join((analyzer, c[0])), c[1]) if 'details' in args else (':'.join((analyzer, c[0])),) for c in configs) diff --git a/analyzer/pytest.ini b/analyzer/pytest.ini index 7ee6b8962d..12ad627b24 100644 --- a/analyzer/pytest.ini +++ b/analyzer/pytest.ini @@ -10,4 +10,4 @@ addopts = # --maxfail=1 # do not capture stdout - --capture=sys + --capture=no diff --git a/analyzer/tests/functional/analyze/test_analyze.py b/analyzer/tests/functional/analyze/test_analyze.py index 3cc6b53ede..39027cc447 100644 --- a/analyzer/tests/functional/analyze/test_analyze.py +++ b/analyzer/tests/functional/analyze/test_analyze.py @@ -1134,7 +1134,7 @@ def test_disable_all_checkers(self): out, _ = process.communicate() # Checkers of all 3 analyzers are disabled. - self.assertEqual(out.count("No checkers enabled for"), 3) + self.assertEqual(out.count("No checkers enabled for"), 4) def test_analyzer_and_checker_config(self): """Test analyzer configuration through command line flags.""" diff --git a/analyzer/tests/functional/analyze_and_parse/test_analyze_and_parse.py b/analyzer/tests/functional/analyze_and_parse/test_analyze_and_parse.py index 3ad7890b2b..98fabd73ce 100644 --- a/analyzer/tests/functional/analyze_and_parse/test_analyze_and_parse.py +++ b/analyzer/tests/functional/analyze_and_parse/test_analyze_and_parse.py @@ -223,7 +223,8 @@ def check_one_file(self, path, mode): "[] - Enabled checkers:", "clang-tidy:", "clangsa:", - "cppcheck:"] + "cppcheck:", + "gcc:"] for line in output: # replace timestamps line = re.sub(r'\[\w+ \d{4}-\d{2}-\d{2} \d{2}:\d{2}\]', @@ -249,6 +250,7 @@ def check_one_file(self, path, mode): print(correct_output) print("Test output file: " + path) + self.maxDiff = None self.assertEqual(''.join(post_processed_output), correct_output) def test_json_output_for_macros(self): diff --git a/analyzer/tests/functional/analyze_and_parse/test_files/Makefile b/analyzer/tests/functional/analyze_and_parse/test_files/Makefile index 49d037b5cb..0e214e6557 100644 --- a/analyzer/tests/functional/analyze_and_parse/test_files/Makefile +++ b/analyzer/tests/functional/analyze_and_parse/test_files/Makefile @@ -49,3 +49,5 @@ cppcheck_include: $(CXX) -w cppcheck_include.cpp -I ./includes/ -o /dev/null cppcheck_undef_include: $(CXX) -w cppcheck_include.cpp -I./includes/ -U HAVE_NULL_DEREFERENCE -o /dev/null +gcc_simple: + $(CXX) -w gcc_simple.cpp -o /dev/null -c diff --git a/analyzer/tests/functional/analyze_and_parse/test_files/gcc_simple.cpp b/analyzer/tests/functional/analyze_and_parse/test_files/gcc_simple.cpp new file mode 100644 index 0000000000..cc1180eea1 --- /dev/null +++ b/analyzer/tests/functional/analyze_and_parse/test_files/gcc_simple.cpp @@ -0,0 +1,6 @@ +#include +void g(void *i) { + i = malloc(sizeof(int)); + free(i); + free(i); +} diff --git a/analyzer/tests/functional/analyze_and_parse/test_files/gcc_simple.output b/analyzer/tests/functional/analyze_and_parse/test_files/gcc_simple.output new file mode 100644 index 0000000000..d7573c3334 --- /dev/null +++ b/analyzer/tests/functional/analyze_and_parse/test_files/gcc_simple.output @@ -0,0 +1,57 @@ +NORMAL#CodeChecker log --output $LOGFILE$ --build "make gcc_simple" --quiet +NORMAL#CodeChecker analyze $LOGFILE$ --output $OUTPUT$ --analyzers gcc --enable=sensitive +NORMAL#CodeChecker parse $OUTPUT$ +CHECK#CodeChecker check --build "make gcc_simple" --output $OUTPUT$ --quiet --analyzers gcc --enable=sensitive +----------------------------------------------- +[] - Starting build... +[] - Using CodeChecker ld-logger. +[] - Build finished successfully. +[] - Starting static analysis ... +[] - [1/1] gcc analyzed gcc_simple.cpp successfully. +[] - ----==== Summary ====---- +[] - Successfully analyzed +[] - gcc: 1 +[] - Total analyzed compilation commands: 1 +[] - ----=================---- +[] - Analysis finished. +[] - To view results in the terminal use the "CodeChecker parse" command. +[] - To store results use the "CodeChecker store" command. +[] - See --help and the user guide for further options about parsing and storing the reports. +[] - ----=================---- +[LOW] gcc_simple.cpp:5:3: double-‘free’ of ‘i’ [-Wanalyzer-double-free] + free(i); + ^ + +Found 1 defect(s) in gcc_simple.cpp + + +----==== Severity Statistics ====---- +---------------------------- +Severity | Number of reports +---------------------------- +LOW | 1 +---------------------------- +----=================---- + +----==== Checker Statistics ====---- +----------------------------------------------------- +Checker name | Severity | Number of reports +----------------------------------------------------- +-Wanalyzer-double-free | LOW | 1 +----------------------------------------------------- +----=================---- + +----==== File Statistics ====---- +---------------------------------- +File name | Number of reports +---------------------------------- +gcc_simple.cpp | 1 +---------------------------------- +----=================---- + +----======== Summary ========---- +--------------------------------------------- +Number of processed analyzer result files | 2 +Number of analyzer reports | 1 +--------------------------------------------- +----=================---- diff --git a/config/labels/analyzers/gcc.json b/config/labels/analyzers/gcc.json new file mode 100644 index 0000000000..c71860920f --- /dev/null +++ b/config/labels/analyzers/gcc.json @@ -0,0 +1,285 @@ +{ + "analyzer": "gcc", + "labels": { + "-Wanalyzer-allocation-size": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-allocation-size", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-deref-before-check": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-deref-before-check", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-double-fclose": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-double-fclose", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-double-free": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-double-free", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-exposure-through-output-file": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-exposure-through-output-file", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-exposure-through-uninit-copy": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-exposure-through-uninit-copy", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-fd-access-mode-mismatch": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-fd-access-mode-mismatch", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-fd-double-close": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-fd-double-close", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-fd-leak": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-fd-leak", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-fd-phase-mismatch": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-fd-phase-mismatch", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-fd-type-mismatch": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-fd-type-mismatch", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-fd-use-after-close": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-fd-use-after-close", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-fd-use-without-check": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-fd-use-without-check", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-file-leak": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-file-leak", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-free-of-non-heap": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-free-of-non-heap", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-imprecise-fp-arithmetic": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-imprecise-fp-arithmetic", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-infinite-recursion": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-infinite-recursion", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-jump-through-null": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-jump-through-null", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-malloc-leak": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-malloc-leak", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-mismatching-deallocation": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-mismatching-deallocation", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-null-argument": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-null-argument", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-null-dereference": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-null-dereference", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-out-of-bounds": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-out-of-bounds", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-overlapping-buffers": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-overlapping-buffers", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-possible-null-argument": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-possible-null-argument", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-possible-null-dereference": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-possible-null-dereference", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-putenv-of-auto-var": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-putenv-of-auto-var", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-shift-count-negative": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-shift-count-negative", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-shift-count-overflow": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-shift-count-overflow", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-stale-setjmp-buffer": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-stale-setjmp-buffer", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-unsafe-call-within-signal-handler": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-unsafe-call-within-signal-handler", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-use-after-free": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-use-after-free", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-use-of-pointer-in-stale-stack-frame": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-use-of-pointer-in-stale-stack-frame", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-use-of-uninitialized-value": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-use-of-uninitialized-value", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-va-arg-type-mismatch": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-va-arg-type-mismatch", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-va-list-exhausted": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-va-list-exhausted", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-va-list-leak": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-va-list-leak", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-va-list-use-after-va-end": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-va-list-use-after-va-end", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-write-to-const": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-write-to-const", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ], + "-Wanalyzer-write-to-string-literal": [ + "doc_url:https://gcc.gnu.org/onlinedocs/gcc/Static-Analyzer-Options.html#index-Wanalyzer-write-to-string-literal", + "profile:extreme", + "profile:security", + "profile:sensitive", + "severity:LOW" + ] + } +} diff --git a/config/package_layout.json b/config/package_layout.json index abfef0572f..49579fe89b 100644 --- a/config/package_layout.json +++ b/config/package_layout.json @@ -3,7 +3,8 @@ "analyzers": { "clangsa": "clang", "clang-tidy": "clang-tidy", - "cppcheck": "cppcheck" + "cppcheck": "cppcheck", + "gcc": "g++" }, "clang-apply-replacements": "clang-apply-replacements" }, diff --git a/docs/README.md b/docs/README.md index 539092b6c0..2e6357e7e7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -32,7 +32,7 @@ macOS (OS X) development environment. # Main features ## Command line C/C++ Analysis - * Executes [_Clang-Tidy_](http://clang.llvm.org/extra/clang-tidy/), [_Clang Static Analyzer_](http://clang-analyzer.llvm.org/) with Cross-Translation Unit analysis, Statistical Analysis (when checkers are available), and [_Cppcheck_](https://cppcheck.sourceforge.io/). + * Executes [_Clang-Tidy_](http://clang.llvm.org/extra/clang-tidy/), [_Clang Static Analyzer_](http://clang-analyzer.llvm.org/) with Cross-Translation Unit analysis, Statistical Analysis (when checkers are available), [_Cppcheck_](https://cppcheck.sourceforge.io/), and the [_GCC Static Analyzer_](https://gcc.gnu.org/wiki/StaticAnalyzer). * Creates the JSON compilation database by wiretapping any build process (e.g., `CodeChecker log -b "make"`). * Automatically analyzes GCC cross-compiled projects: detecting GCC or Clang compiler configuration and forming the corresponding clang analyzer invocations. * Incremental analysis: Only the changed files and its dependencies need to be reanalyzed. @@ -238,8 +238,9 @@ The following commands are used to bootstrap CodeChecker on Ubuntu 20.04 LTS: # NOTE: clang or clang-tidy can be any sufficiently fresh version, and need not # come from package manager! # In case of Cppcheck, the minimal supported version is 1.80. -sudo apt-get install clang clang-tidy cppcheck build-essential curl gcc-multilib \ - git python3-dev python3-venv python3-setuptools +# In case of gcc, the minimal supported version is 13.0.0. +sudo apt-get install clang clang-tidy cppcheck g++ build-essential curl + gcc-multilib git python3-dev python3-venv python3-setuptools # Install nodejs dependency for web. In case of Debian/Ubuntu you can use the # following commands. For more information see the official docs: diff --git a/docs/analyzer/checker_and_analyzer_configuration.md b/docs/analyzer/checker_and_analyzer_configuration.md index 21c41a7d68..7adda1631d 100644 --- a/docs/analyzer/checker_and_analyzer_configuration.md +++ b/docs/analyzer/checker_and_analyzer_configuration.md @@ -267,3 +267,7 @@ CodeChecker check -l ./compile_commands.json \ --analyzer-config cppcheck:inconclusive=true \ # allow inconclusive reports -o ./reports ``` + +# Cppcheck + +TODO diff --git a/docs/analyzer/user_guide.md b/docs/analyzer/user_guide.md index 96c814995a..27ea582c9b 100644 --- a/docs/analyzer/user_guide.md +++ b/docs/analyzer/user_guide.md @@ -1168,11 +1168,13 @@ analyzer arguments: CodeChecker supports several analyzer tools. Currently, these analyzers are the [_Clang Static Analyzer_](http://clang-analyzer.llvm.org), -[_Clang-Tidy_](http://clang.llvm.org/extra/clang-tidy) and -[_Cppcheck_](http://cppcheck.sourceforge.net/). `--analyzers` can be -used to specify which analyzer tool should be used (by default, all supported -are used). The tools are completely independent, so either can be omitted if -not present as they are provided by different binaries. +[_Clang-Tidy_](http://clang.llvm.org/extra/clang-tidy), +[_Cppcheck_](http://cppcheck.sourceforge.net/) and +[_GCC Static Analyzer_](https://gcc.gnu.org/wiki/StaticAnalyzer). +`--analyzers` can be used to specify which analyzer tool should be used (by +default, all supported are used). The tools are completely independent, so +either can be omitted if not present as they are provided by different +binaries. See [Configure Clang Static Analyzer and checkers](checker_and_analyzer_configuration.md) documentation for a more detailed description how to use the `saargs`,