Skip to content

Commit

Permalink
Not allowing disabling Clangsa modeling checkers
Browse files Browse the repository at this point in the history
When a Clang Static Analyzer checker is disabled in CodeChecker,
clang is invoked with the "analyzer-disable-checker" flag.
This allows the user disabling core modeling checkers such as
unix.DynamicMemoryModeling. This causes malfunctioning of depending checkers.

Breaking Change:
After this patch, modeling and debug checkers (listed with clang -cc1 -analyzer-checker-help-developer)
will not be listed and cannot be disabled through CodeChecker with the --enable and --disable flags.

They can be enabled/disabled through the Clang Static Analyzer specific --saargs flag only.
  • Loading branch information
dkrupp committed Feb 25, 2022
1 parent 9a944f8 commit 43f6bd8
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 60 deletions.
20 changes: 14 additions & 6 deletions analyzer/codechecker_analyzer/analyzers/clangsa/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@ def get_analyzer_checkers(
"""Return the list of the supported checkers."""
checker_list_args = clang_options.get_analyzer_checkers_cmd(
cfg_handler,
alpha=True)
alpha=True,
debug=False)
return parse_clang_help_page(checker_list_args, 'CHECKERS:', environ)

@classmethod
Expand Down Expand Up @@ -227,16 +228,23 @@ def construct_analyzer_cmd(self, result_handler):
['-Xclang', '-analyzer-config', '-Xclang', cfg])

# Config handler stores which checkers are enabled or disabled.
disabled_checkers = []
enabled_checkers = []
for checker_name, value in config.checks().items():
state, _ = value
if state == CheckerState.enabled:
analyzer_cmd.extend(['-Xclang',
'-analyzer-checker=' + checker_name])
enabled_checkers.append(checker_name)
elif state == CheckerState.disabled:
analyzer_cmd.extend(['-Xclang',
'-analyzer-disable-checker=' +
checker_name])
disabled_checkers.append(checker_name)

if enabled_checkers:
analyzer_cmd.extend(['-Xclang',
'-analyzer-checker=' +
','.join(enabled_checkers)])
if disabled_checkers:
analyzer_cmd.extend(['-Xclang',
'-analyzer-disable-checker=' +
','.join(disabled_checkers)])
# Enable aggressive-binary-operation-simplification option.
analyzer_cmd.extend(
clang_options.get_abos_options(config.version_info))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
LOG = get_logger('analyzer')


def get_analyzer_checkers_cmd(cfg_handler, alpha=True, debug=True):
def get_analyzer_checkers_cmd(cfg_handler, alpha=True, debug=False):
"""Return the checkers list getter command which depends on the used clang
version.
Expand Down
36 changes: 36 additions & 0 deletions analyzer/tests/functional/analyze/test_analyze.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ def setUp(self):
self.missing_checker_regex = re.compile(
r"No checker\(s\) with these names was found")

self.disabling_modeling_checker_regex = re.compile(
r"analyzer-disable-checker=.*unix.cstring.CStringModeling.*")

def tearDown(self):
"""Restore environment after tests have ran."""
os.chdir(self.__old_pwd)
Expand Down Expand Up @@ -850,6 +853,39 @@ def test_invalid_disabled_checker_name(self):
errcode = process.returncode
self.assertEqual(errcode, 0)

def test_disabling_clangsa_modeling_checkers(self):
"""Warn in case a modeling checker is disabled from clangsa"""
build_json = os.path.join(self.test_workspace, "build_success.json")
analyze_cmd = [self._codechecker_cmd, "analyze", build_json,
"--analyzers", "clangsa", "-o", self.report_dir,
"-d", "unix", "--verbose", "debug_analyzer"]

source_file = os.path.join(self.test_dir, "success.c")
build_log = [{"directory": self.test_workspace,
"command": "gcc -c " + source_file,
"file": source_file
}]

with open(build_json, 'w',
encoding="utf-8", errors="ignore") as outfile:
json.dump(build_log, outfile)

print(analyze_cmd)
process = subprocess.Popen(
analyze_cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=self.test_dir,
encoding="utf-8",
errors="ignore")
out, _ = process.communicate()

match = self.disabling_modeling_checker_regex.search(out)
self.assertIsNone(match)

errcode = process.returncode
self.assertEqual(errcode, 0)

def test_multiple_invalid_checker_names(self):
"""Warn in case of multiple invalid checker names."""
build_json = os.path.join(self.test_workspace, "build_success.json")
Expand Down
12 changes: 6 additions & 6 deletions analyzer/tests/functional/ctu_failure/test_ctu_failure.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def test_ctu_failure_zip(self):
# with a specified name is analyzed.
output, result = self.__do_ctu_all(
on_demand=False, extra_args=["--verbose", "debug",
"-e", "debug.ExprInspection"])
"--saargs", "./ctu_failure.saargs"])
self.assertEqual(result, 3, "Analyzer survived the failure.")

# lib.c should be logged as its AST is loaded by Clang
Expand Down Expand Up @@ -185,7 +185,7 @@ def test_ctu_on_demand_failure_zip(self):
# with a specified name is analyzed.
output, result = self.__do_ctu_all(
on_demand=True, extra_args=["--verbose", "debug",
"-e", "debug.ExprInspection"])
"--saargs", "./ctu_failure.saargs"])
self.assertEqual(result, 3, "Analyzer survived the failure.")

# lib.c should be logged as its AST is loaded by Clang
Expand Down Expand Up @@ -235,7 +235,7 @@ def test_ctu_failure_zip_with_headers(self):
# with a specified name is analyzed.
output, result = self.__do_ctu_all(
on_demand=False, extra_args=["--verbose", "debug",
"-e", "debug.ExprInspection"])
"--saargs", "./ctu_failure.saargs"])
self.assertEqual(result, 3, "Analyzer survived the failure.")

# lib.c should be logged as its AST is loaded by Clang
Expand Down Expand Up @@ -287,7 +287,7 @@ def test_ctu_on_demand_failure_zip_with_headers(self):
# with a specified name is analyzed.
output, result = self.__do_ctu_all(
on_demand=True, extra_args=["--verbose", "debug",
"-e", "debug.ExprInspection"])
"--saargs", "./ctu_failure.saargs"])
self.assertEqual(result, 3, "CTU analyzing should fail.")

# lib.c should be logged as its AST is loaded by Clang
Expand Down Expand Up @@ -334,7 +334,7 @@ def test_ctu_fallback(self):

output, result = self.__do_ctu_all(
on_demand=False, extra_args=["--verbose", "debug",
"-e", "debug.ExprInspection",
"--saargs", "./ctu_failure.saargs",
"--ctu-reanalyze-on-failure"])
self.assertEqual(result, 3, "CTU analyzing should fail.")

Expand Down Expand Up @@ -362,7 +362,7 @@ def test_ctu_on_demand_fallback(self):

output, result = self.__do_ctu_all(
on_demand=True, extra_args=["--verbose", "debug",
"-e", "debug.ExprInspection",
"--saargs", "./ctu_failure.saargs",
"--ctu-reanalyze-on-failure"])
self.assertEqual(result, 3, "CTU analyzing should fail.")

Expand Down
1 change: 1 addition & 0 deletions analyzer/tests/projects/ctu_failure/ctu_failure.saargs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-Xclang -analyzer-checker=debug.ExprInspection
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-Xclang -analyzer-checker=debug.ExprInspection
95 changes: 48 additions & 47 deletions docs/analyzer/checker_and_analyzer_configuration.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
# Configure Clang Static Analyzer and checkers

Analyzer configuration can be done through the `--saargs` analysis option which
forwards arguments without modification to the Clang Static Analyzer:
## Analyzer Configuration <a name="analyzer-configuration"></a>

The analysis can be configured using analyzer wide configuration parameters. These parameters may have effect on the whole analysis, affecting the result of all checkers.

Listing the avaialable configuration options:
`CodeChecker analyzers --analyzer-config clangsa --details`

Setting analyzer configuration opions:
`CodeChecker analyze --analyzer-config <key=value>`

You can find a comprehensive list of analyzer configuration options at the
[clang static analyzer documentation](https://github.com/llvm-mirror/clang/tree/master/docs) pages.

## Checker Configuration <a name="checker-configuration"></a>

Clang Static Analyzer checkers can be enabled and disabled using the `CodeChekcer analyze --enable <checker_name> --disable <checker_name>`
flags. You can list/enable/disable all checkers for Clang Static Analyzer, except for the developer (debug and modeling) checkers.

Some checkers can be customized using checker specific configuration options.

These can be listed using the `CodeChecker checkers --checker-config` command and can be set by `CodeChecker analyze --checker-config clangsa:<option-name>=<value>`.

You can find the documentation of the configuration options at hte
[Clang Static Analyzer checkers](https://github.com/llvm-mirror/clang/tree/master/lib/StaticAnalyzer/Checkers) page.

## Clang Static Analyzer Special Configuration Options
In special cases, when the checker and analyzer configurability that is provided by CodeChecker is not enough, the Clang Static analyzer configuration can be extended through the `--saargs` analysis option.
The content of the saargs file are forwarded as arguments without modification to the Clang Static Analyzer:
```
CodeChecker analyze --saargs static_analyzer.cfg
```
Expand All @@ -12,57 +38,22 @@ configuration options can be configured like this:
-Xclang -analyzer-config -Xclang unix.Malloc:Optimistic=true -Xclang -analyzer-max-loop -Xclang 20
```
__Before every configuration option '-Xclang' argument should be written and
all the configuration options sould be in one line!__
all the configuration options sould be in one line! __

In the `static_analyzer.cfg` example file we set a checker specific
configuration option `unix.Malloc:Optimistic=true` for the `unix.Malloc`
checker and a static analyzer configuration option `analyzer-max-loop` (the
maximum number of times the analyzer will go through a loop, the default
value is 4).

## Checker specific configuration options
This is not a comprehensive list view checker
[documentation or implementation](https://github.com/llvm-mirror/clang/tree/master/lib/StaticAnalyzer/Checkers)
for available configuration options:

| checker name | configuration option | default value | available values | description |
|--------------|--------------------------------|---------------|------------------|----------------------------------------------------------------------------------------|
| nullability | NoDiagnoseCallsToSystemHeaders | false | true/false | If true, the checker will not diagnose nullability issues for calls to system headers. |
| unix.Malloc | Optimistic | false | true/false | |


## Clang Static Analyzer configuration options
This is not a comprehesive list, check out the
[clang static analyzer documentation](https://github.com/llvm-mirror/clang/tree/master/docs)
or source code for more details about the configuration options.

| configuration option | default value | available values | description |
|---------------------------------------|-------------------|------------------------------------------|-----------------------------------------------------------------------------------------------------|
| analyzer-max-loop | 4 | | |
| inline-lambdas | true | | |
| ipa | dynamic-bifurcate | | [inter procedural analysis](https://github.com/llvm-mirror/clang/blob/master/docs/analyzer/IPA.txt) |
| ipa-always-inline-size | 3 | | |
| mode | deep | deep, shallow | |
| max-inlinable-size | 100 | | 100 for deep mode, 4 for shallow |
| max-nodes | 225000 | | 22500 for deep, 75000 for shallow, maximum number of nodes for top level functions |
| unroll-loops | false | true/false | |
| widen-loops | false | true/false | |
| suppress-null-return-paths | false | | |
| c++-inlining | constructors | constructors, destructors, none, methods | [inlining options](https://github.com/llvm-mirror/clang/blob/master/docs/analyzer/IPA.txt) |
| leak-diagnostics-reference-allocation | false | true/false | |
| max-times-inline-large | 32 | | |
| region-store-small-struct-limit | 2 | | |
| path-diagnostics-alternate | false | true/false | |
| report-in-main-source-file | true | true/false | |
| min-cfg-size-treat-functions-as-large | 14 | | |
| cfg-conditional-static-initializers | true | | |
| cfg-implicit-dtors | true | true/false | |
| cfg-lifetime | false | true/false | |
| cfg-loopexit | false | true/false | |
| cfg-temporary-dtors | false | true/false | |
| faux-bodies | true | true/false | |
| graph-trim-interval | 1000 | | |
### Enabling developer checkers
You cannot enable/disable developer checkers in CodeChecker using the `--enable` or `--disable` flags.

These (debug and modeling) checkers should not be used normally. The are typically used by ClangSA developers debug the analysis or to write test cases. These checkers can be listed by `clang -cc1 -analyzer-checker-help-developer`.

If they are needed, they can be switched on using the following command
`CodeChecker analyzer --saarg saarg.config`, where the content of saarg.config is for example
`-Xclang -analyzer-checker=debug.ExprInspection`.

## Z3 Theorem Prover
The static analyzer supports using the
Expand Down Expand Up @@ -97,14 +88,24 @@ command with the `--z3-refutation` option.
You can read more about refutation with the Z3 SMT Solver
[here](https://docs.google.com/document/d/1-HEblH92VxdxDp04vDKjFa4_ZL9l2oPVLFtQUfLKSOo/).

# Configure Clang tidy checkers
# Configuring Clang tidy

## Configuring the analyzer and checkers

You can configure the clang-tidy analyzer and its checkers through CodeChecker with the `--analyzer-config` and the `--checker-config`
flags of `CodeChecker analyze/check` commands as described in sections [Analyzer Configuration](#analyzer-configuration) and [Checker Configuration](#checker-configuration).


## Using Clang tidy configuration files

__clang-tidy__ attempts to read configuration for each analyzed source file
If you want to control the configuration of clang tidy from the `.clang-tidy` configuration files (instead of the CodeChecker command line) you can use the `clang-tidy:take-config-from-directory=true` option. It will skip setting the checkers and checker configuration from CodeChecker (even if a profile was specified).

Then __clang-tidy__ will attempt to read configuration for each analyzed source file
from a `.clang-tidy` file located in the closest parent directory of the
analyzed source file.

So by executing `CodeChecker analyze compile_commands.json -o ./reports --analyzer-config 'clang-tidy:take-config-from-directory=true'`, CodeChecker will generate a clang-tidy command which will NOT contain the -checks option at all so your .clang-tidy file will take precedence.

The `.clang-tidy` configuration file can be in JSON or YAML format.

JSON:
Expand Down

0 comments on commit 43f6bd8

Please sign in to comment.