[llvm-branch-commits] [clang] [docs][clang] Finish MyST migration for analyzer docs (PR #216245)
Reid Kleckner via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Aug 13 21:26:25 PDT 2026
https://github.com/rnk created https://github.com/llvm/llvm-project/pull/216245
Tracking issue: #201242
See the [migration guide] for more information.
[migration guide]: https://llvm.org/docs/SphinxQuickstartTemplate.html#markdown-migration-guidelines
This is a stacked PR based on #216244 , which will be a standalone commit that
renames *.rst -> *.md before this PR lands for history preservation purposes.
This was prepared with rst2myst plus LLM-assisted cleanup. I paged through all the generated HTML looking for migration artifacts, and all of the differences I could find appear to be formatting error corrections. Please spot check my work and approve if it looks good. You can use the HTML links below to confirm it renders properly.
-----
Before/after validation links:
| Source file | Before HTML | After HTML |
| --- | --- | --- |
| `clang/docs/ScalableStaticAnalysis/developer-docs/ForceLinkerHeaders.md` | [before](https://clang.llvm.org/docs/ScalableStaticAnalysis/developer-docs/ForceLinkerHeaders.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/ScalableStaticAnalysis/developer-docs/ForceLinkerHeaders.html) |
| `clang/docs/ScalableStaticAnalysis/developer-docs/HowToExtend.md` | [before](https://clang.llvm.org/docs/ScalableStaticAnalysis/developer-docs/HowToExtend.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/ScalableStaticAnalysis/developer-docs/HowToExtend.html) |
| `clang/docs/ScalableStaticAnalysis/developer-docs/SummaryExtractionInternals.md` | [before](https://clang.llvm.org/docs/ScalableStaticAnalysis/developer-docs/SummaryExtractionInternals.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/ScalableStaticAnalysis/developer-docs/SummaryExtractionInternals.html) |
| `clang/docs/ScalableStaticAnalysis/developer-docs/index.md` | [before](https://clang.llvm.org/docs/ScalableStaticAnalysis/developer-docs/index.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/ScalableStaticAnalysis/developer-docs/index.html) |
| `clang/docs/ScalableStaticAnalysis/user-docs/SourceEditGeneration.md` | [before](https://clang.llvm.org/docs/ScalableStaticAnalysis/user-docs/SourceEditGeneration.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/ScalableStaticAnalysis/user-docs/SourceEditGeneration.html) |
| `clang/docs/ScalableStaticAnalysis/user-docs/SummaryExtraction.md` | [before](https://clang.llvm.org/docs/ScalableStaticAnalysis/user-docs/SummaryExtraction.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/ScalableStaticAnalysis/user-docs/SummaryExtraction.html) |
| `clang/docs/analyzer/checkers.md` | [before](https://clang.llvm.org/docs/analyzer/checkers.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/analyzer/checkers.html) |
| `clang/docs/analyzer/developer-docs/DebugChecks.md` | [before](https://clang.llvm.org/docs/analyzer/developer-docs/DebugChecks.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/analyzer/developer-docs/DebugChecks.html) |
| `clang/docs/analyzer/developer-docs/IPA.md` | [before](https://clang.llvm.org/docs/analyzer/developer-docs/IPA.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/analyzer/developer-docs/IPA.html) |
| `clang/docs/analyzer/developer-docs/InitializerLists.md` | [before](https://clang.llvm.org/docs/analyzer/developer-docs/InitializerLists.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/analyzer/developer-docs/InitializerLists.html) |
| `clang/docs/analyzer/developer-docs/PerformanceInvestigation.md` | [before](https://clang.llvm.org/docs/analyzer/developer-docs/PerformanceInvestigation.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/analyzer/developer-docs/PerformanceInvestigation.html) |
| `clang/docs/analyzer/developer-docs/RegionStore.md` | [before](https://clang.llvm.org/docs/analyzer/developer-docs/RegionStore.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/analyzer/developer-docs/RegionStore.html) |
| `clang/docs/analyzer/developer-docs/Statistics.md` | [before](https://clang.llvm.org/docs/analyzer/developer-docs/Statistics.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/analyzer/developer-docs/Statistics.html) |
| `clang/docs/analyzer/developer-docs/nullability.md` | [before](https://clang.llvm.org/docs/analyzer/developer-docs/nullability.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/analyzer/developer-docs/nullability.html) |
| `clang/docs/analyzer/developer-docs.md` | [before](https://clang.llvm.org/docs/analyzer/developer-docs.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/analyzer/developer-docs.html) |
| `clang/docs/analyzer/user-docs/Annotations.md` | [before](https://clang.llvm.org/docs/analyzer/user-docs/Annotations.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/analyzer/user-docs/Annotations.html) |
| `clang/docs/analyzer/user-docs/CommandLineUsage.md` | [before](https://clang.llvm.org/docs/analyzer/user-docs/CommandLineUsage.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/analyzer/user-docs/CommandLineUsage.html) |
| `clang/docs/analyzer/user-docs/CrossTranslationUnit.md` | [before](https://clang.llvm.org/docs/analyzer/user-docs/CrossTranslationUnit.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/analyzer/user-docs/CrossTranslationUnit.html) |
| `clang/docs/analyzer/user-docs/FAQ.md` | [before](https://clang.llvm.org/docs/analyzer/user-docs/FAQ.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/analyzer/user-docs/FAQ.html) |
| `clang/docs/analyzer/user-docs/FilingBugs.md` | [before](https://clang.llvm.org/docs/analyzer/user-docs/FilingBugs.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/analyzer/user-docs/FilingBugs.html) |
| `clang/docs/analyzer/user-docs/Installation.md` | [before](https://clang.llvm.org/docs/analyzer/user-docs/Installation.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/analyzer/user-docs/Installation.html) |
| `clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.md` | [before](https://clang.llvm.org/docs/analyzer/user-docs/TaintAnalysisConfiguration.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.html) |
| `clang/docs/analyzer/user-docs/UsingWithXCode.md` | [before](https://clang.llvm.org/docs/analyzer/user-docs/UsingWithXCode.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/analyzer/user-docs/UsingWithXCode.html) |
| `clang/docs/analyzer/user-docs.md` | [before](https://clang.llvm.org/docs/analyzer/user-docs.html) | [after](https://llvmdocs.staging.reidkleckner.dev/clang/docs/analyzer/user-docs.html) |
>From 3fb732863ec02d755521567698215e32af81a717 Mon Sep 17 00:00:00 2001
From: Reid Kleckner <rkleckner at nvidia.com>
Date: Thu, 13 Aug 2026 22:44:54 +0000
Subject: [PATCH 1/2] [docs] Convert selected rst docs with rst2myst
---
.../developer-docs/ForceLinkerHeaders.md | 180 +-
.../developer-docs/HowToExtend.md | 270 +-
.../SummaryExtractionInternals.md | 36 +-
.../developer-docs/index.md | 16 +-
.../user-docs/SourceEditGeneration.md | 51 +-
.../user-docs/SummaryExtraction.md | 47 +-
clang/docs/analyzer/checkers.md | 5377 ++++++++---------
clang/docs/analyzer/developer-docs.md | 23 +-
.../analyzer/developer-docs/DebugChecks.md | 300 +-
clang/docs/analyzer/developer-docs/IPA.md | 226 +-
.../developer-docs/InitializerLists.md | 165 +-
.../PerformanceInvestigation.md | 137 +-
.../analyzer/developer-docs/RegionStore.md | 130 +-
.../analyzer/developer-docs/Statistics.md | 36 +-
.../analyzer/developer-docs/nullability.md | 124 +-
clang/docs/analyzer/user-docs.md | 25 +-
clang/docs/analyzer/user-docs/Annotations.md | 765 ++-
.../analyzer/user-docs/CommandLineUsage.md | 286 +-
.../user-docs/CrossTranslationUnit.md | 493 +-
clang/docs/analyzer/user-docs/FAQ.md | 231 +-
clang/docs/analyzer/user-docs/FilingBugs.md | 10 +-
clang/docs/analyzer/user-docs/Installation.md | 10 +-
.../user-docs/TaintAnalysisConfiguration.md | 261 +-
.../docs/analyzer/user-docs/UsingWithXCode.md | 102 +-
24 files changed, 4573 insertions(+), 4728 deletions(-)
diff --git a/clang/docs/ScalableStaticAnalysis/developer-docs/ForceLinkerHeaders.md b/clang/docs/ScalableStaticAnalysis/developer-docs/ForceLinkerHeaders.md
index d75855a8b8af3..daf57291477f7 100644
--- a/clang/docs/ScalableStaticAnalysis/developer-docs/ForceLinkerHeaders.md
+++ b/clang/docs/ScalableStaticAnalysis/developer-docs/ForceLinkerHeaders.md
@@ -1,130 +1,124 @@
-====================
-Force-Linker Headers
-====================
+# Force-Linker Headers
-.. WARNING:: The framework is rapidly evolving.
- The documentation might be out-of-sync with the implementation.
- The purpose of this documentation is to give context for upcoming reviews.
+:::{WARNING}
+The framework is rapidly evolving.
+The documentation might be out-of-sync with the implementation.
+The purpose of this documentation is to give context for upcoming reviews.
+:::
-The problem
-***********
+## The problem
-SSAF uses `llvm::Registry\<\> <https://llvm.org/doxygen/classllvm_1_1Registry.html>`_
+SSAF uses [llvm::Registry\<>](https://llvm.org/doxygen/classllvm_1_1Registry.html)
for decentralized registration of summary extractors and serialization formats.
Each registration is a file-scope static object whose constructor adds an entry
to the global registry:
-.. code-block:: c++
-
- // In MyExtractor.cpp
- static TUSummaryExtractorRegistry::Add<MyExtractor>
- RegisterExtractor("MyExtractor", "My summary extractor");
+```c++
+// In MyExtractor.cpp
+static TUSummaryExtractorRegistry::Add<MyExtractor>
+ RegisterExtractor("MyExtractor", "My summary extractor");
+```
When the translation unit containing this static object is compiled into a
-**static library** (``.a`` / ``.lib``), the static linker will only pull in
+**static library** (`.a` / `.lib`), the static linker will only pull in
object files that resolve an undefined symbol in the consuming binary.
-Because no code ever calls anything in ``MyExtractor.o`` directly, the linker
+Because no code ever calls anything in `MyExtractor.o` directly, the linker
discards the object file — and the registration never runs.
-This is not a problem for **shared libraries** (``.so`` / ``.dylib``), because
+This is not a problem for **shared libraries** (`.so` / `.dylib`), because
the dynamic linker loads the entire shared object and runs all global
constructors unconditionally.
-The solution: anchor symbols
-****************************
-
-Each registration translation unit defines a ``volatile int`` **anchor symbol**:
-
-.. code-block:: c++
+## The solution: anchor symbols
- // In MyExtractor.cpp - next to the registry Add<> object in the ``clang::ssaf`` namespace
- // NOLINTNEXTLINE(misc-use-internal-linkage)
- volatile int MyExtractorAnchorSource = 0;
+Each registration translation unit defines a `volatile int` **anchor symbol**:
-For **in-tree** anchors, add a single ``ANCHOR(...)`` entry to
-``BuiltinAnchorSources.def`` (in alphabetical order):
+```c++
+// In MyExtractor.cpp - next to the registry Add<> object in the ``clang::ssaf`` namespace
+// NOLINTNEXTLINE(misc-use-internal-linkage)
+volatile int MyExtractorAnchorSource = 0;
+```
-.. code-block:: c++
+For **in-tree** anchors, add a single `ANCHOR(...)` entry to
+`BuiltinAnchorSources.def` (in alphabetical order):
- // In clang/include/clang/ScalableStaticAnalysis/BuiltinAnchorSources.def
- ANCHOR(JSONFormatAnchorSource)
- ANCHOR(MyExtractorAnchorSource) // <-- Add here, in alphabetical order
+```c++
+// In clang/include/clang/ScalableStaticAnalysis/BuiltinAnchorSources.def
+ANCHOR(JSONFormatAnchorSource)
+ANCHOR(MyExtractorAnchorSource) // <-- Add here, in alphabetical order
+```
-``SSAFBuiltinForceLinker.h`` includes this ``.def`` file automatically to
-generate the ``extern`` declarations and the ``AnchorSources`` array — there is
+`SSAFBuiltinForceLinker.h` includes this `.def` file automatically to
+generate the `extern` declarations and the `AnchorSources` array — there is
no need to edit that header directly.
-Any translation unit that ``#include``\s this header now has a reference to
-``MyExtractorAnchorSource``, which forces the linker to pull in
-``MyExtractor.o`` — and with it, the static ``Add<>`` registration object.
+Any translation unit that `#include`s this header now has a reference to
+`MyExtractorAnchorSource`, which forces the linker to pull in
+`MyExtractor.o` — and with it, the static `Add<>` registration object.
-The ``volatile`` qualifier is essential: without it the compiler could
-constant-fold the ``0`` and eliminate the reference entirely.
+The `volatile` qualifier is essential: without it the compiler could
+constant-fold the `0` and eliminate the reference entirely.
-These anchor symbols must be mutable (not ``const``), because otherwise on MSVC
-``const volatile`` variables would still have **internal linkage** — despite
+These anchor symbols must be mutable (not `const`), because otherwise on MSVC
+`const volatile` variables would still have **internal linkage** — despite
that the standard specifies that these should have **external linkage**.
-Header hierarchy
-================
+### Header hierarchy
-.. code-block:: text
+```text
+SSAFForceLinker.h (umbrella — include this in binaries)
+└── SSAFBuiltinForceLinker.h (upstream built-in anchors only)
+```
- SSAFForceLinker.h (umbrella — include this in binaries)
- └── SSAFBuiltinForceLinker.h (upstream built-in anchors only)
-
-- ``clang/include/clang/ScalableStaticAnalysis/SSAFBuiltinForceLinker.h`` — anchors for
- upstream-provided (built-in) extractors and formats (e.g. ``JSONFormat``).
-- ``clang/include/clang/ScalableStaticAnalysis/SSAFForceLinker.h`` — umbrella header
- that includes ``SSAFBuiltinForceLinker.h``. This is the header that
+- `clang/include/clang/ScalableStaticAnalysis/SSAFBuiltinForceLinker.h` — anchors for
+ upstream-provided (built-in) extractors and formats (e.g. `JSONFormat`).
+- `clang/include/clang/ScalableStaticAnalysis/SSAFForceLinker.h` — umbrella header
+ that includes `SSAFBuiltinForceLinker.h`. This is the header that
downstream projects should modify to add their own force-linker includes
- (see :doc:`HowToExtend`).
+ (see {doc}`HowToExtend`).
-Include the umbrella header with ``// IWYU pragma: keep`` in any translation
+Include the umbrella header with `// IWYU pragma: keep` in any translation
unit that must guarantee all registrations are active — typically the entry
-point of a binary that uses ``clangScalableStaticAnalysisCore``:
-
-.. code-block:: c++
+point of a binary that uses `clangScalableStaticAnalysisCore`:
- // In ExecuteCompilerInvocation.cpp
- #include "clang/ScalableStaticAnalysis/SSAFForceLinker.h" // IWYU pragma: keep
+```c++
+// In ExecuteCompilerInvocation.cpp
+#include "clang/ScalableStaticAnalysis/SSAFForceLinker.h" // IWYU pragma: keep
+```
-Naming convention
-=================
+### Naming convention
-Anchor symbols follow the pattern ``<Component>AnchorSource`` in the ``clang::ssaf`` namespace.
+Anchor symbols follow the pattern `<Component>AnchorSource` in the `clang::ssaf` namespace.
For example:
-- ``JSONFormatAnchorSource``
-- ``MyExtractorAnchorSource``
+- `JSONFormatAnchorSource`
+- `MyExtractorAnchorSource`
-All anchor sources are aggregated into a single ``BuiltinAnchorDestination``
-lambda in the force-linker header (see ``SSAFBuiltinForceLinker.h``).
+All anchor sources are aggregated into a single `BuiltinAnchorDestination`
+lambda in the force-linker header (see `SSAFBuiltinForceLinker.h`).
-Considered alternatives
-***********************
+## Considered alternatives
-``--whole-archive`` / ``-force_load``
-=====================================
+### `--whole-archive` / `-force_load`
The linker can be instructed to include *every* object file from a static
library, regardless of whether any symbols are referenced:
-.. code-block:: bash
+```bash
+# GNU ld / lld (Linux, BSD)
+-Wl,--whole-archive -lclangScalableStaticAnalysisCore -Wl,--no-whole-archive
- # GNU ld / lld (Linux, BSD)
- -Wl,--whole-archive -lclangScalableStaticAnalysisCore -Wl,--no-whole-archive
+# Apple ld
+-Wl,-force_load,libclangScalableStaticAnalysisCore.a
+```
- # Apple ld
- -Wl,-force_load,libclangScalableStaticAnalysisCore.a
-
-Since CMake 3.24, the ``$<LINK_LIBRARY:WHOLE_ARCHIVE,...>`` generator expression
+Since CMake 3.24, the `$<LINK_LIBRARY:WHOLE_ARCHIVE,...>` generator expression
provides a portable way to do the same:
-.. code-block:: cmake
-
- target_link_libraries(clang PRIVATE
- "$<LINK_LIBRARY:WHOLE_ARCHIVE,clangScalableStaticAnalysisCore>")
+```cmake
+target_link_libraries(clang PRIVATE
+ "$<LINK_LIBRARY:WHOLE_ARCHIVE,clangScalableStaticAnalysisCore>")
+```
**Why we did not choose this approach**:
@@ -132,27 +126,27 @@ provides a portable way to do the same:
increasing binary size.
- The anchor approach only targets specific object files: only registrations
whose anchors are referenced in a force-linker header are pulled in.
-- ``--whole-archive`` semantics vary across platforms and toolchains, requiring
- platform-specific CMake logic or the relatively new ``WHOLE_ARCHIVE``
+- `--whole-archive` semantics vary across platforms and toolchains, requiring
+ platform-specific CMake logic or the relatively new `WHOLE_ARCHIVE`
generator expression.
-Explicit initialization functions
-=================================
+### Explicit initialization functions
-An alternative is a central ``initializeSSAFRegistrations()`` function that
+An alternative is a central `initializeSSAFRegistrations()` function that
explicitly calls into each registration module:
-.. code-block:: c++
-
- void initializeSSAFRegistrations() {
- initializeJSONFormat();
- initializeMyExtractor();
- // ... one entry per registration
- }
+```c++
+void initializeSSAFRegistrations() {
+ initializeJSONFormat();
+ initializeMyExtractor();
+ // ... one entry per registration
+}
+```
**Why we did not choose this approach**:
- It reintroduces a centralized list that must be maintained manually, defeating
- the decoupled-registration benefit of ``llvm::Registry``.
+ the decoupled-registration benefit of `llvm::Registry`.
- Adding a new extractor or format requires modifying a central file, which
increases merge-conflict risk for downstream users.
+
diff --git a/clang/docs/ScalableStaticAnalysis/developer-docs/HowToExtend.md b/clang/docs/ScalableStaticAnalysis/developer-docs/HowToExtend.md
index de6800bd13e0a..8bd88bd8c796e 100644
--- a/clang/docs/ScalableStaticAnalysis/developer-docs/HowToExtend.md
+++ b/clang/docs/ScalableStaticAnalysis/developer-docs/HowToExtend.md
@@ -1,222 +1,208 @@
-===========================
-How to Extend the Framework
-===========================
+# How to Extend the Framework
-.. WARNING:: The framework is rapidly evolving.
- The documentation might be out-of-sync with the implementation.
- The purpose of this documentation is to give context for upcoming reviews.
+:::{WARNING}
+The framework is rapidly evolving.
+The documentation might be out-of-sync with the implementation.
+The purpose of this documentation is to give context for upcoming reviews.
+:::
SSAF is designed to be extensible with new **summary extractors** and **serialization formats**.
Extensions can be added in three ways:
-#. **Statically, in-tree** — built as part of the upstream LLVM/Clang tree.
-#. **Statically, out-of-tree (downstream)** — built in a downstream fork or project that links ``clangScalableStaticAnalysisCore`` as a static library.
-#. **Dynamically, via plugins** — loaded at runtime as shared objects.
+1. **Statically, in-tree** — built as part of the upstream LLVM/Clang tree.
+2. **Statically, out-of-tree (downstream)** — built in a downstream fork or project that links `clangScalableStaticAnalysisCore` as a static library.
+3. **Dynamically, via plugins** — loaded at runtime as shared objects.
-All three approaches use the same ``llvm::Registry``-based registration mechanism.
+All three approaches use the same `llvm::Registry`-based registration mechanism.
The key difference is how the linker sees the registration:
-static libraries need :doc:`force-linker anchors <ForceLinkerHeaders>` to prevent dead-stripping, while shared libraries do not.
+static libraries need {doc}`force-linker anchors <ForceLinkerHeaders>` to prevent dead-stripping, while shared libraries do not.
-Adding a summary extractor
-**************************
+## Adding a summary extractor
-A summary extractor is an ``ASTConsumer`` that inspects the AST and populates a ``TUSummary`` via the ``TUSummaryBuilder`` interface.
+A summary extractor is an `ASTConsumer` that inspects the AST and populates a `TUSummary` via the `TUSummaryBuilder` interface.
-Step 1: Implement the extractor
-===============================
+### Step 1: Implement the extractor
-.. code-block:: c++
+```c++
+//--- MyExtractor.h
+#include "clang/ScalableStaticAnalysis/Core/TUSummary/TUSummaryExtractor.h"
- //--- MyExtractor.h
- #include "clang/ScalableStaticAnalysis/Core/TUSummary/TUSummaryExtractor.h"
+namespace clang::ssaf {
- namespace clang::ssaf {
+class MyExtractor : public TUSummaryExtractor {
+public:
+ using TUSummaryExtractor::TUSummaryExtractor;
- class MyExtractor : public TUSummaryExtractor {
- public:
- using TUSummaryExtractor::TUSummaryExtractor;
+ // Override HandleTranslationUnit or any other virtual functions of an ASTConsumer...
+ // Use the SummaryBuilder to populate the summary while walking the AST.
+};
- // Override HandleTranslationUnit or any other virtual functions of an ASTConsumer...
- // Use the SummaryBuilder to populate the summary while walking the AST.
- };
+} // namespace clang::ssaf
+```
- } // namespace clang::ssaf
+### Step 2: Register the extractor
-Step 2: Register the extractor
-==============================
+```c++
+//--- MyExtractor.cpp
+#include "MyExtractor.h"
+#include "clang/ScalableStaticAnalysis/Core/TUSummary/ExtractorRegistry.h"
-.. code-block:: c++
+using namespace clang::ssaf;
- //--- MyExtractor.cpp
- #include "MyExtractor.h"
- #include "clang/ScalableStaticAnalysis/Core/TUSummary/ExtractorRegistry.h"
+namespace clang::ssaf {
+// NOLINTNEXTLINE(misc-use-internal-linkage)
+volatile int MyExtractorAnchorSource = 0;
+} // namespace clang::ssaf
- using namespace clang::ssaf;
+static TUSummaryExtractorRegistry::Add<MyExtractor>
+ RegisterExtractor("MyExtractor", "My awesome summary extractor");
+```
- namespace clang::ssaf {
- // NOLINTNEXTLINE(misc-use-internal-linkage)
- volatile int MyExtractorAnchorSource = 0;
- } // namespace clang::ssaf
+The `"MyExtractor"` string is the name users pass to `--ssaf-extract-summaries=MyExtractor`.
- static TUSummaryExtractorRegistry::Add<MyExtractor>
- RegisterExtractor("MyExtractor", "My awesome summary extractor");
+### Step 3: Add the force-linker anchor
-The ``"MyExtractor"`` string is the name users pass to ``--ssaf-extract-summaries=MyExtractor``.
-
-Step 3: Add the force-linker anchor
-===================================
-
-See :doc:`ForceLinkerHeaders` for a full explanation of why this is needed.
+See {doc}`ForceLinkerHeaders` for a full explanation of why this is needed.
For **in-tree** additions, add one line to
-``clang/include/clang/ScalableStaticAnalysis/BuiltinAnchorSources.def``
+`clang/include/clang/ScalableStaticAnalysis/BuiltinAnchorSources.def`
(in alphabetical order):
-.. code-block:: c++
-
- ANCHOR(MyExtractorAnchorSource)
+```c++
+ANCHOR(MyExtractorAnchorSource)
+```
-``SSAFBuiltinForceLinker.h`` includes this ``.def`` file automatically — no
+`SSAFBuiltinForceLinker.h` includes this `.def` file automatically — no
need to edit it directly.
-For **downstream** additions, see `Out-of-tree (downstream) extensions`_ below.
-
-
-Adding a serialization format
-*****************************
+For **downstream** additions, see [Out-of-tree (downstream) extensions] below.
-A serialization format controls how the ``TUSummary`` is written to (and read from) disk.
-This involves more boilerplate than an extractor because each format has a per-analysis ``FormatInfo`` sub-registry.
+## Adding a serialization format
-Step 1: Define the format class
-===============================
+A serialization format controls how the `TUSummary` is written to (and read from) disk.
+This involves more boilerplate than an extractor because each format has a per-analysis `FormatInfo` sub-registry.
-Your format class must inherit from ``SerializationFormat`` and define a ``FormatInfo`` type alias:
+### Step 1: Define the format class
-.. code-block:: c++
+Your format class must inherit from `SerializationFormat` and define a `FormatInfo` type alias:
- //--- MyFormat.h
- #include "clang/ScalableStaticAnalysis/Core/Serialization/SerializationFormat.h"
- #include "clang/Support/Compiler.h"
- #include "llvm/Support/Registry.h"
+```c++
+//--- MyFormat.h
+#include "clang/ScalableStaticAnalysis/Core/Serialization/SerializationFormat.h"
+#include "clang/Support/Compiler.h"
+#include "llvm/Support/Registry.h"
- namespace clang::ssaf {
+namespace clang::ssaf {
- class MyFormat : public SerializationFormat {
- public:
- // Define the type aliases: SerializerFn, DeserializerFn
- using FormatInfo = FormatInfoEntry<SerializerFn, DeserializerFn>;
+class MyFormat : public SerializationFormat {
+public:
+ // Define the type aliases: SerializerFn, DeserializerFn
+ using FormatInfo = FormatInfoEntry<SerializerFn, DeserializerFn>;
- // Override readTUSummaryEncoding, writeTUSummary, etc.
- };
+ // Override readTUSummaryEncoding, writeTUSummary, etc.
+};
- } // namespace clang::ssaf
+} // namespace clang::ssaf
- LLVM_DECLARE_REGISTRY(llvm::Registry<MyFormat::FormatInfo>)
+LLVM_DECLARE_REGISTRY(llvm::Registry<MyFormat::FormatInfo>)
+```
-Step 2: Register the format
-===========================
+### Step 2: Register the format
-.. code-block:: c++
+```c++
+//--- MyFormat.cpp
+#include "MyFormat.h"
+#include "clang/ScalableStaticAnalysis/Core/Serialization/SerializationFormatRegistry.h"
- //--- MyFormat.cpp
- #include "MyFormat.h"
- #include "clang/ScalableStaticAnalysis/Core/Serialization/SerializationFormatRegistry.h"
+using namespace clang::ssaf;
- using namespace clang::ssaf;
+namespace clang::ssaf {
+// NOLINTNEXTLINE(misc-use-internal-linkage)
+volatile int MyFormatAnchorSource = 0;
+} // namespace clang::ssaf
- namespace clang::ssaf {
- // NOLINTNEXTLINE(misc-use-internal-linkage)
- volatile int MyFormatAnchorSource = 0;
- } // namespace clang::ssaf
+static SerializationFormatRegistry::Add<MyFormat>
+ RegisterFormat("myformat", "My awesome serialization format");
- static SerializationFormatRegistry::Add<MyFormat>
- RegisterFormat("myformat", "My awesome serialization format");
+LLVM_DEFINE_REGISTRY(llvm::Registry<MyFormat::FormatInfo>)
+```
- LLVM_DEFINE_REGISTRY(llvm::Registry<MyFormat::FormatInfo>)
+The format name (`"myformat"`) is matched against the file extension in `--ssaf-tu-summary-file=output.myformat`.
-The format name (``"myformat"``) is matched against the file extension in ``--ssaf-tu-summary-file=output.myformat``.
+### Step 3: Register per-analysis FormatInfo entries
-Step 3: Register per-analysis FormatInfo entries
-================================================
+For each analysis that should be serializable in your format, register a `FormatInfo` entry.
+`FormatInfo` must be implemented for any of the summaries that wants to support `myformat`:
-For each analysis that should be serializable in your format, register a ``FormatInfo`` entry.
-``FormatInfo`` must be implemented for any of the summaries that wants to support ``myformat``:
+```c++
+namespace {
+using FormatInfo = MyFormat::FormatInfo;
+struct MyAnalysisFormatInfo final : FormatInfo {
+ MyAnalysisFormatInfo() : FormatInfo{
+ SummaryName("MyAnalysis"),
+ serializeMyAnalysis,
+ deserializeMyAnalysis,
+ } {}
+};
+} // namespace
-.. code-block:: c++
+static llvm::Registry<FormatInfo>::Add<MyAnalysisFormatInfo>
+ RegisterFormatInfo("MyAnalysisFormatInfo",
+ "MyFormat format info for MyAnalysis");
+```
- namespace {
- using FormatInfo = MyFormat::FormatInfo;
- struct MyAnalysisFormatInfo final : FormatInfo {
- MyAnalysisFormatInfo() : FormatInfo{
- SummaryName("MyAnalysis"),
- serializeMyAnalysis,
- deserializeMyAnalysis,
- } {}
- };
- } // namespace
+### Step 4: Add the force-linker anchor
- static llvm::Registry<FormatInfo>::Add<MyAnalysisFormatInfo>
- RegisterFormatInfo("MyAnalysisFormatInfo",
- "MyFormat format info for MyAnalysis");
+Same pattern as for extractors — add the anchor to `BuiltinAnchorSources.def`
+(in alphabetical order). See [Adding a summary extractor] Step 3,
+and {doc}`ForceLinkerHeaders`.
-Step 4: Add the force-linker anchor
-===================================
+## Static extensibility
-Same pattern as for extractors — add the anchor to ``BuiltinAnchorSources.def``
-(in alphabetical order). See `Adding a summary extractor`_ Step 3,
-and :doc:`ForceLinkerHeaders`.
-
-
-Static extensibility
-********************
-
-In-tree extensions
-==================
+### In-tree extensions
For extensions that are part of the upstream LLVM/Clang tree:
-#. Add the anchor to ``clang/include/clang/ScalableStaticAnalysis/BuiltinAnchorSources.def`` (in alphabetical order).
-#. Add the source files to the ``clangScalableStaticAnalysisCore`` CMake library target.
-#. That's it — the ``SSAFForceLinker.h`` umbrella includes ``SSAFBuiltinForceLinker.h``
+1. Add the anchor to `clang/include/clang/ScalableStaticAnalysis/BuiltinAnchorSources.def` (in alphabetical order).
+2. Add the source files to the `clangScalableStaticAnalysisCore` CMake library target.
+3. That's it — the `SSAFForceLinker.h` umbrella includes `SSAFBuiltinForceLinker.h`
transitively, so any binary that includes the umbrella will pull in the registration.
-Out-of-tree (downstream) extensions
-===================================
+### Out-of-tree (downstream) extensions
Downstream projects that maintain a fork can add their own extensions without
modifying upstream files — reducing the risk of merge-conflicts:
-#. Create a downstream force-linker header, e.g. ``SSAFDownstreamForceLinker.h``,
+1. Create a downstream force-linker header, e.g. `SSAFDownstreamForceLinker.h`,
containing the anchor references for downstream-only extractors and formats.
-#. Include it from ``SSAFForceLinker.h`` (the umbrella):
- .. code-block:: c++
+2. Include it from `SSAFForceLinker.h` (the umbrella):
- // In SSAFForceLinker.h
- #include "SSAFBuiltinForceLinker.h" // IWYU pragma: keep
- #include "SSAFDownstreamForceLinker.h" // IWYU pragma: keep
+ ```c++
+ // In SSAFForceLinker.h
+ #include "SSAFBuiltinForceLinker.h" // IWYU pragma: keep
+ #include "SSAFDownstreamForceLinker.h" // IWYU pragma: keep
+ ```
This is a single-line addition per downstream project, minimizing conflicts with upstream changes.
Upstream will try to avoid modifying this umbrella header, making it a stable static extension point.
-#. Add the downstream source files to the build system as usual.
+3. Add the downstream source files to the build system as usual.
+## Dynamic extensibility (plugins)
-Dynamic extensibility (plugins)
-*******************************
-
-Shared libraries loaded at runtime — via ``dlopen`` / ``LoadLibrary`` or the
+Shared libraries loaded at runtime — via `dlopen` / `LoadLibrary` or the
Clang plugin mechanism — do **not** need force-linker anchors, but having them also does not hurt.
-When a shared object (``.so`` / ``.dylib``) is loaded, the dynamic linker runs all global constructors in that library unconditionally.
-This means the ``llvm::Registry::Add<>`` objects execute their constructors and register themselves automatically.
+When a shared object (`.so` / `.dylib`) is loaded, the dynamic linker runs all global constructors in that library unconditionally.
+This means the `llvm::Registry::Add<>` objects execute their constructors and register themselves automatically.
To use a plugin:
-#. Build your extractor or format as a shared library.
-#. Load it with the Clang plugin mechanism (``-fplugin=`` or ``-load``).
-#. Pass the extractor name to ``--ssaf-extract-summaries=`` as usual.
+1. Build your extractor or format as a shared library.
+2. Load it with the Clang plugin mechanism (`-fplugin=` or `-load`).
+3. Pass the extractor name to `--ssaf-extract-summaries=` as usual.
No changes to any force-linker header are required.
-The ``llvm::Registry`` infrastructure handles everything once the shared object is loaded.
+The `llvm::Registry` infrastructure handles everything once the shared object is loaded.
+
diff --git a/clang/docs/ScalableStaticAnalysis/developer-docs/SummaryExtractionInternals.md b/clang/docs/ScalableStaticAnalysis/developer-docs/SummaryExtractionInternals.md
index 8190f2c8c7fae..8df055ad0ce69 100644
--- a/clang/docs/ScalableStaticAnalysis/developer-docs/SummaryExtractionInternals.md
+++ b/clang/docs/ScalableStaticAnalysis/developer-docs/SummaryExtractionInternals.md
@@ -1,31 +1,29 @@
-============================
-Summary Extraction Internals
-============================
+# Summary Extraction Internals
-.. WARNING:: The framework is rapidly evolving.
- The documentation might be out-of-sync with the implementation.
- The purpose of this documentation is to give context for upcoming reviews.
+:::{WARNING}
+The framework is rapidly evolving.
+The documentation might be out-of-sync with the implementation.
+The purpose of this documentation is to give context for upcoming reviews.
+:::
-When ``--ssaf-tu-summary-file=`` is non-empty, ``CreateFrontendAction()`` (in ``ExecuteCompilerInvocation.cpp``)
-wraps the original ``FrontendAction`` inside a ``TUSummaryExtractorFrontendAction``.
-This ensures that the summary extraction transparently happens after the original frontend action, which is usually either compilation (``-c``) or just ``-fsyntax-only`` in tests.
+When `--ssaf-tu-summary-file=` is non-empty, `CreateFrontendAction()` (in `ExecuteCompilerInvocation.cpp`)
+wraps the original `FrontendAction` inside a `TUSummaryExtractorFrontendAction`.
+This ensures that the summary extraction transparently happens after the original frontend action, which is usually either compilation (`-c`) or just `-fsyntax-only` in tests.
-Lifetime of a summary extraction
-********************************
+## Lifetime of a summary extraction
-The ``TUSummaryExtractorFrontendAction`` will try to construct a ``TUSummaryRunner`` ASTConsumer and report an error on failure.
+The `TUSummaryExtractorFrontendAction` will try to construct a `TUSummaryRunner` ASTConsumer and report an error on failure.
When it succeeds, it will multiplex the handlers of the ASTConsumer to every summary extractor and in the end, serialize and write the results to the desired file.
-Implementation details
-**********************
+## Implementation details
-Global Registries
-=================
+### Global Registries
-The framework uses `llvm::Registry\<\> <https://llvm.org/doxygen/classllvm_1_1Registry.html>`_
+The framework uses [llvm::Registry\<>](https://llvm.org/doxygen/classllvm_1_1Registry.html)
as an extension point for adding new summary analyses or serialization formats.
Each entry in the *registry* holds a name, a description and a pointer to a constructor.
Because static linking can discard unreferenced registration objects, the framework
-uses :doc:`ForceLinkerHeaders` to ensure they are retained.
+uses {doc}`ForceLinkerHeaders` to ensure they are retained.
+
+For details on how to add new extractors and formats, see {doc}`HowToExtend`.
-For details on how to add new extractors and formats, see :doc:`HowToExtend`.
diff --git a/clang/docs/ScalableStaticAnalysis/developer-docs/index.md b/clang/docs/ScalableStaticAnalysis/developer-docs/index.md
index 139cb281a2ab4..685f8e88d2d90 100644
--- a/clang/docs/ScalableStaticAnalysis/developer-docs/index.md
+++ b/clang/docs/ScalableStaticAnalysis/developer-docs/index.md
@@ -1,10 +1,10 @@
-=======================
-Developer Documentation
-=======================
+# Developer Documentation
-.. toctree::
- :numbered:
- :maxdepth: 2
- :glob:
+```{toctree}
+:glob: true
+:maxdepth: 2
+:numbered: true
+
+*
+```
- *
diff --git a/clang/docs/ScalableStaticAnalysis/user-docs/SourceEditGeneration.md b/clang/docs/ScalableStaticAnalysis/user-docs/SourceEditGeneration.md
index 3e6cb569ebc1a..ad7d93d02fcf9 100644
--- a/clang/docs/ScalableStaticAnalysis/user-docs/SourceEditGeneration.md
+++ b/clang/docs/ScalableStaticAnalysis/user-docs/SourceEditGeneration.md
@@ -1,26 +1,24 @@
-==============================
-Source Edit Generation
-==============================
+# Source Edit Generation
-Source edit generation relies on a ``WPASuite`` result produced by an
+Source edit generation relies on a `WPASuite` result produced by an
earlier whole-program analysis. It runs alongside the normal compile
and emits two per-translation-unit artifacts:
-- a *source-edit file* (``--ssaf-src-edit-file=``) containing
- ``clang::tooling::Replacement`` records ready for
- ``clang-apply-replacements``,
-- a *transformation-report file* (``--ssaf-transformation-report-file=``)
+- a *source-edit file* (`--ssaf-src-edit-file=`) containing
+ `clang::tooling::Replacement` records ready for
+ `clang-apply-replacements`,
+- a *transformation-report file* (`--ssaf-transformation-report-file=`)
containing diagnostic-style findings.
-Driver options
-================
+## Driver options
-Four options control the pipeline; they are all both ``--ssaf-…`` driver
-options and ``cc1`` options. The compilation-unit identifier is shared
+Four options control the pipeline; they are all both `--ssaf-…` driver
+options and `cc1` options. The compilation-unit identifier is shared
with the summary extraction step. A given compilation unit needs to
receive the same identifier for both summary extraction and source
edit generation.
+```{eval-rst}
.. list-table::
:header-rows: 1
@@ -40,24 +38,25 @@ edit generation.
* - ``--ssaf-compilation-unit-id=<id>``
- Stable identifier for this translation unit (also required by
the summary extraction).
+```
-When ``--ssaf-source-transformation=`` is non-empty the framework wraps
-the active ``FrontendAction`` in a ``SourceTransformationFrontendAction``;
+When `--ssaf-source-transformation=` is non-empty the framework wraps
+the active `FrontendAction` in a `SourceTransformationFrontendAction`;
otherwise the compile is byte-for-byte unchanged.
-Examples
-========
+## Examples
-Apply the source edits with ``clang-apply-replacements``:
+Apply the source edits with `clang-apply-replacements`:
-.. code-block:: console
-
- $ clang -c foo.cpp \
- --ssaf-source-transformation=my-transformation \
- --ssaf-global-scope-analysis-result=wpa.json \
- --ssaf-src-edit-file=foo.yaml \
- --ssaf-transformation-report-file=foo.sarif \
- --ssaf-compilation-unit-id=cu-foo
- $ clang-apply-replacements --remove-change-desc-files <dir-with-yaml>
+```console
+$ clang -c foo.cpp \
+ --ssaf-source-transformation=my-transformation \
+ --ssaf-global-scope-analysis-result=wpa.json \
+ --ssaf-src-edit-file=foo.yaml \
+ --ssaf-transformation-report-file=foo.sarif \
+ --ssaf-compilation-unit-id=cu-foo
+$ clang-apply-replacements --remove-change-desc-files <dir-with-yaml>
+```
The transformation report can be consumed by any SARIF viewer.
+
diff --git a/clang/docs/ScalableStaticAnalysis/user-docs/SummaryExtraction.md b/clang/docs/ScalableStaticAnalysis/user-docs/SummaryExtraction.md
index 96892cfa5fdea..50d5ccf510822 100644
--- a/clang/docs/ScalableStaticAnalysis/user-docs/SummaryExtraction.md
+++ b/clang/docs/ScalableStaticAnalysis/user-docs/SummaryExtraction.md
@@ -1,37 +1,36 @@
-==================
-Summary Extraction
-==================
+# Summary Extraction
-.. WARNING:: The framework is rapidly evolving.
- The documentation might be out-of-sync with the implementation.
- The purpose of this documentation is to give context for upcoming reviews.
+:::{WARNING}
+The framework is rapidly evolving.
+The documentation might be out-of-sync with the implementation.
+The purpose of this documentation is to give context for upcoming reviews.
+:::
-Command-line interface
-**********************
+## Command-line interface
Two flags control summary extraction:
-- ``--ssaf-extract-summaries=<name1>,<name2>,...``: Comma-separated list of summary extractor names to enable.
-- ``--ssaf-tu-summary-file=<path>.<format>``: Output file for the extracted summaries. The file extension selects the serialization format (e.g. ``.json``).
-- ``--ssaf-list-extractors``: List the available summary extractors.
-- ``--ssaf-list-formats``: List the available serialization formats.
+- `--ssaf-extract-summaries=<name1>,<name2>,...`: Comma-separated list of summary extractor names to enable.
+- `--ssaf-tu-summary-file=<path>.<format>`: Output file for the extracted summaries. The file extension selects the serialization format (e.g. `.json`).
+- `--ssaf-list-extractors`: List the available summary extractors.
+- `--ssaf-list-formats`: List the available serialization formats.
Example invocation:
-.. code-block:: bash
+```bash
+clang --ssaf-extract-summaries=MyAwesomeAnalysis \
+ --ssaf-tu-summary-file=my-tu-summary.json \
+ -c input.cpp -o input.o
- clang --ssaf-extract-summaries=MyAwesomeAnalysis \
- --ssaf-tu-summary-file=my-tu-summary.json \
- -c input.cpp -o input.o
+clang --ssaf-list-extractors --ssaf-list-formats
+```
- clang --ssaf-list-extractors --ssaf-list-formats
+## Diagnostics
-Diagnostics
-***********
+In case the `--ssaf-*` flags are used incorrectly, or some extractor fails to implement the desired serialization format
+or just happens to have an error, then the error is forwarded as a `scalable-static-analysis-framework` error.
+These errors can be downgraded into warnings using `-Wno-error=scalable-static-analysis-framework`.
+These errors can be completely suppressed using `-Wno-scalable-static-analysis-framework`.
-In case the ``--ssaf-*`` flags are used incorrectly, or some extractor fails to implement the desired serialization format
-or just happens to have an error, then the error is forwarded as a ``scalable-static-analysis-framework`` error.
-These errors can be downgraded into warnings using ``-Wno-error=scalable-static-analysis-framework``.
-These errors can be completely suppressed using ``-Wno-scalable-static-analysis-framework``.
+See the [diagnostic flags](https://clang.llvm.org/docs/DiagnosticsReference.html#wscalable-static-analysis-framework) for the full list of diagnostics controlled by `-Wscalable-static-analysis-framework`.
-See the `diagnostic flags <https://clang.llvm.org/docs/DiagnosticsReference.html#wscalable-static-analysis-framework>`_ for the full list of diagnostics controlled by ``-Wscalable-static-analysis-framework``.
diff --git a/clang/docs/analyzer/checkers.md b/clang/docs/analyzer/checkers.md
index 1f6b974d5ca7a..93a494c5a3fd5 100644
--- a/clang/docs/analyzer/checkers.md
+++ b/clang/docs/analyzer/checkers.md
@@ -1,38 +1,34 @@
-==================
-Available Checkers
-==================
+# Available Checkers
The analyzer performs checks that are categorized into families or "checkers".
The default set of checkers covers a variety of checks targeted at finding security and API usage bugs,
-dead code, and other logic errors. See the :ref:`default-checkers` checkers list below.
+dead code, and other logic errors. See the {ref}`default-checkers` checkers list below.
-In addition to these, the analyzer contains a number of :ref:`alpha-checkers` (aka *alpha* checkers).
+In addition to these, the analyzer contains a number of {ref}`alpha-checkers` (aka *alpha* checkers).
These checkers are under development and are switched off by default. They may crash or emit a higher number of false positives.
-The :ref:`debug-checkers` package contains checkers for analyzer developers for debugging purposes.
+The {ref}`debug-checkers` package contains checkers for analyzer developers for debugging purposes.
-.. contents:: Table of Contents
- :depth: 4
+```{contents} Table of Contents
+:depth: 4
+```
+(default-checkers)=
-.. _default-checkers:
+## Default Checkers
-Default Checkers
-----------------
+(core-checkers)=
-.. _core-checkers:
+### core
-core
-^^^^
Models core language features and contains general-purpose checkers such as division by zero,
null pointer dereference, usage of uninitialized values, etc.
*These checkers must be always switched on as other checker rely on them.*
-.. _core-BitwiseShift:
+(core-bitwiseshift)=
-core.BitwiseShift (C, C++)
-""""""""""""""""""""""""""
+#### core.BitwiseShift (C, C++)
Finds undefined behavior caused by the bitwise left- and right-shift operator
operating on integer types.
@@ -42,8 +38,8 @@ either negative or larger than the bit width of the type of the left operand;
these are logically unsound.
Moreover, if the pedantic mode is activated by
-``-analyzer-config core.BitwiseShift:Pedantic=true``, then this checker also
-reports situations where the _left_ operand of a shift operator is negative or
+`-analyzer-config core.BitwiseShift:Pedantic=true`, then this checker also
+reports situations where the \_left\_ operand of a shift operator is negative or
overflow occurs during the right shift of a signed value. (Most compilers
handle these predictably, but the C standard and the C++ standards before C++20
say that they're undefined behavior. In the C++20 standard these constructs are
@@ -51,430 +47,423 @@ well-defined, so activating pedantic mode in C++20 has no effect.)
**Examples**
-.. code-block:: cpp
+```cpp
+static_assert(sizeof(int) == 4, "assuming 32-bit int")
- static_assert(sizeof(int) == 4, "assuming 32-bit int")
-
- void basic_examples(int a, int b) {
- if (b < 0) {
- b = a << b; // warn: right operand is negative in left shift
- } else if (b >= 32) {
- b = a >> b; // warn: right shift overflows the capacity of 'int'
- }
- }
+void basic_examples(int a, int b) {
+ if (b < 0) {
+ b = a << b; // warn: right operand is negative in left shift
+ } else if (b >= 32) {
+ b = a >> b; // warn: right shift overflows the capacity of 'int'
+ }
+}
- int pedantic_examples(int a, int b) {
- if (a < 0) {
- return a >> b; // warn: left operand is negative in right shift
- }
- a = 1000u << 31; // OK, overflow of unsigned value is well-defined, a == 0
- if (b > 10) {
- a = b << 31; // this is undefined before C++20, but the checker doesn't
- // warn because it doesn't know the exact value of b
- }
- return 1000 << 31; // warn: this overflows the capacity of 'int'
- }
+int pedantic_examples(int a, int b) {
+ if (a < 0) {
+ return a >> b; // warn: left operand is negative in right shift
+ }
+ a = 1000u << 31; // OK, overflow of unsigned value is well-defined, a == 0
+ if (b > 10) {
+ a = b << 31; // this is undefined before C++20, but the checker doesn't
+ // warn because it doesn't know the exact value of b
+ }
+ return 1000 << 31; // warn: this overflows the capacity of 'int'
+}
+```
**Solution**
Ensure the shift operands are in proper range before shifting.
-.. _core-CallAndMessage:
+(core-callandmessage)=
+
+#### core.CallAndMessage (C, C++, ObjC)
-core.CallAndMessage (C, C++, ObjC)
-""""""""""""""""""""""""""""""""""
Check for logical errors for function calls and Objective-C message expressions
(e.g., uninitialized arguments, null function pointers).
This checker is a collection of related checks that are controlled by checker
options. The following checks are all enabled by default, but can be turned off
-by setting their option to ``false``:
+by setting their option to `false`:
-* **FunctionPointer** Check for null or undefined function pointer at function
+- **FunctionPointer** Check for null or undefined function pointer at function
call.
-* **CXXThisMethodCall** Check for null or undefined ``this`` pointer at method
+- **CXXThisMethodCall** Check for null or undefined `this` pointer at method
call.
-* **CXXDeallocationArg** Check for null or undefined argument of
- ``operator delete``.
-* **ArgInitializedness** Check for undefined pass-by-value function arguments.
-* **ParameterCount** Check for correct number of passed arguments to functions
+- **CXXDeallocationArg** Check for null or undefined argument of
+ `operator delete`.
+- **ArgInitializedness** Check for undefined pass-by-value function arguments.
+- **ParameterCount** Check for correct number of passed arguments to functions
or ObjC blocks. This will warn if the actual argument count is less (but not
if more) than the required count (by the declaration).
-* **NilReceiver** Check whether the receiver in a message expression is
- ``nil``.
-* **UndefReceiver** Check whether the receiver in a message expression is
+- **NilReceiver** Check whether the receiver in a message expression is
+ `nil`.
+- **UndefReceiver** Check whether the receiver in a message expression is
undefined.
The following check is disabled by default (because it is more likely to
-produce false positives), this can be turned on by set the option to ``true``:
+produce false positives), this can be turned on by set the option to `true`:
-* **ArgPointeeInitializedness** Check for undefined pass-by-reference (pointer
+- **ArgPointeeInitializedness** Check for undefined pass-by-reference (pointer
to constant value or constant reference) function arguments. In special cases
non-constant arguments are checked. This happens for C library functions
where it is required to initialize (at least partially) a passed structure
which is used for both input and output (for example last argument of
- ``mktime`` or ``mbrlen``).
+ `mktime` or `mbrlen`).
**Additional options**
-* **ArgPointeeInitializednessComplete** Controls when to emit the warning at
- the **ArgPointeeInitializedness** check. If this option is ``false`` (the
- default), a ``struct`` is considered to be "initialized" when at least one
- member is initialized. When this option is set to ``true``, structures are
+- **ArgPointeeInitializednessComplete** Controls when to emit the warning at
+ the **ArgPointeeInitializedness** check. If this option is `false` (the
+ default), a `struct` is considered to be "initialized" when at least one
+ member is initialized. When this option is set to `true`, structures are
only accepted as initialized when all members are initialized. (Arguments of
C library functions which require initialization are always checked as if the
- option would be ``false``.)
+ option would be `false`.)
**Some examples**
-.. literalinclude:: checkers/callandmessage_example.c
- :language: objc
+```{literalinclude} checkers/callandmessage_example.c
+:language: objc
+```
+
+(core-dividezero)=
-.. _core-DivideZero:
+#### core.DivideZero (C, C++, ObjC)
-core.DivideZero (C, C++, ObjC)
-""""""""""""""""""""""""""""""
- Check for division by zero.
+> Check for division by zero.
-.. literalinclude:: checkers/dividezero_example.c
- :language: c
+```{literalinclude} checkers/dividezero_example.c
+:language: c
+```
-.. _core-NonNullParamChecker:
+(core-nonnullparamchecker)=
+
+#### core.NonNullParamChecker (C, C++, ObjC)
-core.NonNullParamChecker (C, C++, ObjC)
-"""""""""""""""""""""""""""""""""""""""
Check for null pointers passed as arguments to a function whose arguments are references or marked with the 'nonnull' attribute.
-.. code-block:: cpp
+```cpp
+int f(int *p) __attribute__((nonnull));
- int f(int *p) __attribute__((nonnull));
+void test(int *p) {
+ if (!p)
+ f(p); // warn
+}
+```
- void test(int *p) {
- if (!p)
- f(p); // warn
- }
+(core-nulldereference)=
-.. _core-NullDereference:
+#### core.NullDereference (C, C++, ObjC)
-core.NullDereference (C, C++, ObjC)
-"""""""""""""""""""""""""""""""""""
Check for dereferences of null pointers.
-.. code-block:: objc
-
- // C
- void test(int *p) {
- if (p)
- return;
+```objc
+// C
+void test(int *p) {
+ if (p)
+ return;
- int x = p[0]; // warn
- }
+ int x = p[0]; // warn
+}
- // C
- void test(int *p) {
- if (!p)
- *p = 0; // warn
- }
+// C
+void test(int *p) {
+ if (!p)
+ *p = 0; // warn
+}
- // C++
- class C {
- public:
- int x;
- };
+// C++
+class C {
+public:
+ int x;
+};
- void test() {
- C *pc = 0;
- int k = pc->x; // warn
- }
+void test() {
+ C *pc = 0;
+ int k = pc->x; // warn
+}
- // Objective-C
- @interface MyClass {
- @public
- int x;
- }
- @end
+// Objective-C
+ at interface MyClass {
+ at public
+ int x;
+}
+ at end
- void test() {
- MyClass *obj = 0;
- obj->x = 1; // warn
- }
+void test() {
+ MyClass *obj = 0;
+ obj->x = 1; // warn
+}
+```
Null pointer dereferences of pointers with address spaces are not always defined
as error. Specifically on x86/x86-64 target if the pointer address space is
256 (x86 GS Segment), 257 (x86 FS Segment), or 258 (x86 SS Segment), a null
-dereference is not defined as error. See `X86/X86-64 Language Extensions
-<https://clang.llvm.org/docs/LanguageExtensions.html#memory-references-to-specified-segments>`__
+dereference is not defined as error. See [X86/X86-64 Language Extensions](https://clang.llvm.org/docs/LanguageExtensions.html#memory-references-to-specified-segments)
for reference.
-If the analyzer option ``suppress-dereferences-from-any-address-space`` is set
+If the analyzer option `suppress-dereferences-from-any-address-space` is set
to true (the default value), then this checker never reports dereference of
pointers with a specified address space. If the option is set to false, then
reports from the specific x86 address spaces 256, 257 and 258 are still
suppressed, but null dereferences from other address spaces are reported.
-.. _core-NullPointerArithm:
+(core-nullpointerarithm)=
+
+#### core.NullPointerArithm (C, C++)
-core.NullPointerArithm (C, C++)
-"""""""""""""""""""""""""""""""
Check for undefined arithmetic operations with null pointers.
The checker can detect the following cases:
- - ``p + x`` and ``x + p`` where ``p`` is a null pointer and ``x`` is a nonzero
- integer value.
- - ``p - x`` where ``p`` is a null pointer and ``x`` is a nonzero integer
- value.
- - ``p1 - p2`` where one of ``p1`` and ``p2`` is null and the other a
- non-null pointer.
+> - `p + x` and `x + p` where `p` is a null pointer and `x` is a nonzero
+> integer value.
+> - `p - x` where `p` is a null pointer and `x` is a nonzero integer
+> value.
+> - `p1 - p2` where one of `p1` and `p2` is null and the other a
+> non-null pointer.
Result of these operations is undefined according to the standard.
In the above listed cases, the checker will warn even if the expression
described to be "nonzero" or "non-null" has unknown value, because it is likely
that it can have non-zero value during the program execution.
-.. code-block:: c
+```c
+void test1(int *p, int offset) {
+ if (p)
+ return;
- void test1(int *p, int offset) {
- if (p)
- return;
+ int *p1 = p + offset; // warn: 'p' is null, 'offset' is unknown but likely non-zero
+}
- int *p1 = p + offset; // warn: 'p' is null, 'offset' is unknown but likely non-zero
- }
+void test2(int *p, int offset) {
+ if (p) { } // this indicates that it is possible for 'p' to be null
+ if (offset == 0)
+ return;
- void test2(int *p, int offset) {
- if (p) { } // this indicates that it is possible for 'p' to be null
- if (offset == 0)
- return;
+ int *p1 = p - offset; // warn: 'p' is null, 'offset' is known to be non-zero
+}
- int *p1 = p - offset; // warn: 'p' is null, 'offset' is known to be non-zero
- }
+void test3(char *p1, char *p2) {
+ if (p1)
+ return;
- void test3(char *p1, char *p2) {
- if (p1)
- return;
+ int a = p1 - p2; // warn: 'p1' is null, 'p2' can be likely non-null
+}
+```
- int a = p1 - p2; // warn: 'p1' is null, 'p2' can be likely non-null
- }
+(core-stackaddressescape)=
-.. _core-StackAddressEscape:
+#### core.StackAddressEscape (C)
-core.StackAddressEscape (C)
-"""""""""""""""""""""""""""
Check that addresses to stack memory do not escape the function.
-.. code-block:: c
-
- char const *p;
+```c
+char const *p;
- void test() {
- char const str[] = "string";
- p = str; // warn
- }
+void test() {
+ char const str[] = "string";
+ p = str; // warn
+}
- void* test() {
- return __builtin_alloca(12); // warn
- }
+void* test() {
+ return __builtin_alloca(12); // warn
+}
- void test() {
- static int *x;
- int y;
- x = &y; // warn
- }
+void test() {
+ static int *x;
+ int y;
+ x = &y; // warn
+}
+```
+(core-undefinedbinaryoperatorresult)=
-.. _core-UndefinedBinaryOperatorResult:
+#### core.UndefinedBinaryOperatorResult (C)
-core.UndefinedBinaryOperatorResult (C)
-""""""""""""""""""""""""""""""""""""""
Check for undefined results of binary operators.
-.. code-block:: c
+```c
+void test() {
+ int x;
+ int y = x + 1; // warn: left operand is garbage
+}
+```
- void test() {
- int x;
- int y = x + 1; // warn: left operand is garbage
- }
+(core-vlasize)=
-.. _core-VLASize:
+#### core.VLASize (C)
-core.VLASize (C)
-""""""""""""""""
Check for declarations of Variable Length Arrays (VLA) of undefined, zero or negative
size.
-.. code-block:: c
-
- void test() {
- int x;
- int vla1[x]; // warn: garbage as size
- }
-
- void test() {
- int x = 0;
- int vla2[x]; // warn: zero size
- }
+```c
+void test() {
+ int x;
+ int vla1[x]; // warn: garbage as size
+}
+void test() {
+ int x = 0;
+ int vla2[x]; // warn: zero size
+}
+```
The checker also gives warning if the `TaintPropagation` checker is switched on
and an unbound, attacker controlled (tainted) value is used to define
the size of the VLA.
-.. code-block:: c
-
- void taintedVLA(void) {
- int x;
- scanf("%d", &x);
- int vla[x]; // Declared variable-length array (VLA) has tainted (attacker controlled) size, that can be 0 or negative
- }
+```c
+void taintedVLA(void) {
+ int x;
+ scanf("%d", &x);
+ int vla[x]; // Declared variable-length array (VLA) has tainted (attacker controlled) size, that can be 0 or negative
+}
- void taintedVerfieidVLA(void) {
- int x;
- scanf("%d", &x);
- if (x<1)
- return;
- int vla[x]; // no-warning. The analyzer can prove that x must be positive.
- }
+void taintedVerfieidVLA(void) {
+ int x;
+ scanf("%d", &x);
+ if (x<1)
+ return;
+ int vla[x]; // no-warning. The analyzer can prove that x must be positive.
+}
+```
+(core-uninitialized-arraysubscript)=
-.. _core-uninitialized-ArraySubscript:
+#### core.uninitialized.ArraySubscript (C)
-core.uninitialized.ArraySubscript (C)
-"""""""""""""""""""""""""""""""""""""
Check for uninitialized values used as array subscripts.
-.. code-block:: c
+```c
+void test() {
+ int i, a[10];
+ int x = a[i]; // warn: array subscript is undefined
+}
+```
- void test() {
- int i, a[10];
- int x = a[i]; // warn: array subscript is undefined
- }
+(core-uninitialized-assign)=
-.. _core-uninitialized-Assign:
+#### core.uninitialized.Assign (C)
-core.uninitialized.Assign (C)
-"""""""""""""""""""""""""""""
Check for assigning uninitialized values.
-.. code-block:: c
+```c
+void test() {
+ int x;
+ x |= 1; // warn: left expression is uninitialized
+}
+```
- void test() {
- int x;
- x |= 1; // warn: left expression is uninitialized
- }
+(core-uninitialized-branch)=
-.. _core-uninitialized-Branch:
+#### core.uninitialized.Branch (C)
-core.uninitialized.Branch (C)
-"""""""""""""""""""""""""""""
Check for uninitialized values used as branch conditions.
-.. code-block:: c
+```c
+void test() {
+ int x;
+ if (x) // warn
+ return;
+}
+```
- void test() {
- int x;
- if (x) // warn
- return;
- }
+(core-uninitialized-capturedblockvariable)=
-.. _core-uninitialized-CapturedBlockVariable:
+#### core.uninitialized.CapturedBlockVariable (C)
-core.uninitialized.CapturedBlockVariable (C)
-""""""""""""""""""""""""""""""""""""""""""""
Check for blocks that capture uninitialized values.
-.. code-block:: c
+```c
+void test() {
+ int x;
+ ^{ int y = x; }(); // warn
+}
+```
- void test() {
- int x;
- ^{ int y = x; }(); // warn
- }
+(core-uninitialized-undefreturn)=
-.. _core-uninitialized-UndefReturn:
+#### core.uninitialized.UndefReturn (C)
-core.uninitialized.UndefReturn (C)
-""""""""""""""""""""""""""""""""""
Check for uninitialized values being returned to the caller.
-.. code-block:: c
-
- int test() {
- int x;
- return x; // warn
- }
+```c
+int test() {
+ int x;
+ return x; // warn
+}
+```
-.. _core-uninitialized-NewArraySize:
+(core-uninitialized-newarraysize)=
-core.uninitialized.NewArraySize (C++)
-"""""""""""""""""""""""""""""""""""""
+#### core.uninitialized.NewArraySize (C++)
Check if the element count in new[] is garbage or undefined.
-.. code-block:: cpp
-
- void test() {
- int n;
- int *arr = new int[n]; // warn: Element count in new[] is a garbage value
- delete[] arr;
- }
-
-
-.. _cplusplus-checkers:
+```cpp
+void test() {
+ int n;
+ int *arr = new int[n]; // warn: Element count in new[] is a garbage value
+ delete[] arr;
+}
+```
+(cplusplus-checkers)=
-cplusplus
-^^^^^^^^^
+### cplusplus
C++ Checkers.
-.. _cplusplus-ArrayDelete:
+(cplusplus-arraydelete)=
-cplusplus.ArrayDelete (C++)
-"""""""""""""""""""""""""""
+#### cplusplus.ArrayDelete (C++)
Reports destructions of arrays of polymorphic objects that are destructed as
their base class. If the dynamic type of the array is different from its static
type, calling `delete[]` is undefined.
-This checker corresponds to the SEI CERT rule `EXP51-CPP: Do not delete an array through a pointer of the incorrect type <https://wiki.sei.cmu.edu/confluence/display/cplusplus/EXP51-CPP.+Do+not+delete+an+array+through+a+pointer+of+the+incorrect+type>`_.
-
-.. code-block:: cpp
+This checker corresponds to the SEI CERT rule [EXP51-CPP: Do not delete an array through a pointer of the incorrect type](https://wiki.sei.cmu.edu/confluence/display/cplusplus/EXP51-CPP.+Do+not+delete+an+array+through+a+pointer+of+the+incorrect+type).
- class Base {
- public:
- virtual ~Base() {}
- };
- class Derived : public Base {};
+```cpp
+class Base {
+public:
+ virtual ~Base() {}
+};
+class Derived : public Base {};
- Base *create() {
- Base *x = new Derived[10]; // note: Casting from 'Derived' to 'Base' here
- return x;
- }
+Base *create() {
+ Base *x = new Derived[10]; // note: Casting from 'Derived' to 'Base' here
+ return x;
+}
- void foo() {
- Base *x = create();
- delete[] x; // warn: Deleting an array of 'Derived' objects as their base class 'Base' is undefined
- }
+void foo() {
+ Base *x = create();
+ delete[] x; // warn: Deleting an array of 'Derived' objects as their base class 'Base' is undefined
+}
+```
**Limitations**
The checker does not emit note tags when casting to and from reference types,
even though the pointer values are tracked across references.
-.. code-block:: cpp
+```cpp
+void foo() {
+ Derived *d = new Derived[10];
+ Derived &dref = *d;
- void foo() {
- Derived *d = new Derived[10];
- Derived &dref = *d;
+ Base &bref = static_cast<Base&>(dref); // no note
+ Base *b = &bref;
+ delete[] b; // warn: Deleting an array of 'Derived' objects as their base class 'Base' is undefined
+}
+```
- Base &bref = static_cast<Base&>(dref); // no note
- Base *b = &bref;
- delete[] b; // warn: Deleting an array of 'Derived' objects as their base class 'Base' is undefined
- }
+(cplusplus-innerpointer)=
-.. _cplusplus-InnerPointer:
+#### cplusplus.InnerPointer (C++)
-cplusplus.InnerPointer (C++)
-""""""""""""""""""""""""""""
Check for inner pointers of C++ containers used after re/deallocation.
Many container methods in the C++ standard library are known to invalidate
@@ -483,326 +472,321 @@ elements of the container. Using such references after they are invalidated
causes undefined behavior, which is a common source of memory errors in C++ that
this checker is capable of finding.
-The checker is currently limited to ``std::string`` objects and doesn't
+The checker is currently limited to `std::string` objects and doesn't
recognize some of the more sophisticated approaches to passing unowned pointers
-around, such as ``std::string_view``.
-
-.. code-block:: cpp
+around, such as `std::string_view`.
+
+```cpp
+void deref_after_assignment() {
+ std::string s = "llvm";
+ const char *c = s.data(); // note: pointer to inner buffer of 'std::string' obtained here
+ s = "clang"; // note: inner buffer of 'std::string' reallocated by call to 'operator='
+ consume(c); // warn: inner pointer of container used after re/deallocation
+}
- void deref_after_assignment() {
- std::string s = "llvm";
- const char *c = s.data(); // note: pointer to inner buffer of 'std::string' obtained here
- s = "clang"; // note: inner buffer of 'std::string' reallocated by call to 'operator='
- consume(c); // warn: inner pointer of container used after re/deallocation
- }
+const char *return_temp(int x) {
+ return std::to_string(x).c_str(); // warn: inner pointer of container used after re/deallocation
+ // note: pointer to inner buffer of 'std::string' obtained here
+ // note: inner buffer of 'std::string' deallocated by call to destructor
+}
+```
- const char *return_temp(int x) {
- return std::to_string(x).c_str(); // warn: inner pointer of container used after re/deallocation
- // note: pointer to inner buffer of 'std::string' obtained here
- // note: inner buffer of 'std::string' deallocated by call to destructor
- }
+(cplusplus-move)=
-.. _cplusplus-Move:
+#### cplusplus.Move (C++)
-cplusplus.Move (C++)
-""""""""""""""""""""
Find use-after-move bugs in C++. This includes method calls on moved-from
objects, assignment of a moved-from object, and repeated move of a moved-from
object.
-.. code-block:: cpp
-
- struct A {
- void foo() {}
- };
+```cpp
+struct A {
+ void foo() {}
+};
- void f1() {
- A a;
- A b = std::move(a); // note: 'a' became 'moved-from' here
- a.foo(); // warn: method call on a 'moved-from' object 'a'
- }
+void f1() {
+ A a;
+ A b = std::move(a); // note: 'a' became 'moved-from' here
+ a.foo(); // warn: method call on a 'moved-from' object 'a'
+}
- void f2() {
- A a;
- A b = std::move(a);
- A c(std::move(a)); // warn: move of an already moved-from object
- }
+void f2() {
+ A a;
+ A b = std::move(a);
+ A c(std::move(a)); // warn: move of an already moved-from object
+}
- void f3() {
- A a;
- A b = std::move(a);
- b = a; // warn: copy of moved-from object
- }
+void f3() {
+ A a;
+ A b = std::move(a);
+ b = a; // warn: copy of moved-from object
+}
+```
-The checker option ``WarnOn`` controls on what objects the use-after-move is
+The checker option `WarnOn` controls on what objects the use-after-move is
checked:
-* The most strict value is ``KnownsOnly``, in this mode only objects are
+- The most strict value is `KnownsOnly`, in this mode only objects are
checked whose type is known to be move-unsafe. These include most STL objects
(but excluding move-safe ones) and smart pointers.
-* With option value ``KnownsAndLocals`` local variables (of any type) are
+- With option value `KnownsAndLocals` local variables (of any type) are
additionally checked. The idea behind this is that local variables are
usually not tempting to be re-used so an use after move is more likely a bug
than with member variables.
-* With option value ``All`` any use-after move condition is checked on all
+- With option value `All` any use-after move condition is checked on all
kinds of variables, excluding global variables and known move-safe cases.
-Default value is ``KnownsAndLocals``.
+Default value is `KnownsAndLocals`.
-Calls of methods named ``empty()`` or ``isEmpty()`` are allowed on moved-from
+Calls of methods named `empty()` or `isEmpty()` are allowed on moved-from
objects because these methods are considered as move-safe. Functions called
-``reset()``, ``destroy()``, ``clear()``, ``assign``, ``resize``, ``shrink`` are
+`reset()`, `destroy()`, `clear()`, `assign`, `resize`, `shrink` are
treated as state-reset functions and are allowed on moved-from objects, these
make the object valid again. This applies to any type of object (not only STL
ones).
-.. _cplusplus-NewDelete:
+(cplusplus-newdelete)=
+
+#### cplusplus.NewDelete (C++)
-cplusplus.NewDelete (C++)
-"""""""""""""""""""""""""
Check for double-free and use-after-free problems. Traces memory managed by new/delete.
Custom allocation/deallocation functions can be defined using
-:ref:`ownership attributes<analyzer-ownership-attrs>`.
+{ref}`ownership attributes<analyzer-ownership-attrs>`.
+
+```{literalinclude} checkers/newdelete_example.cpp
+:language: cpp
+```
-.. literalinclude:: checkers/newdelete_example.cpp
- :language: cpp
+(cplusplus-newdeleteleaks)=
-.. _cplusplus-NewDeleteLeaks:
+#### cplusplus.NewDeleteLeaks (C++)
-cplusplus.NewDeleteLeaks (C++)
-""""""""""""""""""""""""""""""
Check for memory leaks. Traces memory managed by new/delete.
Custom allocation/deallocation functions can be defined using
-:ref:`ownership attributes<analyzer-ownership-attrs>`.
+{ref}`ownership attributes<analyzer-ownership-attrs>`.
-.. code-block:: cpp
+```cpp
+void test() {
+ int *p = new int;
+} // warn
+```
- void test() {
- int *p = new int;
- } // warn
+(cplusplus-placementnew)=
-.. _cplusplus-PlacementNew:
+#### cplusplus.PlacementNew (C++)
-cplusplus.PlacementNew (C++)
-""""""""""""""""""""""""""""
Check if default placement new is provided with pointers to sufficient storage capacity.
-.. code-block:: cpp
+```cpp
+#include <new>
- #include <new>
+void f() {
+ short s;
+ long *lp = ::new (&s) long; // warn
+}
+```
- void f() {
- short s;
- long *lp = ::new (&s) long; // warn
- }
+(cplusplus-selfassignment)=
-.. _cplusplus-SelfAssignment:
+#### cplusplus.SelfAssignment (C++)
-cplusplus.SelfAssignment (C++)
-""""""""""""""""""""""""""""""
Checks C++ copy and move assignment operators for self assignment.
-.. _cplusplus-StringChecker:
+(cplusplus-stringchecker)=
+
+#### cplusplus.StringChecker (C++)
-cplusplus.StringChecker (C++)
-"""""""""""""""""""""""""""""
Checks std::string operations.
-Checks if the cstring pointer from which the ``std::string`` object is
-constructed is ``NULL`` or not.
+Checks if the cstring pointer from which the `std::string` object is
+constructed is `NULL` or not.
If the checker cannot reason about the nullness of the pointer it will assume
that it was non-null to satisfy the precondition of the constructor.
-This checker is capable of checking the `SEI CERT C++ coding rule STR51-CPP.
-Do not attempt to create a std::string from a null pointer
-<https://wiki.sei.cmu.edu/confluence/x/E3s-BQ>`__.
-
-.. code-block:: cpp
+This checker is capable of checking the [SEI CERT C++ coding rule STR51-CPP.
+Do not attempt to create a std::string from a null pointer](https://wiki.sei.cmu.edu/confluence/x/E3s-BQ).
- #include <string>
+```cpp
+#include <string>
- void f(const char *p) {
- if (!p) {
- std::string msg(p); // warn: The parameter must not be null
- }
- }
+void f(const char *p) {
+ if (!p) {
+ std::string msg(p); // warn: The parameter must not be null
+ }
+}
+```
-.. _cplusplus-PureVirtualCall:
+(cplusplus-purevirtualcall)=
-cplusplus.PureVirtualCall (C++)
-"""""""""""""""""""""""""""""""
+#### cplusplus.PureVirtualCall (C++)
-When `virtual methods are called during construction and destruction
-<https://en.cppreference.com/w/cpp/language/virtual#During_construction_and_destruction>`__
+When [virtual methods are called during construction and destruction](https://en.cppreference.com/w/cpp/language/virtual#During_construction_and_destruction)
the polymorphism is restricted to the class that's being constructed or
destructed because the more derived contexts are either not yet initialized or
already destructed.
This checker reports situations where this restricted polymorphism causes a
call to a pure virtual method, which is undefined behavior. (See also the
-related checker :ref:`optin-cplusplus-VirtualCall` which reports situations
+related checker {ref}`optin-cplusplus-VirtualCall` which reports situations
where the restricted polymorphism affects a call and the called method is not
pure virtual – but may be still surprising for the programmer.)
-.. code-block:: cpp
-
- struct A {
- virtual int getKind() = 0;
+```cpp
+struct A {
+ virtual int getKind() = 0;
- A() {
- // warn: This calls the pure virtual method A::getKind().
- log << "Constructing " << getKind();
- }
- virtual ~A() {
- releaseResources();
- }
- void releaseResources() {
- // warn: This can call the pure virtual method A::getKind() when this is
- // called from the destructor.
- callSomeFunction(getKind());
- }
- };
+ A() {
+ // warn: This calls the pure virtual method A::getKind().
+ log << "Constructing " << getKind();
+ }
+ virtual ~A() {
+ releaseResources();
+ }
+ void releaseResources() {
+ // warn: This can call the pure virtual method A::getKind() when this is
+ // called from the destructor.
+ callSomeFunction(getKind());
+ }
+};
+```
-.. _deadcode-checkers:
+(deadcode-checkers)=
-deadcode
-^^^^^^^^
+### deadcode
Dead Code Checkers.
-.. _deadcode-DeadStores:
+(deadcode-deadstores)=
-deadcode.DeadStores (C)
-"""""""""""""""""""""""
-Check for values stored to variables that are never read afterwards.
+#### deadcode.DeadStores (C)
-.. code-block:: c
+Check for values stored to variables that are never read afterwards.
- void test() {
- int x;
- x = 1; // warn
- }
+```c
+void test() {
+ int x;
+ x = 1; // warn
+}
+```
-The ``WarnForDeadNestedAssignments`` option enables the checker to emit
+The `WarnForDeadNestedAssignments` option enables the checker to emit
warnings for nested dead assignments. You can disable with the
-``-analyzer-config deadcode.DeadStores:WarnForDeadNestedAssignments=false``.
+`-analyzer-config deadcode.DeadStores:WarnForDeadNestedAssignments=false`.
*Defaults to true*.
Would warn for this e.g.:
if ((y = make_int())) {
}
-.. _nullability-checkers:
+(nullability-checkers)=
-nullability
-^^^^^^^^^^^
+### nullability
Checkers (mostly Objective C) that warn for null pointer passing and dereferencing errors.
-.. _nullability-NullPassedToNonnull:
+(nullability-nullpassedtononnull)=
-nullability.NullPassedToNonnull (ObjC)
-""""""""""""""""""""""""""""""""""""""
-Warns when a null pointer is passed to a pointer which has a _Nonnull type.
+#### nullability.NullPassedToNonnull (ObjC)
-.. code-block:: objc
+Warns when a null pointer is passed to a pointer which has a \_Nonnull type.
- if (name != nil)
- return;
- // Warning: nil passed to a callee that requires a non-null 1st parameter
- NSString *greeting = [@"Hello " stringByAppendingString:name];
+```objc
+if (name != nil)
+ return;
+// Warning: nil passed to a callee that requires a non-null 1st parameter
+NSString *greeting = [@"Hello " stringByAppendingString:name];
+```
-.. _nullability-NullReturnedFromNonnull:
+(nullability-nullreturnedfromnonnull)=
-nullability.NullReturnedFromNonnull (C, C++, ObjC)
-""""""""""""""""""""""""""""""""""""""""""""""""""
-Warns when a null pointer is returned from a function that has _Nonnull return type.
+#### nullability.NullReturnedFromNonnull (C, C++, ObjC)
-.. code-block:: objc
+Warns when a null pointer is returned from a function that has \_Nonnull return type.
- - (nonnull id)firstChild {
- id result = nil;
- if ([_children count] > 0)
- result = _children[0];
+```objc
+- (nonnull id)firstChild {
+ id result = nil;
+ if ([_children count] > 0)
+ result = _children[0];
- // Warning: nil returned from a method that is expected
- // to return a non-null value
- return result;
- }
+ // Warning: nil returned from a method that is expected
+ // to return a non-null value
+ return result;
+}
+```
-Warns when a null pointer is returned from a function annotated with ``__attribute__((returns_nonnull))``
+Warns when a null pointer is returned from a function annotated with `__attribute__((returns_nonnull))`
-.. code-block:: cpp
+```cpp
+int global;
+__attribute__((returns_nonnull)) void* getPtr(void* p);
- int global;
- __attribute__((returns_nonnull)) void* getPtr(void* p);
+void* getPtr(void* p) {
+ if (p) { // forgot to negate the condition
+ return &global;
+ }
+ // Warning: nullptr returned from a function that is expected
+ // to return a non-null value
+ return p;
+}
+```
- void* getPtr(void* p) {
- if (p) { // forgot to negate the condition
- return &global;
- }
- // Warning: nullptr returned from a function that is expected
- // to return a non-null value
- return p;
- }
+(nullability-nullabledereferenced)=
-.. _nullability-NullableDereferenced:
+#### nullability.NullableDereferenced (ObjC)
-nullability.NullableDereferenced (ObjC)
-"""""""""""""""""""""""""""""""""""""""
Warns when a nullable pointer is dereferenced.
-.. code-block:: objc
+```objc
+struct LinkedList {
+ int data;
+ struct LinkedList *next;
+};
- struct LinkedList {
- int data;
- struct LinkedList *next;
- };
+struct LinkedList * _Nullable getNext(struct LinkedList *l);
- struct LinkedList * _Nullable getNext(struct LinkedList *l);
+void updateNextData(struct LinkedList *list, int newData) {
+ struct LinkedList *next = getNext(list);
+ // Warning: Nullable pointer is dereferenced
+ next->data = 7;
+}
+```
- void updateNextData(struct LinkedList *list, int newData) {
- struct LinkedList *next = getNext(list);
- // Warning: Nullable pointer is dereferenced
- next->data = 7;
- }
+(nullability-nullablepassedtononnull)=
-.. _nullability-NullablePassedToNonnull:
+#### nullability.NullablePassedToNonnull (ObjC)
-nullability.NullablePassedToNonnull (ObjC)
-""""""""""""""""""""""""""""""""""""""""""
-Warns when a nullable pointer is passed to a pointer which has a _Nonnull type.
+Warns when a nullable pointer is passed to a pointer which has a \_Nonnull type.
-.. code-block:: objc
+```objc
+typedef struct Dummy { int val; } Dummy;
+Dummy *_Nullable returnsNullable();
+void takesNonnull(Dummy *_Nonnull);
- typedef struct Dummy { int val; } Dummy;
- Dummy *_Nullable returnsNullable();
- void takesNonnull(Dummy *_Nonnull);
+void test() {
+ Dummy *p = returnsNullable();
+ takesNonnull(p); // warn
+}
+```
- void test() {
- Dummy *p = returnsNullable();
- takesNonnull(p); // warn
- }
+(nullability-nullablereturnedfromnonnull)=
-.. _nullability-NullableReturnedFromNonnull:
+#### nullability.NullableReturnedFromNonnull (ObjC)
-nullability.NullableReturnedFromNonnull (ObjC)
-""""""""""""""""""""""""""""""""""""""""""""""
-Warns when a nullable pointer is returned from a function that has _Nonnull return type.
+Warns when a nullable pointer is returned from a function that has \_Nonnull return type.
-.. _optin-checkers:
+(optin-checkers)=
-optin
-^^^^^
+### optin
Checkers for portability, performance, optional security and coding style specific rules.
-.. _optin-core-EnumCastOutOfRange:
+(optin-core-enumcastoutofrange)=
+
+#### optin.core.EnumCastOutOfRange (C, C++)
-optin.core.EnumCastOutOfRange (C, C++)
-""""""""""""""""""""""""""""""""""""""
Check for integer to enumeration casts that would produce a value with no
corresponding enumerator. This is not necessarily undefined behavior, but can
lead to nasty surprises, so projects may decide to use a coding standard that
@@ -811,15 +795,15 @@ disallows these "unusual" conversions.
Note that no warnings are produced when the enum type (e.g. `std::byte`) has no
enumerators at all.
-.. code-block:: cpp
-
- enum WidgetKind { A=1, B, C, X=99 };
+```cpp
+enum WidgetKind { A=1, B, C, X=99 };
- void foo() {
- WidgetKind c = static_cast<WidgetKind>(3); // OK
- WidgetKind x = static_cast<WidgetKind>(99); // OK
- WidgetKind d = static_cast<WidgetKind>(4); // warn
- }
+void foo() {
+ WidgetKind c = static_cast<WidgetKind>(3); // OK
+ WidgetKind x = static_cast<WidgetKind>(99); // OK
+ WidgetKind d = static_cast<WidgetKind>(4); // warn
+}
+```
**Limitations**
@@ -827,87 +811,87 @@ This checker does not accept the coding pattern where an enum type is used to
store combinations of flag values.
Such enums should be annotated with the `__attribute__((flag_enum))` or by the
`[[clang::flag_enum]]` attribute to signal this intent. Refer to the
-`documentation <https://clang.llvm.org/docs/AttributeReference.html#flag-enum>`_
+[documentation](https://clang.llvm.org/docs/AttributeReference.html#flag-enum)
of this Clang attribute.
-.. code-block:: cpp
-
- enum AnimalFlags
- {
- HasClaws = 1,
- CanFly = 2,
- EatsFish = 4,
- Endangered = 8
- };
-
- AnimalFlags operator|(AnimalFlags a, AnimalFlags b)
- {
- return static_cast<AnimalFlags>(static_cast<int>(a) | static_cast<int>(b));
- }
+```cpp
+enum AnimalFlags
+{
+ HasClaws = 1,
+ CanFly = 2,
+ EatsFish = 4,
+ Endangered = 8
+};
+
+AnimalFlags operator|(AnimalFlags a, AnimalFlags b)
+{
+ return static_cast<AnimalFlags>(static_cast<int>(a) | static_cast<int>(b));
+}
- auto flags = HasClaws | CanFly;
+auto flags = HasClaws | CanFly;
+```
Projects that use this pattern should not enable this optin checker.
-.. _optin-core-FixedAddressDereference:
+(optin-core-fixedaddressdereference)=
+
+#### optin.core.FixedAddressDereference (C, C++, ObjC)
-optin.core.FixedAddressDereference (C, C++, ObjC)
-"""""""""""""""""""""""""""""""""""""""""""""""""
Check for dereferences of fixed addresses.
A pointer contains a fixed address if it was set to a hard-coded value or it
becomes otherwise obvious that at that point it can have only a single fixed
numerical value.
-.. code-block:: c
-
- void test1() {
- int *p = (int *)0x020;
- int x = p[0]; // warn
- }
+```c
+void test1() {
+ int *p = (int *)0x020;
+ int x = p[0]; // warn
+}
- void test2(int *p) {
- if (p == (int *)-1)
- *p = 0; // warn
- }
+void test2(int *p) {
+ if (p == (int *)-1)
+ *p = 0; // warn
+}
- void test3() {
- int (*p_function)(char, char);
- p_function = (int (*)(char, char))0x04080;
- int x = (*p_function)('x', 'y'); // NO warning yet at functon pointer calls
- }
+void test3() {
+ int (*p_function)(char, char);
+ p_function = (int (*)(char, char))0x04080;
+ int x = (*p_function)('x', 'y'); // NO warning yet at functon pointer calls
+}
+```
Access of fixed numerical addresses can be legitimate in low-level projects (e.g. firmware) and hardware interop.
-These values are often marked as ``volatile`` (to prevent unwanted compiler optimizations),
-so this checker doesn't report situations where the pointee of the fixed address is ``volatile``.
-If this suppression is not sufficient on a low-level project, then consider disabling this ``optin`` checker.
-Note that null pointers will still be reported by :ref:`core.NullDereference <core-NullDereference>`
-regardless if the pointee is ``volatile`` or not.
-
-.. code-block:: c
-
- void volatile_pointee() {
- *(volatile int *)0x404 = 1; // no warning: fixed non-null "volatile" pointee, you must know what you are doing
- }
+These values are often marked as `volatile` (to prevent unwanted compiler optimizations),
+so this checker doesn't report situations where the pointee of the fixed address is `volatile`.
+If this suppression is not sufficient on a low-level project, then consider disabling this `optin` checker.
+Note that null pointers will still be reported by {ref}`core.NullDereference <core-NullDereference>`
+regardless if the pointee is `volatile` or not.
+
+```c
+void volatile_pointee() {
+ *(volatile int *)0x404 = 1; // no warning: fixed non-null "volatile" pointee, you must know what you are doing
+}
- void deref_volatile_nullptr() {
- *(volatile int *)0 = 1; // core.NullDereference still warns about this
- }
+void deref_volatile_nullptr() {
+ *(volatile int *)0 = 1; // core.NullDereference still warns about this
+}
+```
-If the analyzer option ``suppress-dereferences-from-any-address-space`` is set
+If the analyzer option `suppress-dereferences-from-any-address-space` is set
to true (the default value), then this checker never reports dereference of
pointers with a specified address space. If the option is set to false, then
reports from the specific x86 address spaces 256, 257 and 258 are still
suppressed, but fixed address dereferences from other address spaces are
reported.
-Do not use the :ref:`address_space <langext-address_space_documentation>`
+Do not use the {ref}`address_space <langext-address_space_documentation>`
attribute to suppress the reports - it just happens so that the checker also doesn't raise issues if the attribute is present.
-.. _optin-core-UnconditionalVAArg:
+(optin-core-unconditionalvaarg)=
+
+#### optin.core.UnconditionalVAArg (C, C++)
-optin.core.UnconditionalVAArg (C, C++)
-""""""""""""""""""""""""""""""""""""""
-Check for variadic functions that unconditionally use ``va_arg()``. It is
+Check for variadic functions that unconditionally use `va_arg()`. It is
possible to use such functions safely (as long as they always receive at least
one variadic argument), but their careless use can lead to undefined behavior
(trying to access a variadic argument when there isn't any), so it is better to
@@ -917,39 +901,36 @@ avoid them.
and reports those that *would* fail if they were called with no variadic
arguments -- even if there is no such call in the codebase.
-This design rule is dictated by the SEI CERT rule `EXP47-C
-<https://wiki.sei.cmu.edu/confluence/display/c/EXP47-C.+Do+not+call+va_arg+with+an+argument+of+the+incorrect+type>`_,
-which describes several issues related to the use of ``va_arg()``. (The problem
+This design rule is dictated by the SEI CERT rule [EXP47-C](https://wiki.sei.cmu.edu/confluence/display/c/EXP47-C.+Do+not+call+va_arg+with+an+argument+of+the+incorrect+type),
+which describes several issues related to the use of `va_arg()`. (The problem
reported by this checker is shown in the second code example; the first,
-unrelated code example is covered by the clang diagnostic `-Wvarargs
-<https://clang.llvm.org/docs/DiagnosticsReference.html#wvarargs>`_.)
-
-.. code-block:: cpp
-
- // This function expects a list of variadic arguments terminated by a NULL pointer.
- void log_message(const char *msg, ...) {
- va_list va;
- const char *arg;
- printf("%s\n", msg);
- va_start(va, msg);
- while ((arg = va_arg(va, const char *))) {
- // warn: calls to 'log_message' always reach this va_arg() expression
- printf(" * %s\n", arg);
- }
- va_end(va);
+unrelated code example is covered by the clang diagnostic [-Wvarargs](https://clang.llvm.org/docs/DiagnosticsReference.html#wvarargs).)
+
+```cpp
+// This function expects a list of variadic arguments terminated by a NULL pointer.
+void log_message(const char *msg, ...) {
+ va_list va;
+ const char *arg;
+ printf("%s\n", msg);
+ va_start(va, msg);
+ while ((arg = va_arg(va, const char *))) {
+ // warn: calls to 'log_message' always reach this va_arg() expression
+ printf(" * %s\n", arg);
}
+ va_end(va);
+}
+```
Instead of this bugprone pattern, the SEI-CERT coding standard suggests
approaches where the number of variadic arguments can be specified in a
different manner -- for example, it can be encoded in the initial parameter
-like ``void foo(size_t num_varargs, ...)``. Those approaches are still not
-foolproof (e.g. ``foo(3, "a")`` will be undefined behavior), but they reduce
+like `void foo(size_t num_varargs, ...)`. Those approaches are still not
+foolproof (e.g. `foo(3, "a")` will be undefined behavior), but they reduce
the chances of an accidental mistake.
-.. _optin-cplusplus-UninitializedObject:
+(optin-cplusplus-uninitializedobject)=
-optin.cplusplus.UninitializedObject (C++)
-"""""""""""""""""""""""""""""""""""""""""
+#### optin.cplusplus.UninitializedObject (C++)
This checker reports uninitialized fields in objects created after a constructor
call. It doesn't only find direct uninitialized fields, but rather makes a deep
@@ -957,108 +938,102 @@ inspection of the object, analyzing all of its fields' subfields.
The checker regards inherited fields as direct fields, so one will receive
warnings for uninitialized inherited data members as well.
-.. code-block:: cpp
-
- // With Pedantic and CheckPointeeInitialization set to true
-
- struct A {
- struct B {
- int x; // note: uninitialized field 'this->b.x'
- // note: uninitialized field 'this->bptr->x'
- int y; // note: uninitialized field 'this->b.y'
- // note: uninitialized field 'this->bptr->y'
- };
- int *iptr; // note: uninitialized pointer 'this->iptr'
- B b;
- B *bptr;
- char *cptr; // note: uninitialized pointee 'this->cptr'
-
- A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
- };
-
- void f() {
- A::B b;
- char c;
- A a(&b, &c); // warning: 6 uninitialized fields
- // after the constructor call
- }
-
- // With Pedantic set to false and
- // CheckPointeeInitialization set to true
- // (every field is uninitialized)
-
- struct A {
- struct B {
- int x;
- int y;
- };
- int *iptr;
- B b;
- B *bptr;
- char *cptr;
-
- A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
- };
-
- void f() {
- A::B b;
- char c;
- A a(&b, &c); // no warning
- }
+```cpp
+// With Pedantic and CheckPointeeInitialization set to true
+
+struct A {
+ struct B {
+ int x; // note: uninitialized field 'this->b.x'
+ // note: uninitialized field 'this->bptr->x'
+ int y; // note: uninitialized field 'this->b.y'
+ // note: uninitialized field 'this->bptr->y'
+ };
+ int *iptr; // note: uninitialized pointer 'this->iptr'
+ B b;
+ B *bptr;
+ char *cptr; // note: uninitialized pointee 'this->cptr'
+
+ A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
+};
+
+void f() {
+ A::B b;
+ char c;
+ A a(&b, &c); // warning: 6 uninitialized fields
+ // after the constructor call
+}
- // With Pedantic set to true and
- // CheckPointeeInitialization set to false
- // (pointees are regarded as initialized)
-
- struct A {
- struct B {
- int x; // note: uninitialized field 'this->b.x'
- int y; // note: uninitialized field 'this->b.y'
- };
- int *iptr; // note: uninitialized pointer 'this->iptr'
- B b;
- B *bptr;
- char *cptr;
-
- A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
- };
-
- void f() {
- A::B b;
- char c;
- A a(&b, &c); // warning: 3 uninitialized fields
- // after the constructor call
- }
+// With Pedantic set to false and
+// CheckPointeeInitialization set to true
+// (every field is uninitialized)
+
+struct A {
+ struct B {
+ int x;
+ int y;
+ };
+ int *iptr;
+ B b;
+ B *bptr;
+ char *cptr;
+
+ A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
+};
+
+void f() {
+ A::B b;
+ char c;
+ A a(&b, &c); // no warning
+}
+// With Pedantic set to true and
+// CheckPointeeInitialization set to false
+// (pointees are regarded as initialized)
+
+struct A {
+ struct B {
+ int x; // note: uninitialized field 'this->b.x'
+ int y; // note: uninitialized field 'this->b.y'
+ };
+ int *iptr; // note: uninitialized pointer 'this->iptr'
+ B b;
+ B *bptr;
+ char *cptr;
+
+ A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
+};
+
+void f() {
+ A::B b;
+ char c;
+ A a(&b, &c); // warning: 3 uninitialized fields
+ // after the constructor call
+}
+```
**Options**
This checker has several options which can be set from command line (e.g.
-``-analyzer-config optin.cplusplus.UninitializedObject:Pedantic=true``):
+`-analyzer-config optin.cplusplus.UninitializedObject:Pedantic=true`):
-* ``Pedantic`` (boolean). If to false, the checker won't emit warnings for
+- `Pedantic` (boolean). If to false, the checker won't emit warnings for
objects that don't have at least one initialized field. Defaults to false.
-
-* ``NotesAsWarnings`` (boolean). If set to true, the checker will emit a
+- `NotesAsWarnings` (boolean). If set to true, the checker will emit a
warning for each uninitialized field, as opposed to emitting one warning per
constructor call, and listing the uninitialized fields that belongs to it in
notes. *Defaults to false*.
-
-* ``CheckPointeeInitialization`` (boolean). If set to false, the checker will
+- `CheckPointeeInitialization` (boolean). If set to false, the checker will
not analyze the pointee of pointer/reference fields, and will only check
whether the object itself is initialized. *Defaults to false*.
-
-* ``IgnoreRecordsWithField`` (string). If supplied, the checker will not analyze
- structures that have a field with a name or type name that matches the given
+- `IgnoreRecordsWithField` (string). If supplied, the checker will not analyze
+ structures that have a field with a name or type name that matches the given
pattern. *Defaults to ""*.
-.. _optin-cplusplus-VirtualCall:
+(optin-cplusplus-virtualcall)=
-optin.cplusplus.VirtualCall (C++)
-"""""""""""""""""""""""""""""""""
+#### optin.cplusplus.VirtualCall (C++)
-When `virtual methods are called during construction and destruction
-<https://en.cppreference.com/w/cpp/language/virtual#During_construction_and_destruction>`__
+When [virtual methods are called during construction and destruction](https://en.cppreference.com/w/cpp/language/virtual#During_construction_and_destruction)
the polymorphism is restricted to the class that's being constructed or
destructed because the more derived contexts are either not yet initialized or
already destructed.
@@ -1069,103 +1044,103 @@ virtual calls but can be affected by this restricted polymorphism.
Note that situations where this restricted polymorphism causes a call to a pure
virtual method (which is definitely invalid, triggers undefined behavior) are
-**reported by another checker:** :ref:`cplusplus-PureVirtualCall` and **this
+**reported by another checker:** {ref}`cplusplus-PureVirtualCall` and **this
checker does not report them**.
-.. code-block:: cpp
-
- struct A {
- virtual int getKind();
-
- A() {
- // warn: This calls A::getKind() even if we are constructing an instance
- // of a different class that is derived from A.
- log << "Constructing " << getKind();
- }
- virtual ~A() {
- releaseResources();
- }
- void releaseResources() {
- // warn: This can be called within ~A() and calls A::getKind() even if
- // we are destructing a class that is derived from A.
- callSomeFunction(getKind());
- }
- };
-
-.. _optin-mpi-MPI-Checker:
-
-optin.mpi.MPI-Checker (C)
-"""""""""""""""""""""""""
+```cpp
+struct A {
+ virtual int getKind();
+
+ A() {
+ // warn: This calls A::getKind() even if we are constructing an instance
+ // of a different class that is derived from A.
+ log << "Constructing " << getKind();
+ }
+ virtual ~A() {
+ releaseResources();
+ }
+ void releaseResources() {
+ // warn: This can be called within ~A() and calls A::getKind() even if
+ // we are destructing a class that is derived from A.
+ callSomeFunction(getKind());
+ }
+};
+```
+
+(optin-mpi-mpi-checker)=
+
+#### optin.mpi.MPI-Checker (C)
+
Checks MPI code.
-.. code-block:: c
-
- void test() {
- double buf = 0;
- MPI_Request sendReq1;
- MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM,
- 0, MPI_COMM_WORLD, &sendReq1);
- } // warn: request 'sendReq1' has no matching wait.
-
- void test() {
- double buf = 0;
- MPI_Request sendReq;
- MPI_Isend(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq);
- MPI_Irecv(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq); // warn
- MPI_Isend(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq); // warn
- MPI_Wait(&sendReq, MPI_STATUS_IGNORE);
- }
+```c
+void test() {
+ double buf = 0;
+ MPI_Request sendReq1;
+ MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM,
+ 0, MPI_COMM_WORLD, &sendReq1);
+} // warn: request 'sendReq1' has no matching wait.
+
+void test() {
+ double buf = 0;
+ MPI_Request sendReq;
+ MPI_Isend(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq);
+ MPI_Irecv(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq); // warn
+ MPI_Isend(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq); // warn
+ MPI_Wait(&sendReq, MPI_STATUS_IGNORE);
+}
- void missingNonBlocking() {
- int rank = 0;
- MPI_Comm_rank(MPI_COMM_WORLD, &rank);
- MPI_Request sendReq1[10][10][10];
- MPI_Wait(&sendReq1[1][7][9], MPI_STATUS_IGNORE); // warn
- }
+void missingNonBlocking() {
+ int rank = 0;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ MPI_Request sendReq1[10][10][10];
+ MPI_Wait(&sendReq1[1][7][9], MPI_STATUS_IGNORE); // warn
+}
+```
+
+(optin-osx-cocoa-localizability-emptylocalizationcontextchecker)=
-.. _optin-osx-cocoa-localizability-EmptyLocalizationContextChecker:
+#### optin.osx.cocoa.localizability.EmptyLocalizationContextChecker (ObjC)
-optin.osx.cocoa.localizability.EmptyLocalizationContextChecker (ObjC)
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Check that NSLocalizedString macros include a comment for context.
-.. code-block:: objc
+```objc
+- (void)test {
+ NSString *string = NSLocalizedString(@"LocalizedString", nil); // warn
+ NSString *string2 = NSLocalizedString(@"LocalizedString", @" "); // warn
+ NSString *string3 = NSLocalizedStringWithDefaultValue(
+ @"LocalizedString", nil, [[NSBundle alloc] init], nil,@""); // warn
+}
+```
- - (void)test {
- NSString *string = NSLocalizedString(@"LocalizedString", nil); // warn
- NSString *string2 = NSLocalizedString(@"LocalizedString", @" "); // warn
- NSString *string3 = NSLocalizedStringWithDefaultValue(
- @"LocalizedString", nil, [[NSBundle alloc] init], nil,@""); // warn
- }
+(optin-osx-cocoa-localizability-nonlocalizedstringchecker)=
-.. _optin-osx-cocoa-localizability-NonLocalizedStringChecker:
+#### optin.osx.cocoa.localizability.NonLocalizedStringChecker (ObjC)
-optin.osx.cocoa.localizability.NonLocalizedStringChecker (ObjC)
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Warns about uses of non-localized NSStrings passed to UI methods expecting localized NSStrings.
-.. code-block:: objc
+```objc
+NSString *alarmText =
+ NSLocalizedString(@"Enabled", @"Indicates alarm is turned on");
+if (!isEnabled) {
+ alarmText = @"Disabled";
+}
+UILabel *alarmStateLabel = [[UILabel alloc] init];
- NSString *alarmText =
- NSLocalizedString(@"Enabled", @"Indicates alarm is turned on");
- if (!isEnabled) {
- alarmText = @"Disabled";
- }
- UILabel *alarmStateLabel = [[UILabel alloc] init];
+// Warning: User-facing text should use localized string macro
+[alarmStateLabel setText:alarmText];
+```
- // Warning: User-facing text should use localized string macro
- [alarmStateLabel setText:alarmText];
+(optin-performance-gcdantipattern)=
-.. _optin-performance-GCDAntipattern:
+#### optin.performance.GCDAntipattern
-optin.performance.GCDAntipattern
-""""""""""""""""""""""""""""""""
Check for performance anti-patterns when using Grand Central Dispatch.
-.. _optin-performance-Padding:
+(optin-performance-padding)=
+
+#### optin.performance.Padding (C, C++, ObjC)
-optin.performance.Padding (C, C++, ObjC)
-""""""""""""""""""""""""""""""""""""""""
Check for excessively padded structs.
This checker detects structs with excessive padding, which can lead to wasted
@@ -1175,112 +1150,107 @@ as some processors require data to be aligned to certain boundaries. On others,
unaligned data access are possible, but impose significantly larger latencies.
To avoid padding bytes, the fields of a struct should be ordered by decreasing
-by alignment. Usually, its easier to think of the ``sizeof`` of the fields, and
-ordering the fields by ``sizeof`` would usually also lead to the same optimal
+by alignment. Usually, its easier to think of the `sizeof` of the fields, and
+ordering the fields by `sizeof` would usually also lead to the same optimal
layout.
-In rare cases, one can use the ``#pragma pack(1)`` directive to enforce a packed
+In rare cases, one can use the `#pragma pack(1)` directive to enforce a packed
layout too, but it can significantly increase the access times, so reordering the
fields is usually a better solution.
-
-.. code-block:: cpp
-
- // warn: Excessive padding in 'struct NonOptimal' (35 padding bytes, where 3 is optimal)
- struct NonOptimal {
- char c1;
- // 7 bytes of padding
- std::int64_t big1; // 8 bytes
- char c2;
- // 7 bytes of padding
- std::int64_t big2; // 8 bytes
- char c3;
- // 7 bytes of padding
- std::int64_t big3; // 8 bytes
- char c4;
- // 7 bytes of padding
- std::int64_t big4; // 8 bytes
- char c5;
- // 7 bytes of padding
- };
- static_assert(sizeof(NonOptimal) == 4*8+5+5*7);
-
- // no-warning: The fields are nicely aligned to have the minimal amount of padding bytes.
- struct Optimal {
- std::int64_t big1; // 8 bytes
- std::int64_t big2; // 8 bytes
- std::int64_t big3; // 8 bytes
- std::int64_t big4; // 8 bytes
- char c1;
- char c2;
- char c3;
- char c4;
- char c5;
- // 3 bytes of padding
- };
- static_assert(sizeof(Optimal) == 4*8+5+3);
-
- // no-warning: Bit packing representation is also accepted by this checker, but
- // it can significantly increase access times, so prefer reordering the fields.
- #pragma pack(1)
- struct BitPacked {
- char c1;
- std::int64_t big1; // 8 bytes
- char c2;
- std::int64_t big2; // 8 bytes
- char c3;
- std::int64_t big3; // 8 bytes
- char c4;
- std::int64_t big4; // 8 bytes
- char c5;
- };
- static_assert(sizeof(BitPacked) == 4*8+5);
-
-The ``AllowedPad`` option can be used to specify a threshold for the number
+```cpp
+// warn: Excessive padding in 'struct NonOptimal' (35 padding bytes, where 3 is optimal)
+struct NonOptimal {
+ char c1;
+ // 7 bytes of padding
+ std::int64_t big1; // 8 bytes
+ char c2;
+ // 7 bytes of padding
+ std::int64_t big2; // 8 bytes
+ char c3;
+ // 7 bytes of padding
+ std::int64_t big3; // 8 bytes
+ char c4;
+ // 7 bytes of padding
+ std::int64_t big4; // 8 bytes
+ char c5;
+ // 7 bytes of padding
+};
+static_assert(sizeof(NonOptimal) == 4*8+5+5*7);
+
+// no-warning: The fields are nicely aligned to have the minimal amount of padding bytes.
+struct Optimal {
+ std::int64_t big1; // 8 bytes
+ std::int64_t big2; // 8 bytes
+ std::int64_t big3; // 8 bytes
+ std::int64_t big4; // 8 bytes
+ char c1;
+ char c2;
+ char c3;
+ char c4;
+ char c5;
+ // 3 bytes of padding
+};
+static_assert(sizeof(Optimal) == 4*8+5+3);
+
+// no-warning: Bit packing representation is also accepted by this checker, but
+// it can significantly increase access times, so prefer reordering the fields.
+#pragma pack(1)
+struct BitPacked {
+ char c1;
+ std::int64_t big1; // 8 bytes
+ char c2;
+ std::int64_t big2; // 8 bytes
+ char c3;
+ std::int64_t big3; // 8 bytes
+ char c4;
+ std::int64_t big4; // 8 bytes
+ char c5;
+};
+static_assert(sizeof(BitPacked) == 4*8+5);
+```
+
+The `AllowedPad` option can be used to specify a threshold for the number
padding bytes raising the warning. If the number of padding bytes of the struct
and the optimal number of padding bytes differ by more than the threshold value,
a warning will be raised.
-By default, the ``AllowedPad`` threshold is 24 bytes.
+By default, the `AllowedPad` threshold is 24 bytes.
To override this threshold to e.g. 4 bytes, use the
-``-analyzer-config optin.performance.Padding:AllowedPad=4`` option.
+`-analyzer-config optin.performance.Padding:AllowedPad=4` option.
+(optin-portability-unixapi)=
-.. _optin-portability-UnixAPI:
+#### optin.portability.UnixAPI
-optin.portability.UnixAPI
-"""""""""""""""""""""""""
Reports situations where 0 is passed as the "size" argument of various
-allocation functions ( ``calloc``, ``malloc``, ``realloc``, ``reallocf``,
-``alloca``, ``__builtin_alloca``, ``__builtin_alloca_with_align``, ``valloc``).
+allocation functions ( `calloc`, `malloc`, `realloc`, `reallocf`,
+`alloca`, `__builtin_alloca`, `__builtin_alloca_with_align`, `valloc`).
-Note that similar functionality is also supported by :ref:`unix-Malloc` which
+Note that similar functionality is also supported by {ref}`unix-Malloc` which
reports code that *uses* memory allocated with size zero.
(The name of this checker is motivated by the fact that it was originally
introduced with the vague goal that it "Finds implementation-defined behavior
in UNIX/Posix functions.")
-
-optin.taint
-^^^^^^^^^^^
+### optin.taint
Checkers implementing
-`taint analysis <https://en.wikipedia.org/wiki/Taint_checking>`_.
+[taint analysis](https://en.wikipedia.org/wiki/Taint_checking).
-.. _optin-taint-GenericTaint:
+(optin-taint-generictaint)=
-optin.taint.GenericTaint (C, C++)
-"""""""""""""""""""""""""""""""""
+#### optin.taint.GenericTaint (C, C++)
Taint analysis identifies potential security vulnerabilities where the
attacker can inject malicious data to the program to execute an attack
(privilege escalation, command injection, SQL injection etc.).
-The malicious data is injected at the taint source (e.g. ``getenv()`` call)
+The malicious data is injected at the taint source (e.g. `getenv()` call)
which is then propagated through function calls and being used as arguments of
-sensitive operations, also called as taint sinks (e.g. ``system()`` call).
+sensitive operations, also called as taint sinks (e.g. `system()` call).
One can defend against this type of vulnerability by always checking and
sanitizing the potentially malicious, untrusted user input.
@@ -1290,24 +1260,24 @@ taint source-sink pairs and the propagation call chain.
The most notable examples of taint sources are:
- - data from network
- - files or standard input
- - environment variables
- - data from databases
+> - data from network
+> - files or standard input
+> - environment variables
+> - data from databases
Let us examine a practical example of a Command Injection attack.
-.. code-block:: c
-
- // Command Injection Vulnerability Example
- int main(int argc, char** argv) {
- char cmd[2048] = "/bin/cat ";
- char filename[1024];
- printf("Filename:");
- scanf (" %1023[^\n]", filename); // The attacker can inject a shell escape here
- strcat(cmd, filename);
- system(cmd); // Warning: Untrusted data is passed to a system call
- }
+```c
+// Command Injection Vulnerability Example
+int main(int argc, char** argv) {
+ char cmd[2048] = "/bin/cat ";
+ char filename[1024];
+ printf("Filename:");
+ scanf (" %1023[^\n]", filename); // The attacker can inject a shell escape here
+ strcat(cmd, filename);
+ system(cmd); // Warning: Untrusted data is passed to a system call
+}
+```
The program prints the content of any user specified file.
Unfortunately the attacker can execute arbitrary commands
@@ -1320,45 +1290,45 @@ The analysis implemented in this checker points out this problem.
One can protect against such attack by for example checking if the provided
input refers to a valid file and removing any invalid user input.
-.. code-block:: c
-
- // No vulnerability anymore, but we still get the warning
- void sanitizeFileName(char* filename){
- if (access(filename,F_OK)){// Verifying user input
- printf("File does not exist\n");
- filename[0]='\0';
- }
- }
- int main(int argc, char** argv) {
- char cmd[2048] = "/bin/cat ";
- char filename[1024];
- printf("Filename:");
- scanf (" %1023[^\n]", filename); // The attacker can inject a shell escape here
- sanitizeFileName(filename);// filename is safe after this point
- if (!filename[0])
- return -1;
- strcat(cmd, filename);
- system(cmd); // Superfluous Warning: Untrusted data is passed to a system call
- }
+```c
+// No vulnerability anymore, but we still get the warning
+void sanitizeFileName(char* filename){
+ if (access(filename,F_OK)){// Verifying user input
+ printf("File does not exist\n");
+ filename[0]='\0';
+ }
+}
+int main(int argc, char** argv) {
+ char cmd[2048] = "/bin/cat ";
+ char filename[1024];
+ printf("Filename:");
+ scanf (" %1023[^\n]", filename); // The attacker can inject a shell escape here
+ sanitizeFileName(filename);// filename is safe after this point
+ if (!filename[0])
+ return -1;
+ strcat(cmd, filename);
+ system(cmd); // Superfluous Warning: Untrusted data is passed to a system call
+}
+```
Unfortunately, the checker cannot discover automatically that the programmer
have performed data sanitation, so it still emits the warning.
One can get rid of this superfluous warning by telling by specifying the
sanitation functions in the taint configuration file (see
-:doc:`user-docs/TaintAnalysisConfiguration`).
+{doc}`user-docs/TaintAnalysisConfiguration`).
-.. code-block:: YAML
-
- Filters:
- - Name: sanitizeFileName
- Args: [0]
+```YAML
+Filters:
+- Name: sanitizeFileName
+ Args: [0]
+```
The clang invocation to pass the configuration file location:
-.. code-block:: bash
-
- clang --analyze -Xclang -analyzer-config -Xclang optin.taint.TaintPropagation:Config=`pwd`/taint_config.yml ...
+```bash
+clang --analyze -Xclang -analyzer-config -Xclang optin.taint.TaintPropagation:Config=`pwd`/taint_config.yml ...
+```
If you are validating your inputs instead of sanitizing them, or don't want to
mention each sanitizing function in our configuration,
@@ -1368,41 +1338,41 @@ Introduce a generic no-op `csa_mark_sanitized(..)` function to
tell the Clang Static Analyzer
that the variable is safe to be used on that analysis path.
-.. code-block:: c
-
- // Marking sanitized variables safe.
- // No vulnerability anymore, no warning.
-
- // User csa_mark_sanitize function is for the analyzer only
+```c
+// Marking sanitized variables safe.
+// No vulnerability anymore, no warning.
+
+// User csa_mark_sanitize function is for the analyzer only
+#ifdef __clang_analyzer__
+ void csa_mark_sanitized(const void *);
+#endif
+
+int main(int argc, char** argv) {
+ char cmd[2048] = "/bin/cat ";
+ char filename[1024];
+ printf("Filename:");
+ scanf (" %1023[^\n]", filename);
+ if (access(filename,F_OK)){// Verifying user input
+ printf("File does not exist\n");
+ return -1;
+ }
#ifdef __clang_analyzer__
- void csa_mark_sanitized(const void *);
+ csa_mark_sanitized(filename); // Indicating to CSA that filename variable is safe to be used after this point
#endif
-
- int main(int argc, char** argv) {
- char cmd[2048] = "/bin/cat ";
- char filename[1024];
- printf("Filename:");
- scanf (" %1023[^\n]", filename);
- if (access(filename,F_OK)){// Verifying user input
- printf("File does not exist\n");
- return -1;
- }
- #ifdef __clang_analyzer__
- csa_mark_sanitized(filename); // Indicating to CSA that filename variable is safe to be used after this point
- #endif
- strcat(cmd, filename);
- system(cmd); // No warning
- }
+ strcat(cmd, filename);
+ system(cmd); // No warning
+}
+```
Similarly to the previous example, you need to
define a `Filter` function in a `YAML` configuration file
and add the `csa_mark_sanitized` function.
-.. code-block:: YAML
-
- Filters:
- - Name: csa_mark_sanitized
- Args: [0]
+```YAML
+Filters:
+- Name: csa_mark_sanitized
+ Args: [0]
+```
Then calling `csa_mark_sanitized(X)` will tell the analyzer that `X` is safe to
be used after this point, because its contents are verified. It is the
@@ -1412,527 +1382,515 @@ used during Clang Static Analysis and skipped in (production) builds.
Further examples of injection vulnerabilities this checker can find.
-.. code-block:: c
-
- void test() {
- char x = getchar(); // 'x' marked as tainted
- system(&x); // warn: untrusted data is passed to a system call
- }
+```c
+void test() {
+ char x = getchar(); // 'x' marked as tainted
+ system(&x); // warn: untrusted data is passed to a system call
+}
- // note: compiler internally checks if the second param to
- // sprintf is a string literal or not.
- // Use -Wno-format-security to suppress compiler warning.
- void test() {
- char s[10], buf[10];
- fscanf(stdin, "%s", s); // 's' marked as tainted
+// note: compiler internally checks if the second param to
+// sprintf is a string literal or not.
+// Use -Wno-format-security to suppress compiler warning.
+void test() {
+ char s[10], buf[10];
+ fscanf(stdin, "%s", s); // 's' marked as tainted
- sprintf(buf, s); // warn: untrusted data used as a format string
- }
+ sprintf(buf, s); // warn: untrusted data used as a format string
+}
+```
There are built-in sources, propagations and sinks even if no external taint
configuration is provided.
Default sources:
- ``_IO_getc``, ``fdopen``, ``fopen``, ``freopen``, ``get_current_dir_name``,
- ``getch``, ``getchar``, ``getchar_unlocked``, ``getwd``, ``getcwd``,
- ``getgroups``, ``gethostname``, ``getlogin``, ``getlogin_r``, ``getnameinfo``,
- ``gets``, ``gets_s``, ``getseuserbyname``, ``readlink``, ``readlinkat``,
- ``scanf``, ``scanf_s``, ``socket``, ``wgetch``
+
+: `_IO_getc`, `fdopen`, `fopen`, `freopen`, `get_current_dir_name`,
+ `getch`, `getchar`, `getchar_unlocked`, `getwd`, `getcwd`,
+ `getgroups`, `gethostname`, `getlogin`, `getlogin_r`, `getnameinfo`,
+ `gets`, `gets_s`, `getseuserbyname`, `readlink`, `readlinkat`,
+ `scanf`, `scanf_s`, `socket`, `wgetch`
Default propagations rules:
- ``atoi``, ``atol``, ``atoll``, ``basename``, ``dirname``, ``fgetc``,
- ``fgetln``, ``fgets``, ``fnmatch``, ``fread``, ``fscanf``, ``fscanf_s``,
- ``index``, ``inflate``, ``isalnum``, ``isalpha``, ``isascii``, ``isblank``,
- ``iscntrl``, ``isdigit``, ``isgraph``, ``islower``, ``isprint``, ``ispunct``,
- ``isspace``, ``isupper``, ``isxdigit``, ``memchr``, ``memrchr``, ``sscanf``,
- ``getc``, ``getc_unlocked``, ``getdelim``, ``getline``, ``getw``, ``memcmp``,
- ``memcpy``, ``memmem``, ``memmove``, ``mbtowc``, ``pread``, ``qsort``,
- ``qsort_r``, ``rawmemchr``, ``read``, ``recv``, ``recvfrom``, ``rindex``,
- ``strcasestr``, ``strchr``, ``strchrnul``, ``strcasecmp``, ``strcmp``,
- ``strcspn``, ``strncasecmp``, ``strncmp``, ``strndup``,
- ``strndupa``, ``strpbrk``, ``strrchr``, ``strsep``, ``strspn``,
- ``strstr``, ``strtol``, ``strtoll``, ``strtoul``, ``strtoull``, ``tolower``,
- ``toupper``, ``ttyname``, ``ttyname_r``, ``wctomb``, ``wcwidth``
+
+: `atoi`, `atol`, `atoll`, `basename`, `dirname`, `fgetc`,
+ `fgetln`, `fgets`, `fnmatch`, `fread`, `fscanf`, `fscanf_s`,
+ `index`, `inflate`, `isalnum`, `isalpha`, `isascii`, `isblank`,
+ `iscntrl`, `isdigit`, `isgraph`, `islower`, `isprint`, `ispunct`,
+ `isspace`, `isupper`, `isxdigit`, `memchr`, `memrchr`, `sscanf`,
+ `getc`, `getc_unlocked`, `getdelim`, `getline`, `getw`, `memcmp`,
+ `memcpy`, `memmem`, `memmove`, `mbtowc`, `pread`, `qsort`,
+ `qsort_r`, `rawmemchr`, `read`, `recv`, `recvfrom`, `rindex`,
+ `strcasestr`, `strchr`, `strchrnul`, `strcasecmp`, `strcmp`,
+ `strcspn`, `strncasecmp`, `strncmp`, `strndup`,
+ `strndupa`, `strpbrk`, `strrchr`, `strsep`, `strspn`,
+ `strstr`, `strtol`, `strtoll`, `strtoul`, `strtoull`, `tolower`,
+ `toupper`, `ttyname`, `ttyname_r`, `wctomb`, `wcwidth`
Default sinks:
- ``printf``, ``setproctitle``, ``system``, ``popen``, ``execl``, ``execle``,
- ``execlp``, ``execv``, ``execvp``, ``execvP``, ``execve``, ``dlopen``
+
+: `printf`, `setproctitle`, `system`, `popen`, `execl`, `execle`,
+ `execlp`, `execv`, `execvp`, `execvP`, `execve`, `dlopen`
Please note that there are no built-in filter functions.
One can configure their own taint sources, sinks, and propagation rules by
providing a configuration file via checker option
-``optin.taint.TaintPropagation:Config``. The configuration file is in
-`YAML <http://llvm.org/docs/YamlIO.html#introduction-to-yaml>`_ format. The
+`optin.taint.TaintPropagation:Config`. The configuration file is in
+[YAML](http://llvm.org/docs/YamlIO.html#introduction-to-yaml) format. The
taint-related options defined in the config file extend but do not override the
built-in sources, rules, sinks. The format of the external taint configuration
file is not stable, and could change without any notice even in a non-backward
compatible way.
For a more detailed description of configuration options, please see the
-:doc:`user-docs/TaintAnalysisConfiguration`. For an example see
-:ref:`clangsa-taint-configuration-example`.
+{doc}`user-docs/TaintAnalysisConfiguration`. For an example see
+{ref}`clangsa-taint-configuration-example`.
**Configuration**
-* ``optin.taint.TaintPropagation:Config`` Specifies the name of the YAML
+- `optin.taint.TaintPropagation:Config` Specifies the name of the YAML
configuration file. The user can define their own taint sources and sinks.
-* ``optin.taint.TaintPropagation:EnableDefaultConfig`` If set to false,
- the default source, sink and propagation rules are not loaded. This way,
- advanced users can fully customize their taint configuration model.
- Default: ``true``.
-
-* If the analyzer option ``assume-controlled-environment`` is set to ``false``,
+- `optin.taint.TaintPropagation:EnableDefaultConfig` If set to false,
+ : the default source, sink and propagation rules are not loaded. This way,
+ advanced users can fully customize their taint configuration model.
+ Default: `true`.
+- If the analyzer option `assume-controlled-environment` is set to `false`,
it is assumed that the command line arguments and the environment
variables of the program are attacker controlled.
- In particular, the ``argv``, ``argc`` and ``envp`` arguments of the
- ``main`` function and the return value of the ``getenv()``
+ In particular, the `argv`, `argc` and `envp` arguments of the
+ `main` function and the return value of the `getenv()`
function are assumed to hold tainted values.
**Related Guidelines**
-* `CWE Data Neutralization Issues
- <https://cwe.mitre.org/data/definitions/137.html>`_
-* `SEI Cert STR02-C. Sanitize data passed to complex subsystems
- <https://wiki.sei.cmu.edu/confluence/display/c/STR02-C.+Sanitize+data+passed+to+complex+subsystems>`_
-* `SEI Cert ENV33-C. Do not call system()
- <https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152177>`_
-* `ENV03-C. Sanitize the environment when invoking external programs
- <https://wiki.sei.cmu.edu/confluence/display/c/ENV03-C.+Sanitize+the+environment+when+invoking+external+programs>`_
+- [CWE Data Neutralization Issues](https://cwe.mitre.org/data/definitions/137.html)
+- [SEI Cert STR02-C. Sanitize data passed to complex subsystems](https://wiki.sei.cmu.edu/confluence/display/c/STR02-C.+Sanitize+data+passed+to+complex+subsystems)
+- [SEI Cert ENV33-C. Do not call system()](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152177)
+- [ENV03-C. Sanitize the environment when invoking external programs](https://wiki.sei.cmu.edu/confluence/display/c/ENV03-C.+Sanitize+the+environment+when+invoking+external+programs)
**Limitations**
-* The taintedness property is not propagated through function calls which are
+- The taintedness property is not propagated through function calls which are
unknown (or too complex) to the analyzer, unless there is a specific
propagation rule built-in to the checker or given in the YAML configuration
file. This causes potential true positive findings to be lost.
+(optin-taint-taintedalloc)=
-.. _optin-taint-TaintedAlloc:
-
-optin.taint.TaintedAlloc (C, C++)
-"""""""""""""""""""""""""""""""""
+#### optin.taint.TaintedAlloc (C, C++)
-This checker warns for cases when the ``size`` parameter of the ``malloc`` ,
-``calloc``, ``realloc``, ``alloca`` or the size parameter of the
+This checker warns for cases when the `size` parameter of the `malloc` ,
+`calloc`, `realloc`, `alloca` or the size parameter of the
array new C++ operator is tainted (potentially attacker controlled).
If an attacker can inject a large value as the size parameter, memory exhaustion
denial of service attack can be carried out.
The analyzer emits warning only if it cannot prove that the size parameter is
-within reasonable bounds (``<= SIZE_MAX/4``). This functionality partially
-covers the SEI Cert coding standard rule `INT04-C
-<https://wiki.sei.cmu.edu/confluence/display/c/INT04-C.+Enforce+limits+on+integer+values+originating+from+tainted+sources>`_.
+within reasonable bounds (`<= SIZE_MAX/4`). This functionality partially
+covers the SEI Cert coding standard rule [INT04-C](https://wiki.sei.cmu.edu/confluence/display/c/INT04-C.+Enforce+limits+on+integer+values+originating+from+tainted+sources).
-You can silence this warning either by bound checking the ``size`` parameter, or
-by explicitly marking the ``size`` parameter as sanitized. See the
-:ref:`optin-taint-GenericTaint` checker for an example.
+You can silence this warning either by bound checking the `size` parameter, or
+by explicitly marking the `size` parameter as sanitized. See the
+{ref}`optin-taint-GenericTaint` checker for an example.
Custom allocation/deallocation functions can be defined using
-:ref:`ownership attributes<analyzer-ownership-attrs>`.
-
-.. code-block:: c
+{ref}`ownership attributes<analyzer-ownership-attrs>`.
+
+```c
+void vulnerable(void) {
+ size_t size = 0;
+ scanf("%zu", &size);
+ int *p = malloc(size); // warn: malloc is called with a tainted (potentially attacker controlled) value
+ free(p);
+}
- void vulnerable(void) {
- size_t size = 0;
- scanf("%zu", &size);
- int *p = malloc(size); // warn: malloc is called with a tainted (potentially attacker controlled) value
- free(p);
- }
+void not_vulnerable(void) {
+ size_t size = 0;
+ scanf("%zu", &size);
+ if (1024 < size)
+ return;
+ int *p = malloc(size); // No warning expected as the the user input is bound
+ free(p);
+}
- void not_vulnerable(void) {
- size_t size = 0;
- scanf("%zu", &size);
- if (1024 < size)
- return;
- int *p = malloc(size); // No warning expected as the the user input is bound
- free(p);
- }
+void vulnerable_cpp(void) {
+ size_t size = 0;
+ scanf("%zu", &size);
+ int *ptr = new int[size];// warn: Memory allocation function is called with a tainted (potentially attacker controlled) value
+ delete[] ptr;
+}
+```
- void vulnerable_cpp(void) {
- size_t size = 0;
- scanf("%zu", &size);
- int *ptr = new int[size];// warn: Memory allocation function is called with a tainted (potentially attacker controlled) value
- delete[] ptr;
- }
+(optin-taint-tainteddiv)=
-.. _optin-taint-TaintedDiv:
+#### optin.taint.TaintedDiv (C, C++, ObjC)
-optin.taint.TaintedDiv (C, C++, ObjC)
-"""""""""""""""""""""""""""""""""""""
This checker warns when the denominator in a division
operation is a tainted (potentially attacker controlled) value.
If the attacker can set the denominator to 0, a runtime error can
be triggered. The checker warns when the denominator is a tainted
value and the analyzer cannot prove that it is not 0. This warning
-is more pessimistic than the :ref:`core-DivideZero` checker
+is more pessimistic than the {ref}`core-DivideZero` checker
which warns only when it can prove that the denominator is 0.
-.. code-block:: c
-
- int vulnerable(int n) {
- size_t size = 0;
- scanf("%zu", &size);
- return n / size; // warn: Division by a tainted value, possibly zero
- }
+```c
+int vulnerable(int n) {
+ size_t size = 0;
+ scanf("%zu", &size);
+ return n / size; // warn: Division by a tainted value, possibly zero
+}
- int not_vulnerable(int n) {
- size_t size = 0;
- scanf("%zu", &size);
- if (!size)
- return 0;
- return n / size; // no warning
- }
+int not_vulnerable(int n) {
+ size_t size = 0;
+ scanf("%zu", &size);
+ if (!size)
+ return 0;
+ return n / size; // no warning
+}
+```
-.. _security-checkers:
+(security-checkers)=
-security
-^^^^^^^^
+### security
Security related checkers.
-.. _security-ArrayBound:
+(security-arraybound)=
+
+#### security.ArrayBound (C, C++)
-security.ArrayBound (C, C++)
-""""""""""""""""""""""""""""
Report out of bounds access to memory that is before the start or after the end
of the accessed region (array, heap-allocated region, string literal etc.).
This usually means incorrect indexing, but the checker also detects access via
-the operators ``*`` and ``->``.
-
-.. code-block:: c
+the operators `*` and `->`.
- void test_underflow(int x) {
- int buf[100][100];
- if (x < 0)
- buf[0][x] = 1; // warn
- }
+```c
+void test_underflow(int x) {
+ int buf[100][100];
+ if (x < 0)
+ buf[0][x] = 1; // warn
+}
- void test_overflow() {
- int buf[100];
- int *p = buf + 100;
- *p = 1; // warn
- }
+void test_overflow() {
+ int buf[100];
+ int *p = buf + 100;
+ *p = 1; // warn
+}
+```
-If checkers like :ref:`unix-Malloc` or :ref:`cplusplus-NewDelete` are enabled
-to model the behavior of ``malloc()``, ``operator new`` and similar
+If checkers like {ref}`unix-Malloc` or {ref}`cplusplus-NewDelete` are enabled
+to model the behavior of `malloc()`, `operator new` and similar
allocators), then this checker can also reports out of bounds access to
dynamically allocated memory:
-.. code-block:: cpp
-
- int *test_dynamic() {
- int *mem = new int[100];
- mem[-1] = 42; // warn
- return mem;
- }
+```cpp
+int *test_dynamic() {
+ int *mem = new int[100];
+ mem[-1] = 42; // warn
+ return mem;
+}
+```
In uncertain situations (when the checker can neither prove nor disprove that
overflow occurs), the checker assumes that the the index (more precisely, the
memory offeset) is within bounds.
-However, if :ref:`optin-taint-GenericTaint` is enabled and the index/offset is
+However, if {ref}`optin-taint-GenericTaint` is enabled and the index/offset is
tainted (i.e. it is influenced by an untrusted source), then this checker
reports the potential out of bounds access:
-.. code-block:: c
-
- void test_with_tainted_index() {
- char s[] = "abc";
- int x = getchar();
- char c = s[x]; // warn: potential out of bounds access with tainted index
- }
-
-.. note::
+```c
+void test_with_tainted_index() {
+ char s[] = "abc";
+ int x = getchar();
+ char c = s[x]; // warn: potential out of bounds access with tainted index
+}
+```
- This checker is an improved and renamed version of the checker that was
- previously known as ``alpha.security.ArrayBoundV2``. The old checker
- ``alpha.security.ArrayBound`` was removed when the (previously
- "experimental") V2 variant became stable enough for regular use.
+:::{note}
+This checker is an improved and renamed version of the checker that was
+previously known as `alpha.security.ArrayBoundV2`. The old checker
+`alpha.security.ArrayBound` was removed when the (previously
+"experimental") V2 variant became stable enough for regular use.
+:::
-.. _security-cert-env-InvalidPtr:
+(security-cert-env-invalidptr)=
-security.cert.env.InvalidPtr
-""""""""""""""""""""""""""""
+#### security.cert.env.InvalidPtr
-Corresponds to SEI CERT Rules `ENV31-C <https://wiki.sei.cmu.edu/confluence/display/c/ENV31-C.+Do+not+rely+on+an+environment+pointer+following+an+operation+that+may+invalidate+it>`_ and `ENV34-C <https://wiki.sei.cmu.edu/confluence/display/c/ENV34-C.+Do+not+store+pointers+returned+by+certain+functions>`_.
+Corresponds to SEI CERT Rules [ENV31-C](https://wiki.sei.cmu.edu/confluence/display/c/ENV31-C.+Do+not+rely+on+an+environment+pointer+following+an+operation+that+may+invalidate+it) and [ENV34-C](https://wiki.sei.cmu.edu/confluence/display/c/ENV34-C.+Do+not+store+pointers+returned+by+certain+functions).
-* **ENV31-C**:
- Rule is about the possible problem with ``main`` function's third argument, environment pointer,
+- **ENV31-C**:
+ Rule is about the possible problem with `main` function's third argument, environment pointer,
"envp". When environment array is modified using some modification function
- such as ``putenv``, ``setenv`` or others, It may happen that memory is reallocated,
+ such as `putenv`, `setenv` or others, It may happen that memory is reallocated,
however "envp" is not updated to reflect the changes and points to old memory
region.
-
-* **ENV34-C**:
+- **ENV34-C**:
Some functions return a pointer to a statically allocated buffer.
Consequently, subsequent call of these functions will invalidate previous
- pointer. These functions include: ``getenv``, ``localeconv``, ``asctime``, ``setlocale``, ``strerror``
+ pointer. These functions include: `getenv`, `localeconv`, `asctime`, `setlocale`, `strerror`
-.. code-block:: c
-
- int main(int argc, const char *argv[], const char *envp[]) {
- if (setenv("MY_NEW_VAR", "new_value", 1) != 0) {
- // setenv call may invalidate 'envp'
- /* Handle error */
- }
- if (envp != NULL) {
- for (size_t i = 0; envp[i] != NULL; ++i) {
- puts(envp[i]);
- // envp may no longer point to the current environment
- // this program has unanticipated behavior, since envp
- // does not reflect changes made by setenv function.
- }
+```c
+int main(int argc, const char *argv[], const char *envp[]) {
+ if (setenv("MY_NEW_VAR", "new_value", 1) != 0) {
+ // setenv call may invalidate 'envp'
+ /* Handle error */
+ }
+ if (envp != NULL) {
+ for (size_t i = 0; envp[i] != NULL; ++i) {
+ puts(envp[i]);
+ // envp may no longer point to the current environment
+ // this program has unanticipated behavior, since envp
+ // does not reflect changes made by setenv function.
}
- return 0;
}
+ return 0;
+}
- void previous_call_invalidation() {
- char *p, *pp;
-
- p = getenv("VAR");
- setenv("SOMEVAR", "VALUE", /*overwrite = */1);
- // call to 'setenv' may invalidate p
+void previous_call_invalidation() {
+ char *p, *pp;
- *p;
- // dereferencing invalid pointer
- }
+ p = getenv("VAR");
+ setenv("SOMEVAR", "VALUE", /*overwrite = */1);
+ // call to 'setenv' may invalidate p
+ *p;
+ // dereferencing invalid pointer
+}
+```
-The ``InvalidatingGetEnv`` option is available for treating ``getenv`` calls as
-invalidating. When enabled, the checker issues a warning if ``getenv`` is called
+The `InvalidatingGetEnv` option is available for treating `getenv` calls as
+invalidating. When enabled, the checker issues a warning if `getenv` is called
multiple times and their results are used without first creating a copy.
This level of strictness might be considered overly pedantic for the commonly
-used ``getenv`` implementations.
+used `getenv` implementations.
To enable this option, use:
-``-analyzer-config security.cert.env.InvalidPtr:InvalidatingGetEnv=true``.
+`-analyzer-config security.cert.env.InvalidPtr:InvalidatingGetEnv=true`.
By default, this option is set to *false*.
When this option is enabled, warnings will be generated for scenarios like the
following:
-.. code-block:: c
+```c
+char* p = getenv("VAR");
+char* pp = getenv("VAR2"); // assumes this call can invalidate `env`
+strlen(p); // warns about accessing invalid ptr
+```
- char* p = getenv("VAR");
- char* pp = getenv("VAR2"); // assumes this call can invalidate `env`
- strlen(p); // warns about accessing invalid ptr
+(security-floatloopcounter)=
-.. _security-FloatLoopCounter:
+#### security.FloatLoopCounter (C)
-security.FloatLoopCounter (C)
-"""""""""""""""""""""""""""""
Warn on using a floating point value as a loop counter (CERT: FLP30-C, FLP30-CPP).
-.. code-block:: c
+```c
+void test() {
+ for (float x = 0.1f; x <= 1.0f; x += 0.1f) {} // warn
+}
+```
- void test() {
- for (float x = 0.1f; x <= 1.0f; x += 0.1f) {} // warn
- }
+(security-insecureapi-uncheckedreturn)=
-.. _security-insecureAPI-UncheckedReturn:
+#### security.insecureAPI.UncheckedReturn (C)
-security.insecureAPI.UncheckedReturn (C)
-""""""""""""""""""""""""""""""""""""""""
Warn on uses of functions whose return values must be always checked.
-.. code-block:: c
+```c
+void test() {
+ setuid(1); // warn
+}
+```
- void test() {
- setuid(1); // warn
- }
+(security-insecureapi-bcmp)=
-.. _security-insecureAPI-bcmp:
+#### security.insecureAPI.bcmp (C)
-security.insecureAPI.bcmp (C)
-"""""""""""""""""""""""""""""
Warn on uses of the 'bcmp' function.
-.. code-block:: c
+```c
+void test() {
+ bcmp(ptr0, ptr1, n); // warn
+}
+```
- void test() {
- bcmp(ptr0, ptr1, n); // warn
- }
+(security-insecureapi-bcopy)=
-.. _security-insecureAPI-bcopy:
+#### security.insecureAPI.bcopy (C)
-security.insecureAPI.bcopy (C)
-""""""""""""""""""""""""""""""
Warn on uses of the 'bcopy' function.
-.. code-block:: c
+```c
+void test() {
+ bcopy(src, dst, n); // warn
+}
+```
- void test() {
- bcopy(src, dst, n); // warn
- }
+(security-insecureapi-bzero)=
-.. _security-insecureAPI-bzero:
+#### security.insecureAPI.bzero (C)
-security.insecureAPI.bzero (C)
-""""""""""""""""""""""""""""""
Warn on uses of the 'bzero' function.
-.. code-block:: c
-
- void test() {
- bzero(ptr, n); // warn
- }
+```c
+void test() {
+ bzero(ptr, n); // warn
+}
+```
-.. _security-insecureAPI-decodeValueOfObjCType:
+(security-insecureapi-decodevalueofobjctype)=
-security.insecureAPI.decodeValueOfObjCType (C)
-""""""""""""""""""""""""""""""""""""""""""""""
-Warn on uses of the Objective-C method ``-decodeValueOfObjCType:at:``.
+#### security.insecureAPI.decodeValueOfObjCType (C)
-.. code-block:: objc
+Warn on uses of the Objective-C method `-decodeValueOfObjCType:at:`.
- void test(NSCoder *decoder) {
- unsigned int x;
- [decoder decodeValueOfObjCType:"I" at:&x]; // warn
- }
+```objc
+void test(NSCoder *decoder) {
+ unsigned int x;
+ [decoder decodeValueOfObjCType:"I" at:&x]; // warn
+}
+```
This diagnostic is emitted only on Apple platforms where the safer
-``-decodeValueOfObjCType:at:size:`` alternative is available
+`-decodeValueOfObjCType:at:size:` alternative is available
(iOS 11+, macOS 10.13+, tvOS 11+, watchOS 4.0+).
-.. _security-insecureAPI-getpw:
+(security-insecureapi-getpw)=
+
+#### security.insecureAPI.getpw (C)
-security.insecureAPI.getpw (C)
-""""""""""""""""""""""""""""""
Warn on uses of the 'getpw' function.
-.. code-block:: c
+```c
+void test() {
+ char buff[1024];
+ getpw(2, buff); // warn
+}
+```
- void test() {
- char buff[1024];
- getpw(2, buff); // warn
- }
+(security-insecureapi-gets)=
-.. _security-insecureAPI-gets:
+#### security.insecureAPI.gets (C)
-security.insecureAPI.gets (C)
-"""""""""""""""""""""""""""""
Warn on uses of the 'gets' function.
-.. code-block:: c
+```c
+void test() {
+ char buff[1024];
+ gets(buff); // warn
+}
+```
- void test() {
- char buff[1024];
- gets(buff); // warn
- }
+(security-insecureapi-mkstemp)=
-.. _security-insecureAPI-mkstemp:
+#### security.insecureAPI.mkstemp (C)
-security.insecureAPI.mkstemp (C)
-""""""""""""""""""""""""""""""""
Warn when 'mkstemp' is passed fewer than 6 X's in the format string.
-.. code-block:: c
+```c
+void test() {
+ mkstemp("XX"); // warn
+}
+```
- void test() {
- mkstemp("XX"); // warn
- }
+(security-insecureapi-mktemp)=
-.. _security-insecureAPI-mktemp:
+#### security.insecureAPI.mktemp (C)
-security.insecureAPI.mktemp (C)
-"""""""""""""""""""""""""""""""
-Warn on uses of the ``mktemp`` function.
+Warn on uses of the `mktemp` function.
-.. code-block:: c
+```c
+void test() {
+ char *x = mktemp("/tmp/zxcv"); // warn: insecure, use mkstemp
+}
+```
- void test() {
- char *x = mktemp("/tmp/zxcv"); // warn: insecure, use mkstemp
- }
+(security-insecureapi-rand)=
-.. _security-insecureAPI-rand:
+#### security.insecureAPI.rand (C)
-security.insecureAPI.rand (C)
-"""""""""""""""""""""""""""""
Warn on uses of inferior random number generating functions (only if arc4random function is available):
-``drand48, erand48, jrand48, lcong48, lrand48, mrand48, nrand48, random, rand_r``.
+`drand48, erand48, jrand48, lcong48, lrand48, mrand48, nrand48, random, rand_r`.
-.. code-block:: c
-
- void test() {
- random(); // warn
- }
-
-.. _security-insecureAPI-strcpy:
-
-security.insecureAPI.strcpy (C)
-"""""""""""""""""""""""""""""""
-Warn on uses of the ``strcpy`` and ``strcat`` functions.
-
-.. code-block:: c
+```c
+void test() {
+ random(); // warn
+}
+```
- void test() {
- char x[4];
- char *y = "abcd";
+(security-insecureapi-strcpy)=
- strcpy(x, y); // warn
- }
+#### security.insecureAPI.strcpy (C)
+Warn on uses of the `strcpy` and `strcat` functions.
-.. _security-insecureAPI-vfork:
+```c
+void test() {
+ char x[4];
+ char *y = "abcd";
-security.insecureAPI.vfork (C)
-""""""""""""""""""""""""""""""
- Warn on uses of the 'vfork' function.
+ strcpy(x, y); // warn
+}
+```
-.. code-block:: c
+(security-insecureapi-vfork)=
- void test() {
- vfork(); // warn
- }
+#### security.insecureAPI.vfork (C)
-.. _security-insecureAPI-DeprecatedOrUnsafeBufferHandling:
+> Warn on uses of the 'vfork' function.
-security.insecureAPI.DeprecatedOrUnsafeBufferHandling (C)
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
- Warn on occurrences of unsafe or deprecated buffer handling functions, which now have a secure variant: ``sprintf, fprintf, vsprintf, scanf, wscanf, fscanf, fwscanf, vscanf, vwscanf, vfscanf, vfwscanf, sscanf, swscanf, vsscanf, vswscanf, swprintf, snprintf, vswprintf, vsnprintf, memcpy, memmove, strncpy, strncat, memset``
+```c
+void test() {
+ vfork(); // warn
+}
+```
-.. code-block:: c
+(security-insecureapi-deprecatedorunsafebufferhandling)=
- void test() {
- char buf [5];
- strncpy(buf, "a", 1); // warn
- }
+#### security.insecureAPI.DeprecatedOrUnsafeBufferHandling (C)
-The ``ReportMode`` option controls when warnings are reported:
+> Warn on occurrences of unsafe or deprecated buffer handling functions, which now have a secure variant: `sprintf, fprintf, vsprintf, scanf, wscanf, fscanf, fwscanf, vscanf, vwscanf, vfscanf, vfwscanf, sscanf, swscanf, vsscanf, vswscanf, swprintf, snprintf, vswprintf, vsnprintf, memcpy, memmove, strncpy, strncat, memset`
-* ``all``: Reports all unsafe functions regardless of C standard or Annex K availability. Useful for security auditing and vulnerability scanning.
+```c
+void test() {
+ char buf [5];
+ strncpy(buf, "a", 1); // warn
+}
+```
-* ``actionable``: Only reports when Annex K is available (C11 with ``__STDC_LIB_EXT1__`` and ``__STDC_WANT_LIB_EXT1__=1``).
+The `ReportMode` option controls when warnings are reported:
-* ``c11-only``: Reports when C11 standard is enabled (does not take Annex K availability into account).
+- `all`: Reports all unsafe functions regardless of C standard or Annex K availability. Useful for security auditing and vulnerability scanning.
+- `actionable`: Only reports when Annex K is available (C11 with `__STDC_LIB_EXT1__` and `__STDC_WANT_LIB_EXT1__=1`).
+- `c11-only`: Reports when C11 standard is enabled (does not take Annex K availability into account).
To set this option, use:
-``-analyzer-config security.insecureAPI.DeprecatedOrUnsafeBufferHandling:ReportMode=all``
+`-analyzer-config security.insecureAPI.DeprecatedOrUnsafeBufferHandling:ReportMode=all`
By default, this option is set to *c11-only*.
-.. _security-MmapWriteExec:
+(security-mmapwriteexec)=
-security.MmapWriteExec (C)
-""""""""""""""""""""""""""
-Warn on ``mmap()`` calls with both writable and executable access.
+#### security.MmapWriteExec (C)
-.. code-block:: c
+Warn on `mmap()` calls with both writable and executable access.
- void test(int n) {
- void *c = mmap(NULL, 32, PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANON, -1, 0);
- // warn: Both PROT_WRITE and PROT_EXEC flags are set. This can lead to
- // exploitable memory regions, which could be overwritten with malicious
- // code
- }
+```c
+void test(int n) {
+ void *c = mmap(NULL, 32, PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ // warn: Both PROT_WRITE and PROT_EXEC flags are set. This can lead to
+ // exploitable memory regions, which could be overwritten with malicious
+ // code
+}
+```
+
+(security-pointersub)=
-.. _security-PointerSub:
+#### security.PointerSub (C)
-security.PointerSub (C)
-"""""""""""""""""""""""
Check for pointer subtractions on two pointers pointing to different memory
chunks. According to the C standard §6.5.6 only subtraction of pointers that
point into (or one past the end) the same array object is valid (for this
@@ -1942,60 +1900,59 @@ array index is correct. Furthermore, only cases are reported where
stack-allocated objects are involved (no warnings on pointers to memory
allocated by `malloc`).
-.. code-block:: c
-
- void test() {
- int a, b, c[10], d[10];
- int x = &c[3] - &c[1];
- x = &d[4] - &c[1]; // warn: 'c' and 'd' are different arrays
- x = (&a + 1) - &a;
- x = &b - &a; // warn: 'a' and 'b' are different variables
- }
+```c
+void test() {
+ int a, b, c[10], d[10];
+ int x = &c[3] - &c[1];
+ x = &d[4] - &c[1]; // warn: 'c' and 'd' are different arrays
+ x = (&a + 1) - &a;
+ x = &b - &a; // warn: 'a' and 'b' are different variables
+}
- struct S {
- int x[10];
- int y[10];
- };
-
- void test1() {
- struct S a[10];
- struct S b;
- int d = &a[4] - &a[6];
- d = &a[0].x[3] - &a[0].x[1];
- d = a[0].y - a[0].x; // warn: 'S.b' and 'S.a' are different objects
- d = (char *)&b.y - (char *)&b.x; // warn: different members of the same object
- d = (char *)&b.y - (char *)&b; // warn: object of type S is not the same array as a member of it
- }
+struct S {
+ int x[10];
+ int y[10];
+};
+
+void test1() {
+ struct S a[10];
+ struct S b;
+ int d = &a[4] - &a[6];
+ d = &a[0].x[3] - &a[0].x[1];
+ d = a[0].y - a[0].x; // warn: 'S.b' and 'S.a' are different objects
+ d = (char *)&b.y - (char *)&b.x; // warn: different members of the same object
+ d = (char *)&b.y - (char *)&b; // warn: object of type S is not the same array as a member of it
+}
+```
There may be existing applications that use code like above for calculating
offsets of members in a structure, using pointer subtractions. This is still
undefined behavior according to the standard and code like this can be replaced
with the `offsetof` macro.
-.. _security-putenv-stack-array:
+(security-putenv-stack-array)=
+
+#### security.PutenvStackArray (C)
-security.PutenvStackArray (C)
-"""""""""""""""""""""""""""""
-Finds calls to the ``putenv`` function which pass a pointer to a stack-allocated
-(automatic) array as the argument. Function ``putenv`` does not copy the passed
+Finds calls to the `putenv` function which pass a pointer to a stack-allocated
+(automatic) array as the argument. Function `putenv` does not copy the passed
string, only a pointer to the data is stored and this data can be read even by
other threads. Content of a stack-allocated array is likely to be overwritten
after exiting from the function.
The problem can be solved by using a static array variable or dynamically
-allocated memory. Even better is to avoid using ``putenv`` (it has other
-problems related to memory leaks) and use ``setenv`` instead.
+allocated memory. Even better is to avoid using `putenv` (it has other
+problems related to memory leaks) and use `setenv` instead.
The check corresponds to CERT rule
-`POS34-C. Do not call putenv() with a pointer to an automatic variable as the argument
-<https://wiki.sei.cmu.edu/confluence/display/c/POS34-C.+Do+not+call+putenv%28%29+with+a+pointer+to+an+automatic+variable+as+the+argument>`_.
+[POS34-C. Do not call putenv() with a pointer to an automatic variable as the argument](https://wiki.sei.cmu.edu/confluence/display/c/POS34-C.+Do+not+call+putenv%28%29+with+a+pointer+to+an+automatic+variable+as+the+argument).
-.. code-block:: c
-
- int f() {
- char env[] = "NAME=value";
- return putenv(env); // putenv function should not be called with stack-allocated string
- }
+```c
+int f() {
+ char env[] = "NAME=value";
+ return putenv(env); // putenv function should not be called with stack-allocated string
+}
+```
There is one case where the checker can report a false positive. This is when
the stack-allocated array is used at `putenv` in a function or code branch that
@@ -2007,420 +1964,420 @@ to use the stack-allocated string (a multi-threaded program may require more
attention). The checker does not warn for cases when stack space of `main` is
used at the `putenv` call.
-security.SetgidSetuidOrder (C)
-""""""""""""""""""""""""""""""
+#### security.SetgidSetuidOrder (C)
+
When dropping user-level and group-level privileges in a program by using
-``setuid`` and ``setgid`` calls, it is important to reset the group-level
-privileges (with ``setgid``) first. Function ``setgid`` will likely fail if
+`setuid` and `setgid` calls, it is important to reset the group-level
+privileges (with `setgid`) first. Function `setgid` will likely fail if
the superuser privileges are already dropped.
-The checker checks for sequences of ``setuid(getuid())`` and
-``setgid(getgid())`` calls (in this order). If such a sequence is found and
-there is no other privilege-changing function call (``seteuid``, ``setreuid``,
-``setresuid`` and the GID versions of these) in between, a warning is
-generated. The checker finds only exactly ``setuid(getuid())`` calls (and the
-GID versions), not for example if the result of ``getuid()`` is stored in a
+The checker checks for sequences of `setuid(getuid())` and
+`setgid(getgid())` calls (in this order). If such a sequence is found and
+there is no other privilege-changing function call (`seteuid`, `setreuid`,
+`setresuid` and the GID versions of these) in between, a warning is
+generated. The checker finds only exactly `setuid(getuid())` calls (and the
+GID versions), not for example if the result of `getuid()` is stored in a
variable.
-.. code-block:: c
-
- void test1() {
- // ...
- // end of section with elevated privileges
- // reset privileges (user and group) to normal user
- if (setuid(getuid()) != 0) {
- handle_error();
- return;
- }
- if (setgid(getgid()) != 0) { // warning: A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail
- handle_error();
- return;
- }
- // user-ID and group-ID are reset to normal user now
- // ...
- }
+```c
+void test1() {
+ // ...
+ // end of section with elevated privileges
+ // reset privileges (user and group) to normal user
+ if (setuid(getuid()) != 0) {
+ handle_error();
+ return;
+ }
+ if (setgid(getgid()) != 0) { // warning: A 'setgid(getgid())' call following a 'setuid(getuid())' call is likely to fail
+ handle_error();
+ return;
+ }
+ // user-ID and group-ID are reset to normal user now
+ // ...
+}
+```
-In the code above the problem is that ``setuid(getuid())`` removes superuser
-privileges before ``setgid(getgid())`` is called. To fix the problem the
-``setgid(getgid())`` should be called first. Further attention is needed to
-avoid code like ``setgid(getuid())`` (this checker does not detect bugs like
+In the code above the problem is that `setuid(getuid())` removes superuser
+privileges before `setgid(getgid())` is called. To fix the problem the
+`setgid(getgid())` should be called first. Further attention is needed to
+avoid code like `setgid(getuid())` (this checker does not detect bugs like
this) and always check the return value of these calls.
-This check corresponds to SEI CERT Rule `POS36-C <https://wiki.sei.cmu.edu/confluence/display/c/POS36-C.+Observe+correct+revocation+order+while+relinquishing+privileges>`_.
+This check corresponds to SEI CERT Rule [POS36-C](https://wiki.sei.cmu.edu/confluence/display/c/POS36-C.+Observe+correct+revocation+order+while+relinquishing+privileges).
-.. _security-VAList:
+(security-valist)=
-security.VAList (C, C++)
-""""""""""""""""""""""""
-Reports use of uninitialized (or already released) ``va_list`` objects and
-situations where a ``va_start`` call is not followed by ``va_end``.
+#### security.VAList (C, C++)
-.. code-block:: c
+Reports use of uninitialized (or already released) `va_list` objects and
+situations where a `va_start` call is not followed by `va_end`.
- int test_use_after_release(int x, ...) {
- va_list va;
- va_start(va, x);
- va_end(va);
- return va_arg(va, int); // warn: va is uninitialized
- }
+```c
+int test_use_after_release(int x, ...) {
+ va_list va;
+ va_start(va, x);
+ va_end(va);
+ return va_arg(va, int); // warn: va is uninitialized
+}
+
+void test_leak(int x, ...) {
+ va_list va;
+ va_start(va, x);
+} // warn: va is leaked
+```
- void test_leak(int x, ...) {
- va_list va;
- va_start(va, x);
- } // warn: va is leaked
+(unix-checkers)=
-.. _unix-checkers:
+### unix
-unix
-^^^^
POSIX/Unix checkers.
-.. _unix-generic-options:
+(unix-generic-options)=
-unix generic options
-""""""""""""""""""""
-These are common options that affect multiple checkers in the ``unix`` group.
+#### unix generic options
-* ``unix.DynamicMemoryModeling:Optimistic``
+These are common options that affect multiple checkers in the `unix` group.
- If set to ``true``, the static analyzer assumes that all memory allocations
- and deallocations (like ``malloc`` or ``free``) are marked with
- ``ownership_holds``, ``ownership_takes`` and ``ownership_returns``
+- `unix.DynamicMemoryModeling:Optimistic`
+
+ If set to `true`, the static analyzer assumes that all memory allocations
+ and deallocations (like `malloc` or `free`) are marked with
+ `ownership_holds`, `ownership_takes` and `ownership_returns`
attributes. For more information see
- `Attributes in Clang <../AttributeReference.html#ownership-holds-ownership-returns-ownership-takes-clang-static-analyzer>`_.
- Default value is ``false``.
+ [Attributes in Clang](../AttributeReference.html#ownership-holds-ownership-returns-ownership-takes-clang-static-analyzer).
+ Default value is `false`.
-* ``unix.DynamicMemoryModeling:ModelAllocationFailure``
+- `unix.DynamicMemoryModeling:ModelAllocationFailure`
- Setting this option to ``true`` enforces that the return value of memory
+ Setting this option to `true` enforces that the return value of memory
allocation functions is tested for null by the programmer (if applicable).
By default the analyzer does not know if a returned pointer is null or
non-null after an allocation and access of this pointer is not reported as
- null pointer access. If the option is set to ``true`` the analyzer adds a
+ null pointer access. If the option is set to `true` the analyzer adds a
specific execution branch where the return value is known to be null and a
possible null pointer access can be found by other checkers. Default value of
- the option is ``false``.
-
-.. _unix-API:
+ the option is `false`.
-unix.API (C)
-""""""""""""
-Check calls to various UNIX/Posix functions: ``open, pthread_once, calloc, malloc, realloc, alloca``.
+(unix-api)=
-.. literalinclude:: checkers/unix_api_example.c
- :language: c
+#### unix.API (C)
-.. _unix-BlockInCriticalSection:
+Check calls to various UNIX/Posix functions: `open, pthread_once, calloc, malloc, realloc, alloca`.
-unix.BlockInCriticalSection (C, C++)
-""""""""""""""""""""""""""""""""""""
-Check for calls to blocking functions inside a critical section.
-Blocking functions detected by this checker: ``sleep, getc, fgets, read, recv``.
-Critical section handling functions modeled by this checker:
-``lock, unlock, pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_unlock, mtx_lock, mtx_timedlock, mtx_trylock, mtx_unlock, lock_guard, unique_lock, scoped_lock``.
+```{literalinclude} checkers/unix_api_example.c
+:language: c
+```
-.. code-block:: c
+(unix-blockincriticalsection)=
- void pthread_lock_example(pthread_mutex_t *m) {
- pthread_mutex_lock(m); // note: entering critical section here
- sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
- pthread_mutex_unlock(m);
- }
+#### unix.BlockInCriticalSection (C, C++)
-.. code-block:: cpp
+Check for calls to blocking functions inside a critical section.
+Blocking functions detected by this checker: `sleep, getc, fgets, read, recv`.
+Critical section handling functions modeled by this checker:
+`lock, unlock, pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_unlock, mtx_lock, mtx_timedlock, mtx_trylock, mtx_unlock, lock_guard, unique_lock, scoped_lock`.
- void overlapping_critical_sections(mtx_t *m1, std::mutex &m2) {
- std::lock_guard lg{m2}; // note: entering critical section here
- mtx_lock(m1); // note: entering critical section here
- sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
- mtx_unlock(m1);
- sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
- // still inside of the critical section of the std::lock_guard
- }
+```c
+void pthread_lock_example(pthread_mutex_t *m) {
+ pthread_mutex_lock(m); // note: entering critical section here
+ sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
+ pthread_mutex_unlock(m);
+}
+```
+
+```cpp
+void overlapping_critical_sections(mtx_t *m1, std::mutex &m2) {
+ std::lock_guard lg{m2}; // note: entering critical section here
+ mtx_lock(m1); // note: entering critical section here
+ sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
+ mtx_unlock(m1);
+ sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
+ // still inside of the critical section of the std::lock_guard
+}
+```
**Limitations**
-* The ``trylock`` and ``timedlock`` versions of acquiring locks are currently assumed to always succeed.
+- The `trylock` and `timedlock` versions of acquiring locks are currently assumed to always succeed.
This can lead to false positives.
-.. code-block:: c
-
- void trylock_example(pthread_mutex_t *m) {
- if (pthread_mutex_trylock(m) == 0) { // assume trylock always succeeds
- sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
- pthread_mutex_unlock(m);
- } else {
- sleep(10); // false positive: Incorrect warning about blocking function inside critical section.
- }
- }
-
-.. _unix-Chroot:
+```c
+void trylock_example(pthread_mutex_t *m) {
+ if (pthread_mutex_trylock(m) == 0) { // assume trylock always succeeds
+ sleep(10); // warn: Call to blocking function 'sleep' inside of critical section
+ pthread_mutex_unlock(m);
+ } else {
+ sleep(10); // false positive: Incorrect warning about blocking function inside critical section.
+ }
+}
+```
-unix.Chroot (C)
-"""""""""""""""
-Check improper use of chroot described by SEI Cert C recommendation `POS05-C.
-Limit access to files by creating a jail
-<https://wiki.sei.cmu.edu/confluence/display/c/POS05-C.+Limit+access+to+files+by+creating+a+jail>`_.
-The checker finds usage patterns where ``chdir("/")`` is not called immediately
-after a call to ``chroot(path)``.
+(unix-chroot)=
-.. code-block:: c
+#### unix.Chroot (C)
- void f();
+Check improper use of chroot described by SEI Cert C recommendation [POS05-C.
+Limit access to files by creating a jail](https://wiki.sei.cmu.edu/confluence/display/c/POS05-C.+Limit+access+to+files+by+creating+a+jail).
+The checker finds usage patterns where `chdir("/")` is not called immediately
+after a call to `chroot(path)`.
- void test_bad() {
- chroot("/usr/local");
- f(); // warn: no call of chdir("/") immediately after chroot
- }
+```c
+void f();
- void test_bad_path() {
- chroot("/usr/local");
- chdir("/usr"); // warn: no call of chdir("/") immediately after chroot
- f();
- }
+void test_bad() {
+ chroot("/usr/local");
+ f(); // warn: no call of chdir("/") immediately after chroot
+}
- void test_good() {
+ void test_bad_path() {
chroot("/usr/local");
- chdir("/"); // no warning
+ chdir("/usr"); // warn: no call of chdir("/") immediately after chroot
f();
}
-.. _unix-Errno:
+void test_good() {
+ chroot("/usr/local");
+ chdir("/"); // no warning
+ f();
+}
+```
+
+(unix-errno)=
-unix.Errno (C)
-""""""""""""""
+#### unix.Errno (C)
-Check for improper use of ``errno``.
+Check for improper use of `errno`.
This checker implements partially CERT rule
-`ERR30-C. Set errno to zero before calling a library function known to set errno,
-and check errno only after the function returns a value indicating failure
-<https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152351>`_.
-The checker can find the first read of ``errno`` after successful standard
+[ERR30-C. Set errno to zero before calling a library function known to set errno,
+and check errno only after the function returns a value indicating failure](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152351).
+The checker can find the first read of `errno` after successful standard
function calls.
The C and POSIX standards often do not define if a standard library function
-may change value of ``errno`` if the call does not fail.
-Therefore, ``errno`` should only be used if it is known from the return value
+may change value of `errno` if the call does not fail.
+Therefore, `errno` should only be used if it is known from the return value
of a function that the call has failed.
-There are exceptions to this rule (for example ``strtol``) but the affected
+There are exceptions to this rule (for example `strtol`) but the affected
functions are not yet supported by the checker.
The return values for the failure cases are documented in the standard Linux man
-pages of the functions and in the `POSIX standard <https://pubs.opengroup.org/onlinepubs/9699919799/>`_.
-
-.. code-block:: c
-
- int unsafe_errno_read(int sock, void *data, int data_size) {
- if (send(sock, data, data_size, 0) != data_size) {
- // 'send' can be successful even if not all data was sent
- if (errno == 1) { // An undefined value may be read from 'errno'
- return 0;
- }
- }
- return 1;
- }
+pages of the functions and in the [POSIX standard](https://pubs.opengroup.org/onlinepubs/9699919799/).
-The checker :ref:`unix-StdCLibraryFunctions` must be turned on to get the
+```c
+int unsafe_errno_read(int sock, void *data, int data_size) {
+ if (send(sock, data, data_size, 0) != data_size) {
+ // 'send' can be successful even if not all data was sent
+ if (errno == 1) { // An undefined value may be read from 'errno'
+ return 0;
+ }
+ }
+ return 1;
+}
+```
+
+The checker {ref}`unix-StdCLibraryFunctions` must be turned on to get the
warnings from this checker. The supported functions are the same as by
-:ref:`unix-StdCLibraryFunctions`. The ``ModelPOSIX`` option of that
+{ref}`unix-StdCLibraryFunctions`. The `ModelPOSIX` option of that
checker affects the set of checked functions.
**Parameters**
-The ``AllowErrnoReadOutsideConditionExpressions`` option allows read of the
-errno value if the value is not used in a condition (in ``if`` statements,
-loops, conditional expressions, ``switch`` statements). For example ``errno``
+The `AllowErrnoReadOutsideConditionExpressions` option allows read of the
+errno value if the value is not used in a condition (in `if` statements,
+loops, conditional expressions, `switch` statements). For example `errno`
can be stored into a variable without getting a warning by the checker.
-.. code-block:: c
-
- int unsafe_errno_read(int sock, void *data, int data_size) {
- if (send(sock, data, data_size, 0) != data_size) {
- int err = errno;
- // warning if 'AllowErrnoReadOutsideConditionExpressions' is false
- // no warning if 'AllowErrnoReadOutsideConditionExpressions' is true
- }
- return 1;
- }
+```c
+int unsafe_errno_read(int sock, void *data, int data_size) {
+ if (send(sock, data, data_size, 0) != data_size) {
+ int err = errno;
+ // warning if 'AllowErrnoReadOutsideConditionExpressions' is false
+ // no warning if 'AllowErrnoReadOutsideConditionExpressions' is true
+ }
+ return 1;
+}
+```
-Default value of this option is ``true``. This allows save of the errno value
+Default value of this option is `true`. This allows save of the errno value
for possible later error handling.
**Limitations**
- - Only the very first usage of ``errno`` is checked after an affected function
- call. Value of ``errno`` is not followed when it is stored into a variable
- or returned from a function.
- - Documentation of function ``lseek`` is not clear about what happens if the
- function returns different value than the expected file position but not -1.
- To avoid possible false-positives ``errno`` is allowed to be used in this
- case.
+> - Only the very first usage of `errno` is checked after an affected function
+> call. Value of `errno` is not followed when it is stored into a variable
+> or returned from a function.
+> - Documentation of function `lseek` is not clear about what happens if the
+> function returns different value than the expected file position but not -1.
+> To avoid possible false-positives `errno` is allowed to be used in this
+> case.
-.. _unix-Malloc:
+(unix-malloc)=
+
+#### unix.Malloc (C)
-unix.Malloc (C)
-"""""""""""""""
Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free().
Custom allocation/deallocation functions can be defined using
-:ref:`ownership attributes<analyzer-ownership-attrs>`.
+{ref}`ownership attributes<analyzer-ownership-attrs>`.
-.. literalinclude:: checkers/unix_malloc_example.c
- :language: c
+```{literalinclude} checkers/unix_malloc_example.c
+:language: c
+```
-.. _unix-MallocSizeof:
+(unix-mallocsizeof)=
-unix.MallocSizeof (C)
-"""""""""""""""""""""
-Check for dubious ``malloc`` arguments involving ``sizeof``.
+#### unix.MallocSizeof (C)
-Custom allocation/deallocation functions can be defined using
-:ref:`ownership attributes<analyzer-ownership-attrs>`.
+Check for dubious `malloc` arguments involving `sizeof`.
-.. code-block:: c
+Custom allocation/deallocation functions can be defined using
+{ref}`ownership attributes<analyzer-ownership-attrs>`.
+
+```c
+void test() {
+ long *p = malloc(sizeof(short));
+ // warn: result is converted to 'long *', which is
+ // incompatible with operand type 'short'
+ free(p);
+}
+```
- void test() {
- long *p = malloc(sizeof(short));
- // warn: result is converted to 'long *', which is
- // incompatible with operand type 'short'
- free(p);
- }
+(unix-mismatcheddeallocator)=
-.. _unix-MismatchedDeallocator:
+#### unix.MismatchedDeallocator (C, C++)
-unix.MismatchedDeallocator (C, C++)
-"""""""""""""""""""""""""""""""""""
Check for mismatched deallocators.
Custom allocation/deallocation functions can be defined using
-:ref:`ownership attributes<analyzer-ownership-attrs>`.
-
-.. literalinclude:: checkers/mismatched_deallocator_example.cpp
- :language: c
-
-.. _unix-Vfork:
-
-unix.Vfork (C)
-""""""""""""""
-Check for proper usage of ``vfork``.
-
-.. code-block:: c
-
- int test(int x) {
- pid_t pid = vfork(); // warn
- if (pid != 0)
- return 0;
-
- switch (x) {
- case 0:
- pid = 1;
- execl("", "", 0);
- _exit(1);
- break;
- case 1:
- x = 0; // warn: this assignment is prohibited
- break;
- case 2:
- foo(); // warn: this function call is prohibited
- break;
- default:
- return 0; // warn: return is prohibited
- }
-
- while(1);
- }
+{ref}`ownership attributes<analyzer-ownership-attrs>`.
-.. _unix-cstring-BadSizeArg:
+```{literalinclude} checkers/mismatched_deallocator_example.cpp
+:language: c
+```
-unix.cstring.BadSizeArg (C)
-"""""""""""""""""""""""""""
-Check the size argument passed into C string functions for common erroneous patterns. Use ``-Wno-strncat-size`` compiler option to mute other ``strncat``-related compiler warnings.
+(unix-vfork)=
-.. code-block:: c
+#### unix.Vfork (C)
- void test() {
- char dest[3];
- strncat(dest, """""""""""""""""""""""""*", sizeof(dest));
- // warn: potential buffer overflow
- }
+Check for proper usage of `vfork`.
+
+```c
+int test(int x) {
+ pid_t pid = vfork(); // warn
+ if (pid != 0)
+ return 0;
+
+ switch (x) {
+ case 0:
+ pid = 1;
+ execl("", "", 0);
+ _exit(1);
+ break;
+ case 1:
+ x = 0; // warn: this assignment is prohibited
+ break;
+ case 2:
+ foo(); // warn: this function call is prohibited
+ break;
+ default:
+ return 0; // warn: return is prohibited
+ }
+
+ while(1);
+}
+```
+
+(unix-cstring-badsizearg)=
+
+#### unix.cstring.BadSizeArg (C)
+
+Check the size argument passed into C string functions for common erroneous patterns. Use `-Wno-strncat-size` compiler option to mute other `strncat`-related compiler warnings.
-.. _unix-cstring-NotNullTerminated:
+```c
+void test() {
+ char dest[3];
+ strncat(dest, """""""""""""""""""""""""*", sizeof(dest));
+ // warn: potential buffer overflow
+}
+```
+
+(unix-cstring-notnullterminated)=
+
+#### unix.cstring.NotNullTerminated (C)
-unix.cstring.NotNullTerminated (C)
-""""""""""""""""""""""""""""""""""
Check for arguments which are not null-terminated strings;
-applies to the ``strlen``, ``strcpy``, ``strcat``, ``strcmp`` family of functions.
+applies to the `strlen`, `strcpy`, `strcat`, `strcmp` family of functions.
Only very fundamental cases are detected where the passed memory block is
absolutely different from a null-terminated string. This checker does not
find if a memory buffer is passed where the terminating zero character
is missing.
-.. code-block:: c
+```c
+void test1() {
+ int l = strlen((char *)&test1); // warn
+}
- void test1() {
- int l = strlen((char *)&test1); // warn
- }
+void test2() {
+label:
+ int l = strlen((char *)&&label); // warn
+}
+```
- void test2() {
- label:
- int l = strlen((char *)&&label); // warn
- }
+(unix-cstring-nullarg)=
-.. _unix-cstring-NullArg:
+#### unix.cstring.NullArg (C)
-unix.cstring.NullArg (C)
-""""""""""""""""""""""""
Check for null pointers being passed as arguments to C string functions:
-``strlen, strnlen, strcpy, strncpy, strcat, strncat, strcmp, strncmp, strcasecmp, strncasecmp, wcslen, wcsnlen``.
+`strlen, strnlen, strcpy, strncpy, strcat, strncat, strcmp, strncmp, strcasecmp, strncasecmp, wcslen, wcsnlen`.
-.. code-block:: c
+```c
+int test() {
+ return strlen(0); // warn
+}
+```
- int test() {
- return strlen(0); // warn
- }
+(unix-cstring-uninitializedread)=
-.. _unix-cstring-UninitializedRead:
+#### unix.cstring.UninitializedRead (C)
-unix.cstring.UninitializedRead (C)
-""""""""""""""""""""""""""""""""""
Check for uninitialized reads from common memory copy/manipulation functions such as:
- ``memcpy, mempcpy, memmove, memcmp, strcmp, strncmp, strcpy, strlen, strsep`` and many more.
-.. code-block:: c
+: `memcpy, mempcpy, memmove, memcmp, strcmp, strncmp, strcpy, strlen, strsep` and many more.
- void test() {
- char src[10];
- char dst[5];
- memcpy(dst,src,sizeof(dst)); // warn: Bytes string function accesses uninitialized/garbage values
- }
+```c
+void test() {
+ char src[10];
+ char dst[5];
+ memcpy(dst,src,sizeof(dst)); // warn: Bytes string function accesses uninitialized/garbage values
+}
+```
Limitations:
- - Due to limitations of the memory modeling in the analyzer, one can likely
- observe some false-positives of the following kind:
+> - Due to limitations of the memory modeling in the analyzer, one can likely
+> observe some false-positives of the following kind:
+>
+> > ```c
+> > void false_positive() {
+> > int src[] = {1, 2, 3, 4};
+> > int dst[5] = {0};
+> > memcpy(dst, src, 4 * sizeof(int)); // false-positive:
+> > // The 'src' buffer was correctly initialized, yet we cannot conclude
+> > // that since the analyzer could not see a direct initialization of the
+> > // very last byte of the source buffer.
+> > }
+> > ```
+>
+> More details at the corresponding [GitHub issue](https://github.com/llvm/llvm-project/issues/43459).
+
+(unix-stdclibraryfunctions)=
+
+#### unix.StdCLibraryFunctions (C)
- .. code-block:: c
-
- void false_positive() {
- int src[] = {1, 2, 3, 4};
- int dst[5] = {0};
- memcpy(dst, src, 4 * sizeof(int)); // false-positive:
- // The 'src' buffer was correctly initialized, yet we cannot conclude
- // that since the analyzer could not see a direct initialization of the
- // very last byte of the source buffer.
- }
-
- More details at the corresponding `GitHub issue <https://github.com/llvm/llvm-project/issues/43459>`_.
-
-
-.. _unix-StdCLibraryFunctions:
-
-unix.StdCLibraryFunctions (C)
-"""""""""""""""""""""""""""""
Check for calls of standard library functions that violate predefined argument
constraints. For example, according to the C standard the behavior of function
-``int isalnum(int ch)`` is undefined if the value of ``ch`` is not representable
-as ``unsigned char`` and is not equal to ``EOF``.
+`int isalnum(int ch)` is undefined if the value of `ch` is not representable
+as `unsigned char` and is not equal to `EOF`.
You can think of this checker as defining restrictions (pre- and postconditions)
on standard library functions. Preconditions are checked, and when they are
@@ -2435,57 +2392,57 @@ interval. Similarly, if a function mustn't be called with a null pointer and the
analyzer cannot prove that it is null, then it will assume that it is non-null.
These are the possible checks on the values passed as function arguments:
- - The argument has an allowed range (or multiple ranges) of values. The checker
- can detect if a passed value is outside of the allowed range and show the
- actual and allowed values.
- - The argument has pointer type and is not allowed to be null pointer. Many
- (but not all) standard functions can produce undefined behavior if a null
- pointer is passed, these cases can be detected by the checker.
- - The argument is a pointer to a memory block and the minimal size of this
- buffer is determined by another argument to the function, or by
- multiplication of two arguments (like at function ``fread``), or is a fixed
- value (for example ``asctime_r`` requires at least a buffer of size 26). The
- checker can detect if the buffer size is too small and in optimal case show
- the size of the buffer and the values of the corresponding arguments.
-
-.. code-block:: c
-
- #define EOF -1
- void test_alnum_concrete(int v) {
- int ret = isalnum(256); // \
- // warning: Function argument outside of allowed range
- (void)ret;
- }
+: - The argument has an allowed range (or multiple ranges) of values. The checker
+ can detect if a passed value is outside of the allowed range and show the
+ actual and allowed values.
+ - The argument has pointer type and is not allowed to be null pointer. Many
+ (but not all) standard functions can produce undefined behavior if a null
+ pointer is passed, these cases can be detected by the checker.
+ - The argument is a pointer to a memory block and the minimal size of this
+ buffer is determined by another argument to the function, or by
+ multiplication of two arguments (like at function `fread`), or is a fixed
+ value (for example `asctime_r` requires at least a buffer of size 26). The
+ checker can detect if the buffer size is too small and in optimal case show
+ the size of the buffer and the values of the corresponding arguments.
+
+```c
+#define EOF -1
+void test_alnum_concrete(int v) {
+ int ret = isalnum(256); // \
+ // warning: Function argument outside of allowed range
+ (void)ret;
+}
- void buffer_size_violation(FILE *file) {
- enum { BUFFER_SIZE = 1024 };
- wchar_t wbuf[BUFFER_SIZE];
+void buffer_size_violation(FILE *file) {
+ enum { BUFFER_SIZE = 1024 };
+ wchar_t wbuf[BUFFER_SIZE];
- const size_t size = sizeof(*wbuf); // 4
- const size_t nitems = sizeof(wbuf); // 4096
+ const size_t size = sizeof(*wbuf); // 4
+ const size_t nitems = sizeof(wbuf); // 4096
- // Below we receive a warning because the 3rd parameter should be the
- // number of elements to read, not the size in bytes. This case is a known
- // vulnerability described by the ARR38-C SEI-CERT rule.
- fread(wbuf, size, nitems, file);
- }
+ // Below we receive a warning because the 3rd parameter should be the
+ // number of elements to read, not the size in bytes. This case is a known
+ // vulnerability described by the ARR38-C SEI-CERT rule.
+ fread(wbuf, size, nitems, file);
+}
- int test_alnum_symbolic(int x) {
- int ret = isalnum(x);
- // after the call, ret is assumed to be in the range [-1, 255]
+int test_alnum_symbolic(int x) {
+ int ret = isalnum(x);
+ // after the call, ret is assumed to be in the range [-1, 255]
- if (ret > 255) // impossible (infeasible branch)
- if (x == 0)
- return ret / x; // division by zero is not reported
- return ret;
- }
+ if (ret > 255) // impossible (infeasible branch)
+ if (x == 0)
+ return ret / x; // division by zero is not reported
+ return ret;
+}
+```
Additionally to the argument and return value conditions, this checker also adds
-state of the value ``errno`` if applicable to the analysis. Many system
-functions set the ``errno`` value only if an error occurs (together with a
+state of the value `errno` if applicable to the analysis. Many system
+functions set the `errno` value only if an error occurs (together with a
specific return value of the function), otherwise it becomes undefined. This
checker changes the analysis state to contain such information. This data is
-used by other checkers, for example :ref:`unix-Errno`.
+used by other checkers, for example {ref}`unix-Errno`.
**Limitations**
@@ -2501,575 +2458,571 @@ range of the argument.
**Parameters**
-The ``ModelPOSIX`` option controls if functions from the POSIX standard are
+The `ModelPOSIX` option controls if functions from the POSIX standard are
recognized by the checker.
-With ``ModelPOSIX=true``, many POSIX functions are modeled according to the
-`POSIX standard`_. This includes ranges of parameters and possible return
-values. Furthermore the behavior related to ``errno`` in the POSIX case is
-often that ``errno`` is set only if a function call fails, and it becomes
+With `ModelPOSIX=true`, many POSIX functions are modeled according to the
+[POSIX standard]. This includes ranges of parameters and possible return
+values. Furthermore the behavior related to `errno` in the POSIX case is
+often that `errno` is set only if a function call fails, and it becomes
undefined after a successful function call.
-With ``ModelPOSIX=false``, this checker follows the C99 language standard and
+With `ModelPOSIX=false`, this checker follows the C99 language standard and
only models the functions that are described there. It is possible that the
same functions are modeled differently in the two cases because differences in
the standards. The C standard specifies less aspects of the functions, for
-example exact ``errno`` behavior is often unspecified (and not modeled by the
+example exact `errno` behavior is often unspecified (and not modeled by the
checker).
-Default value of the option is ``true``.
+Default value of the option is `true`.
+
+(unix-stream)=
-.. _unix-Stream:
+#### unix.Stream (C)
-unix.Stream (C)
-"""""""""""""""
Check C stream handling functions:
-``fopen, fdopen, freopen, tmpfile, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, fprintf, fscanf, ungetc, getdelim, getline, fseek, fseeko, ftell, ftello, fflush, rewind, fgetpos, fsetpos, clearerr, feof, ferror, fileno``.
+`fopen, fdopen, freopen, tmpfile, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, fprintf, fscanf, ungetc, getdelim, getline, fseek, fseeko, ftell, ftello, fflush, rewind, fgetpos, fsetpos, clearerr, feof, ferror, fileno`.
-The checker maintains information about the C stream objects (``FILE *``) and
+The checker maintains information about the C stream objects (`FILE *`) and
can detect error conditions related to use of streams. The following conditions
are detected:
-* The ``FILE *`` pointer passed to the function is NULL (the single exception is
- ``fflush`` where NULL is allowed).
-* Use of stream after close.
-* Opened stream is not closed.
-* Read from a stream after end-of-file. (This is not a fatal error but reported
+- The `FILE *` pointer passed to the function is NULL (the single exception is
+ `fflush` where NULL is allowed).
+- Use of stream after close.
+- Opened stream is not closed.
+- Read from a stream after end-of-file. (This is not a fatal error but reported
by the checker. Stream remains in EOF state and the read operation fails.)
-* Use of stream when the file position is indeterminate after a previous failed
- operation. Some functions (like ``ferror``, ``clearerr``, ``fseek``) are
+- Use of stream when the file position is indeterminate after a previous failed
+ operation. Some functions (like `ferror`, `clearerr`, `fseek`) are
allowed in this state.
-* Invalid 3rd ("``whence``") argument to ``fseek``.
+- Invalid 3rd ("`whence`") argument to `fseek`.
The stream operations are by this checker usually split into two cases, a success
and a failure case.
-On the success case it also assumes that the current value of ``stdout``,
-``stderr``, or ``stdin`` can't be equal to the file pointer returned by ``fopen``.
-Operations performed on ``stdout``, ``stderr``, or ``stdin`` are not checked by
-this checker in contrast to the streams opened by ``fopen``.
+On the success case it also assumes that the current value of `stdout`,
+`stderr`, or `stdin` can't be equal to the file pointer returned by `fopen`.
+Operations performed on `stdout`, `stderr`, or `stdin` are not checked by
+this checker in contrast to the streams opened by `fopen`.
-In the case of write operations (like ``fwrite``,
-``fprintf`` and even ``fsetpos``) this behavior could produce a large amount of
+In the case of write operations (like `fwrite`,
+`fprintf` and even `fsetpos`) this behavior could produce a large amount of
unwanted reports on projects that don't have error checks around the write
operations, so by default the checker assumes that write operations always succeed.
-This behavior can be controlled by the ``Pedantic`` flag: With
-``-analyzer-config unix.Stream:Pedantic=true`` the checker will model the
+This behavior can be controlled by the `Pedantic` flag: With
+`-analyzer-config unix.Stream:Pedantic=true` the checker will model the
cases where a write operation fails and report situations where this leads to
-erroneous behavior. (The default is ``Pedantic=false``, where write operations
+erroneous behavior. (The default is `Pedantic=false`, where write operations
are assumed to succeed.)
-.. code-block:: c
+```c
+void test1() {
+ FILE *p = fopen("foo", "r");
+} // warn: opened file is never closed
- void test1() {
- FILE *p = fopen("foo", "r");
- } // warn: opened file is never closed
-
- void test2() {
- FILE *p = fopen("foo", "r");
- fseek(p, 1, SEEK_SET); // warn: stream pointer might be NULL
- fclose(p);
- }
+void test2() {
+ FILE *p = fopen("foo", "r");
+ fseek(p, 1, SEEK_SET); // warn: stream pointer might be NULL
+ fclose(p);
+}
- void test3() {
- FILE *p = fopen("foo", "r");
- if (p) {
- fseek(p, 1, 3); // warn: third arg should be SEEK_SET, SEEK_END, or SEEK_CUR
- fclose(p);
- }
- }
+void test3() {
+ FILE *p = fopen("foo", "r");
+ if (p) {
+ fseek(p, 1, 3); // warn: third arg should be SEEK_SET, SEEK_END, or SEEK_CUR
+ fclose(p);
+ }
+}
- void test4() {
- FILE *p = fopen("foo", "r");
- if (!p)
- return;
+void test4() {
+ FILE *p = fopen("foo", "r");
+ if (!p)
+ return;
- fclose(p);
- fclose(p); // warn: stream already closed
- }
+ fclose(p);
+ fclose(p); // warn: stream already closed
+}
- void test5() {
- FILE *p = fopen("foo", "r");
- if (!p)
- return;
+void test5() {
+ FILE *p = fopen("foo", "r");
+ if (!p)
+ return;
- fgetc(p);
- if (!ferror(p))
- fgetc(p); // warn: possible read after end-of-file
+ fgetc(p);
+ if (!ferror(p))
+ fgetc(p); // warn: possible read after end-of-file
- fclose(p);
- }
+ fclose(p);
+}
- void test6() {
- FILE *p = fopen("foo", "r");
- if (!p)
- return;
+void test6() {
+ FILE *p = fopen("foo", "r");
+ if (!p)
+ return;
- fgetc(p);
- if (!feof(p))
- fgetc(p); // warn: file position may be indeterminate after I/O error
+ fgetc(p);
+ if (!feof(p))
+ fgetc(p); // warn: file position may be indeterminate after I/O error
- fclose(p);
- }
+ fclose(p);
+}
+```
**Limitations**
The checker does not track the correspondence between integer file descriptors
-and ``FILE *`` pointers.
+and `FILE *` pointers.
+
+(osx-checkers)=
-.. _osx-checkers:
+### osx
-osx
-^^^
macOS checkers.
-.. _osx-API:
+(osx-api)=
+
+#### osx.API (C)
-osx.API (C)
-"""""""""""
Check for proper uses of various Apple APIs.
-.. code-block:: objc
+```objc
+void test() {
+ dispatch_once_t pred = 0;
+ dispatch_once(&pred, ^(){}); // warn: dispatch_once uses local
+}
+```
- void test() {
- dispatch_once_t pred = 0;
- dispatch_once(&pred, ^(){}); // warn: dispatch_once uses local
- }
+(osx-numberobjectconversion)=
-.. _osx-NumberObjectConversion:
+#### osx.NumberObjectConversion (C, C++, ObjC)
-osx.NumberObjectConversion (C, C++, ObjC)
-"""""""""""""""""""""""""""""""""""""""""
Check for erroneous conversions of objects representing numbers into numbers.
-.. code-block:: objc
+```objc
+NSNumber *photoCount = [albumDescriptor objectForKey:@"PhotoCount"];
+// Warning: Comparing a pointer value of type 'NSNumber *'
+// to a scalar integer value
+if (photoCount > 0) {
+ [self displayPhotos];
+}
+```
- NSNumber *photoCount = [albumDescriptor objectForKey:@"PhotoCount"];
- // Warning: Comparing a pointer value of type 'NSNumber *'
- // to a scalar integer value
- if (photoCount > 0) {
- [self displayPhotos];
- }
+(osx-objcproperty)=
-.. _osx-ObjCProperty:
+#### osx.ObjCProperty (ObjC)
-osx.ObjCProperty (ObjC)
-"""""""""""""""""""""""
Check for proper uses of Objective-C properties.
-.. code-block:: objc
-
- NSNumber *photoCount = [albumDescriptor objectForKey:@"PhotoCount"];
- // Warning: Comparing a pointer value of type 'NSNumber *'
- // to a scalar integer value
- if (photoCount > 0) {
- [self displayPhotos];
- }
+```objc
+NSNumber *photoCount = [albumDescriptor objectForKey:@"PhotoCount"];
+// Warning: Comparing a pointer value of type 'NSNumber *'
+// to a scalar integer value
+if (photoCount > 0) {
+ [self displayPhotos];
+}
+```
+(osx-seckeychainapi)=
-.. _osx-SecKeychainAPI:
+#### osx.SecKeychainAPI (C)
-osx.SecKeychainAPI (C)
-""""""""""""""""""""""
Check for proper uses of Secure Keychain APIs.
-.. literalinclude:: checkers/seckeychainapi_example.m
- :language: objc
+```{literalinclude} checkers/seckeychainapi_example.m
+:language: objc
+```
+
+(osx-cocoa-atsync)=
-.. _osx-cocoa-AtSync:
+#### osx.cocoa.AtSync (ObjC)
-osx.cocoa.AtSync (ObjC)
-"""""""""""""""""""""""
Check for nil pointers used as mutexes for @synchronized.
-.. code-block:: objc
+```objc
+void test(id x) {
+ if (!x)
+ @synchronized(x) {} // warn: nil value used as mutex
+}
- void test(id x) {
- if (!x)
- @synchronized(x) {} // warn: nil value used as mutex
- }
+void test() {
+ id y;
+ @synchronized(y) {} // warn: uninitialized value used as mutex
+}
+```
- void test() {
- id y;
- @synchronized(y) {} // warn: uninitialized value used as mutex
- }
+(osx-cocoa-autoreleasewrite)=
-.. _osx-cocoa-AutoreleaseWrite:
+#### osx.cocoa.AutoreleaseWrite
-osx.cocoa.AutoreleaseWrite
-""""""""""""""""""""""""""
Warn about potentially crashing writes to autoreleasing objects from different autoreleasing pools in Objective-C.
-.. _osx-cocoa-ClassRelease:
+(osx-cocoa-classrelease)=
+
+#### osx.cocoa.ClassRelease (ObjC)
-osx.cocoa.ClassRelease (ObjC)
-"""""""""""""""""""""""""""""
Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
-.. code-block:: objc
+```objc
+ at interface MyClass : NSObject
+ at end
- @interface MyClass : NSObject
- @end
+void test(void) {
+ [MyClass release]; // warn
+}
+```
- void test(void) {
- [MyClass release]; // warn
- }
+(osx-cocoa-dealloc)=
-.. _osx-cocoa-Dealloc:
+#### osx.cocoa.Dealloc (ObjC)
-osx.cocoa.Dealloc (ObjC)
-""""""""""""""""""""""""
Warn about Objective-C classes that lack a correct implementation of -dealloc
-.. literalinclude:: checkers/dealloc_example.m
- :language: objc
+```{literalinclude} checkers/dealloc_example.m
+:language: objc
+```
+
+(osx-cocoa-incompatiblemethodtypes)=
-.. _osx-cocoa-IncompatibleMethodTypes:
+#### osx.cocoa.IncompatibleMethodTypes (ObjC)
-osx.cocoa.IncompatibleMethodTypes (ObjC)
-""""""""""""""""""""""""""""""""""""""""
Warn about Objective-C method signatures with type incompatibilities.
-.. code-block:: objc
+```objc
+ at interface MyClass1 : NSObject
+- (int)foo;
+ at end
- @interface MyClass1 : NSObject
- - (int)foo;
- @end
+ at implementation MyClass1
+- (int)foo { return 1; }
+ at end
- @implementation MyClass1
- - (int)foo { return 1; }
- @end
+ at interface MyClass2 : MyClass1
+- (float)foo;
+ at end
- @interface MyClass2 : MyClass1
- - (float)foo;
- @end
+ at implementation MyClass2
+- (float)foo { return 1.0; } // warn
+ at end
+```
- @implementation MyClass2
- - (float)foo { return 1.0; } // warn
- @end
+(osx-cocoa-loops)=
-.. _osx-cocoa-Loops:
+#### osx.cocoa.Loops
-osx.cocoa.Loops
-"""""""""""""""
Improved modeling of loops using Cocoa collection types.
-.. _osx-cocoa-MissingSuperCall:
+(osx-cocoa-missingsupercall)=
-osx.cocoa.MissingSuperCall (ObjC)
-"""""""""""""""""""""""""""""""""
-Warn about Objective-C methods that lack a necessary call to super.
+#### osx.cocoa.MissingSuperCall (ObjC)
-.. code-block:: objc
+Warn about Objective-C methods that lack a necessary call to super.
- @interface Test : UIViewController
- @end
- @implementation test
- - (void)viewDidLoad {} // warn
- @end
+```objc
+ at interface Test : UIViewController
+ at end
+ at implementation test
+- (void)viewDidLoad {} // warn
+ at end
+```
+(osx-cocoa-nsautoreleasepool)=
-.. _osx-cocoa-NSAutoreleasePool:
+#### osx.cocoa.NSAutoreleasePool (ObjC)
-osx.cocoa.NSAutoreleasePool (ObjC)
-""""""""""""""""""""""""""""""""""
Warn for suboptimal uses of NSAutoreleasePool in Objective-C GC mode.
-.. code-block:: objc
+```objc
+void test() {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [pool release]; // warn
+}
+```
- void test() {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- [pool release]; // warn
- }
+(osx-cocoa-nserror)=
-.. _osx-cocoa-NSError:
+#### osx.cocoa.NSError (ObjC)
-osx.cocoa.NSError (ObjC)
-""""""""""""""""""""""""
Check usage of NSError parameters.
-.. code-block:: objc
+```objc
+ at interface A : NSObject
+- (void)foo:(NSError """""""""""""""""""""""")error;
+ at end
- @interface A : NSObject
- - (void)foo:(NSError """""""""""""""""""""""")error;
- @end
+ at implementation A
+- (void)foo:(NSError """""""""""""""""""""""")error {
+ // warn: method accepting NSError"""""""""""""""""""""""" should have a non-void
+ // return value
+}
+ at end
- @implementation A
- - (void)foo:(NSError """""""""""""""""""""""")error {
- // warn: method accepting NSError"""""""""""""""""""""""" should have a non-void
- // return value
- }
- @end
+ at interface A : NSObject
+- (BOOL)foo:(NSError """""""""""""""""""""""")error;
+ at end
- @interface A : NSObject
- - (BOOL)foo:(NSError """""""""""""""""""""""")error;
- @end
+ at implementation A
+- (BOOL)foo:(NSError """""""""""""""""""""""")error {
+ *error = 0; // warn: potential null dereference
+ return 0;
+}
+ at end
+```
- @implementation A
- - (BOOL)foo:(NSError """""""""""""""""""""""")error {
- *error = 0; // warn: potential null dereference
- return 0;
- }
- @end
+(osx-cocoa-nilarg)=
-.. _osx-cocoa-NilArg:
+#### osx.cocoa.NilArg (ObjC)
-osx.cocoa.NilArg (ObjC)
-"""""""""""""""""""""""
Check for prohibited nil arguments to ObjC method calls.
- - caseInsensitiveCompare:
- - compare:
- - compare:options:
- - compare:options:range:
- - compare:options:range:locale:
- - componentsSeparatedByCharactersInSet:
- - initWithFormat:
-
-.. code-block:: objc
-
- NSComparisonResult test(NSString *s) {
- NSString *aString = nil;
- return [s caseInsensitiveCompare:aString];
- // warn: argument to 'NSString' method
- // 'caseInsensitiveCompare:' cannot be nil
- }
+> - caseInsensitiveCompare:
+> - compare:
+> - compare:options:
+> - compare:options:range:
+> - compare:options:range:locale:
+> - componentsSeparatedByCharactersInSet:
+> - initWithFormat:
+
+```objc
+NSComparisonResult test(NSString *s) {
+ NSString *aString = nil;
+ return [s caseInsensitiveCompare:aString];
+ // warn: argument to 'NSString' method
+ // 'caseInsensitiveCompare:' cannot be nil
+}
+```
+(osx-cocoa-nonnilreturnvalue)=
-.. _osx-cocoa-NonNilReturnValue:
+#### osx.cocoa.NonNilReturnValue
-osx.cocoa.NonNilReturnValue
-"""""""""""""""""""""""""""
Models the APIs that are guaranteed to return a non-nil value.
-.. _osx-cocoa-ObjCGenerics:
+(osx-cocoa-objcgenerics)=
+
+#### osx.cocoa.ObjCGenerics (ObjC)
-osx.cocoa.ObjCGenerics (ObjC)
-"""""""""""""""""""""""""""""
Check for type errors when using Objective-C generics.
-.. code-block:: objc
+```objc
+NSMutableArray *names = [NSMutableArray array];
+NSMutableArray *birthDates = names;
- NSMutableArray *names = [NSMutableArray array];
- NSMutableArray *birthDates = names;
+// Warning: Conversion from value of type 'NSDate *'
+// to incompatible type 'NSString *'
+[birthDates addObject: [NSDate date]];
+```
- // Warning: Conversion from value of type 'NSDate *'
- // to incompatible type 'NSString *'
- [birthDates addObject: [NSDate date]];
+(osx-cocoa-retaincount)=
-.. _osx-cocoa-RetainCount:
+#### osx.cocoa.RetainCount (ObjC)
-osx.cocoa.RetainCount (ObjC)
-""""""""""""""""""""""""""""
Check for leaks and improper reference count management
-.. code-block:: objc
-
- void test() {
- NSString *s = [[NSString alloc] init]; // warn
- }
+```objc
+void test() {
+ NSString *s = [[NSString alloc] init]; // warn
+}
- CFStringRef test(char *bytes) {
- return CFStringCreateWithCStringNoCopy(
- 0, bytes, NSNEXTSTEPStringEncoding, 0); // warn
- }
+CFStringRef test(char *bytes) {
+ return CFStringCreateWithCStringNoCopy(
+ 0, bytes, NSNEXTSTEPStringEncoding, 0); // warn
+}
+```
+(osx-cocoa-runloopautoreleaseleak)=
-.. _osx-cocoa-RunLoopAutoreleaseLeak:
+#### osx.cocoa.RunLoopAutoreleaseLeak
-osx.cocoa.RunLoopAutoreleaseLeak
-""""""""""""""""""""""""""""""""
Check for leaked memory in autorelease pools that will never be drained.
-.. _osx-cocoa-SelfInit:
+(osx-cocoa-selfinit)=
+
+#### osx.cocoa.SelfInit (ObjC)
-osx.cocoa.SelfInit (ObjC)
-"""""""""""""""""""""""""
Check that 'self' is properly initialized inside an initializer method.
-.. code-block:: objc
+```objc
+ at interface MyObj : NSObject {
+ id x;
+}
+- (id)init;
+ at end
+
+ at implementation MyObj
+- (id)init {
+ [super init];
+ x = 0; // warn: instance variable used while 'self' is not
+ // initialized
+ return 0;
+}
+ at end
- @interface MyObj : NSObject {
- id x;
- }
- - (id)init;
- @end
-
- @implementation MyObj
- - (id)init {
- [super init];
- x = 0; // warn: instance variable used while 'self' is not
- // initialized
- return 0;
- }
- @end
+ at interface MyObj : NSObject
+- (id)init;
+ at end
- @interface MyObj : NSObject
- - (id)init;
- @end
+ at implementation MyObj
+- (id)init {
+ [super init];
+ return self; // warn: returning uninitialized 'self'
+}
+ at end
+```
- @implementation MyObj
- - (id)init {
- [super init];
- return self; // warn: returning uninitialized 'self'
- }
- @end
+(osx-cocoa-superdealloc)=
-.. _osx-cocoa-SuperDealloc:
+#### osx.cocoa.SuperDealloc (ObjC)
-osx.cocoa.SuperDealloc (ObjC)
-"""""""""""""""""""""""""""""
Warn about improper use of '[super dealloc]' in Objective-C.
-.. code-block:: objc
+```objc
+ at interface SuperDeallocThenReleaseIvarClass : NSObject {
+ NSObject *_ivar;
+}
+ at end
- @interface SuperDeallocThenReleaseIvarClass : NSObject {
- NSObject *_ivar;
- }
- @end
+ at implementation SuperDeallocThenReleaseIvarClass
+- (void)dealloc {
+ [super dealloc];
+ [_ivar release]; // warn
+}
+ at end
+```
- @implementation SuperDeallocThenReleaseIvarClass
- - (void)dealloc {
- [super dealloc];
- [_ivar release]; // warn
- }
- @end
+(osx-cocoa-unusedivars)=
-.. _osx-cocoa-UnusedIvars:
+#### osx.cocoa.UnusedIvars (ObjC)
-osx.cocoa.UnusedIvars (ObjC)
-""""""""""""""""""""""""""""
Warn about private ivars that are never used.
-.. code-block:: objc
+```objc
+ at interface MyObj : NSObject {
+ at private
+ id x; // warn
+}
+ at end
- @interface MyObj : NSObject {
- @private
- id x; // warn
- }
- @end
+ at implementation MyObj
+ at end
+```
- @implementation MyObj
- @end
+(osx-cocoa-variadicmethodtypes)=
-.. _osx-cocoa-VariadicMethodTypes:
+#### osx.cocoa.VariadicMethodTypes (ObjC)
-osx.cocoa.VariadicMethodTypes (ObjC)
-""""""""""""""""""""""""""""""""""""
Check for passing non-Objective-C types to variadic collection
initialization methods that expect only Objective-C types.
-.. code-block:: objc
+```objc
+void test() {
+ [NSSet setWithObjects:@"Foo", "Bar", nil];
+ // warn: argument should be an ObjC pointer type, not 'char *'
+}
+```
- void test() {
- [NSSet setWithObjects:@"Foo", "Bar", nil];
- // warn: argument should be an ObjC pointer type, not 'char *'
- }
+(osx-corefoundation-cferror)=
-.. _osx-coreFoundation-CFError:
+#### osx.coreFoundation.CFError (C)
-osx.coreFoundation.CFError (C)
-""""""""""""""""""""""""""""""
-Check usage of CFErrorRef* parameters
+Check usage of CFErrorRef\* parameters
-.. code-block:: c
+```c
+void test(CFErrorRef *error) {
+ // warn: function accepting CFErrorRef* should have a
+ // non-void return
+}
- void test(CFErrorRef *error) {
- // warn: function accepting CFErrorRef* should have a
- // non-void return
- }
+int foo(CFErrorRef *error) {
+ *error = 0; // warn: potential null dereference
+ return 0;
+}
+```
- int foo(CFErrorRef *error) {
- *error = 0; // warn: potential null dereference
- return 0;
- }
+(osx-corefoundation-cfnumber)=
-.. _osx-coreFoundation-CFNumber:
+#### osx.coreFoundation.CFNumber (C)
-osx.coreFoundation.CFNumber (C)
-"""""""""""""""""""""""""""""""
Check for proper uses of CFNumber APIs.
-.. code-block:: c
+```c
+CFNumberRef test(unsigned char x) {
+ return CFNumberCreate(0, kCFNumberSInt16Type, &x);
+ // warn: 8-bit integer is used to initialize a 16-bit integer
+}
+```
- CFNumberRef test(unsigned char x) {
- return CFNumberCreate(0, kCFNumberSInt16Type, &x);
- // warn: 8-bit integer is used to initialize a 16-bit integer
- }
+(osx-corefoundation-cfretainrelease)=
-.. _osx-coreFoundation-CFRetainRelease:
+#### osx.coreFoundation.CFRetainRelease (C)
-osx.coreFoundation.CFRetainRelease (C)
-""""""""""""""""""""""""""""""""""""""
Check for null arguments to CFRetain/CFRelease/CFMakeCollectable.
-.. code-block:: c
+```c
+void test(CFTypeRef p) {
+ if (!p)
+ CFRetain(p); // warn
+}
- void test(CFTypeRef p) {
- if (!p)
- CFRetain(p); // warn
- }
+void test(int x, CFTypeRef p) {
+ if (p)
+ return;
- void test(int x, CFTypeRef p) {
- if (p)
- return;
+ CFRelease(p); // warn
+}
+```
- CFRelease(p); // warn
- }
+(osx-corefoundation-containers-outofbounds)=
-.. _osx-coreFoundation-containers-OutOfBounds:
+#### osx.coreFoundation.containers.OutOfBounds (C)
-osx.coreFoundation.containers.OutOfBounds (C)
-"""""""""""""""""""""""""""""""""""""""""""""
Checks for index out-of-bounds when using 'CFArray' API.
-.. code-block:: c
+```c
+void test() {
+ CFArrayRef A = CFArrayCreate(0, 0, 0, &kCFTypeArrayCallBacks);
+ CFArrayGetValueAtIndex(A, 0); // warn
+}
+```
- void test() {
- CFArrayRef A = CFArrayCreate(0, 0, 0, &kCFTypeArrayCallBacks);
- CFArrayGetValueAtIndex(A, 0); // warn
- }
+(osx-corefoundation-containers-pointersizedvalues)=
-.. _osx-coreFoundation-containers-PointerSizedValues:
+#### osx.coreFoundation.containers.PointerSizedValues (C)
-osx.coreFoundation.containers.PointerSizedValues (C)
-""""""""""""""""""""""""""""""""""""""""""""""""""""
Warns if 'CFArray', 'CFDictionary', 'CFSet' are created with non-pointer-size values.
-.. code-block:: c
-
- void test() {
- int x[] = { 1 };
- CFArrayRef A = CFArrayCreate(0, (const void """""""""""""""""""""""")x, 1,
- &kCFTypeArrayCallBacks); // warn
- }
+```c
+void test() {
+ int x[] = { 1 };
+ CFArrayRef A = CFArrayCreate(0, (const void """""""""""""""""""""""")x, 1,
+ &kCFTypeArrayCallBacks); // warn
+}
+```
-Fuchsia
-^^^^^^^
+### Fuchsia
Fuchsia is an open source capability-based operating system currently being
developed by Google. This section describes checkers that can find various
misuses of Fuchsia APIs.
-.. _fuchsia-HandleChecker:
+(fuchsia-handlechecker)=
+
+#### fuchsia.HandleChecker
-fuchsia.HandleChecker
-""""""""""""""""""""""""""""
Handles identify resources. Similar to pointers they can be leaked,
double freed, or use after freed. This check attempts to find such problems.
-.. code-block:: cpp
-
- void checkLeak08(int tag) {
- zx_handle_t sa, sb;
- zx_channel_create(0, &sa, &sb);
- if (tag)
- zx_handle_close(sa);
- use(sb); // Warn: Potential leak of handle
- zx_handle_close(sb);
- }
+```cpp
+void checkLeak08(int tag) {
+ zx_handle_t sa, sb;
+ zx_channel_create(0, &sa, &sb);
+ if (tag)
+ zx_handle_close(sa);
+ use(sb); // Warn: Potential leak of handle
+ zx_handle_close(sb);
+}
+```
-WebKit
-^^^^^^
+### WebKit
WebKit is an open-source web browser engine available for macOS, iOS and Linux.
This section describes checkers that can find issues in WebKit codebase.
@@ -3077,735 +3030,719 @@ This section describes checkers that can find issues in WebKit codebase.
Most of the checkers focus on memory management for which WebKit uses custom implementation of reference counted smartpointers.
Checkers are formulated in terms related to ref-counting:
- - *Ref-counted type* is either ``Ref<T>`` or ``RefPtr<T>``.
- - *Ref-countable type* is any type that implements ``ref()`` and ``deref()`` methods as ``RefPtr<>`` is a template (i. e. relies on duck typing).
- - *Uncounted type* is ref-countable but not ref-counted type.
+: - *Ref-counted type* is either `Ref<T>` or `RefPtr<T>`.
+ - *Ref-countable type* is any type that implements `ref()` and `deref()` methods as `RefPtr<>` is a template (i. e. relies on duck typing).
+ - *Uncounted type* is ref-countable but not ref-counted type.
+
+(webkit-refcntblbasevirtualdtor)=
-.. _webkit-RefCntblBaseVirtualDtor:
+#### webkit.RefCntblBaseVirtualDtor
-webkit.RefCntblBaseVirtualDtor
-""""""""""""""""""""""""""""""""""""
All uncounted types used as base classes must have a virtual destructor.
-Ref-counted types hold their ref-countable data by a raw pointer and allow implicit upcasting from ref-counted pointer to derived type to ref-counted pointer to base type. This might lead to an object of (dynamic) derived type being deleted via pointer to the base class type which C++ standard defines as UB in case the base class doesn't have virtual destructor ``[expr.delete]``.
+Ref-counted types hold their ref-countable data by a raw pointer and allow implicit upcasting from ref-counted pointer to derived type to ref-counted pointer to base type. This might lead to an object of (dynamic) derived type being deleted via pointer to the base class type which C++ standard defines as UB in case the base class doesn't have virtual destructor `[expr.delete]`.
-.. code-block:: cpp
+```cpp
+struct RefCntblBase {
+ void ref() {}
+ void deref() {}
+};
- struct RefCntblBase {
- void ref() {}
- void deref() {}
- };
+struct Derived : RefCntblBase { }; // warn
+```
- struct Derived : RefCntblBase { }; // warn
+(webkit-nouncountedmemberchecker)=
-.. _webkit-NoUncountedMemberChecker:
+#### webkit.NoUncountedMemberChecker
-webkit.NoUncountedMemberChecker
-"""""""""""""""""""""""""""""""""""""
Raw pointers and references to uncounted types can't be used as class members. Only ref-counted types are allowed.
-.. code-block:: cpp
+```cpp
+struct RefCntbl {
+ void ref() {}
+ void deref() {}
+};
- struct RefCntbl {
- void ref() {}
- void deref() {}
- };
+struct Foo {
+ RefCntbl * ptr; // warn
+ RefCntbl & ptr; // warn
+ // ...
+};
+```
- struct Foo {
- RefCntbl * ptr; // warn
- RefCntbl & ptr; // warn
- // ...
- };
+(webkit-uncountedlambdacaptureschecker)=
-.. _webkit-UncountedLambdaCapturesChecker:
+#### webkit.UncountedLambdaCapturesChecker
-webkit.UncountedLambdaCapturesChecker
-"""""""""""""""""""""""""""""""""""""
Raw pointers and references to uncounted types can't be captured in lambdas. Only ref-counted types are allowed.
-.. code-block:: cpp
+```cpp
+struct RefCntbl {
+ void ref() {}
+ void deref() {}
+};
- struct RefCntbl {
- void ref() {}
- void deref() {}
- };
+void foo(RefCntbl* a, RefCntbl& b) {
+ [&, a](){ // warn about 'a'
+ do_something(b); // warn about 'b'
+ };
+};
+```
- void foo(RefCntbl* a, RefCntbl& b) {
- [&, a](){ // warn about 'a'
- do_something(b); // warn about 'b'
- };
- };
+(alpha-checkers)=
-.. _alpha-checkers:
-
-Experimental Checkers
----------------------
+## Experimental Checkers
*These are checkers with known issues or limitations that keep them from being on by default. They are likely to have false positives. Bug reports and especially patches are welcome.*
-alpha.clone
-^^^^^^^^^^^
+### alpha.clone
+
+(alpha-clone-clonechecker)=
-.. _alpha-clone-CloneChecker:
+#### alpha.clone.CloneChecker (C, C++, ObjC)
-alpha.clone.CloneChecker (C, C++, ObjC)
-"""""""""""""""""""""""""""""""""""""""
Reports similar pieces of code.
-.. code-block:: c
+```c
+void log();
- void log();
+int max(int a, int b) { // warn
+ log();
+ if (a > b)
+ return a;
+ return b;
+}
- int max(int a, int b) { // warn
- log();
- if (a > b)
- return a;
- return b;
- }
+int maxClone(int x, int y) { // similar code here
+ log();
+ if (x > y)
+ return x;
+ return y;
+}
+```
- int maxClone(int x, int y) { // similar code here
- log();
- if (x > y)
- return x;
- return y;
- }
+### alpha.core
-alpha.core
-^^^^^^^^^^
+(alpha-core-boolassignment)=
-.. _alpha-core-BoolAssignment:
+#### alpha.core.BoolAssignment (ObjC)
-alpha.core.BoolAssignment (ObjC)
-""""""""""""""""""""""""""""""""
Warn about assigning non-{0,1} values to boolean variables.
-.. code-block:: objc
+```objc
+void test() {
+ BOOL b = -1; // warn
+}
+```
- void test() {
- BOOL b = -1; // warn
- }
+(alpha-core-c11lock)=
-.. _alpha-core-C11Lock:
+#### alpha.core.C11Lock
-alpha.core.C11Lock
-""""""""""""""""""
-Similarly to :ref:`alpha.unix.PthreadLock <alpha-unix-PthreadLock>`, checks for
-the locking/unlocking of ``mtx_t`` mutexes.
+Similarly to {ref}`alpha.unix.PthreadLock <alpha-unix-PthreadLock>`, checks for
+the locking/unlocking of `mtx_t` mutexes.
-.. code-block:: cpp
+```cpp
+mtx_t mtx1;
- mtx_t mtx1;
+void bad1(void)
+{
+ mtx_lock(&mtx1);
+ mtx_lock(&mtx1); // warn: This lock has already been acquired
+}
+```
- void bad1(void)
- {
- mtx_lock(&mtx1);
- mtx_lock(&mtx1); // warn: This lock has already been acquired
- }
+(alpha-core-casttostruct)=
-.. _alpha-core-CastToStruct:
+#### alpha.core.CastToStruct (C, C++)
-alpha.core.CastToStruct (C, C++)
-""""""""""""""""""""""""""""""""
Check for cast from non-struct pointer to struct pointer.
-.. code-block:: cpp
+```cpp
+// C
+struct s {};
- // C
- struct s {};
+void test(int *p) {
+ struct s *ps = (struct s *) p; // warn
+}
- void test(int *p) {
- struct s *ps = (struct s *) p; // warn
- }
+// C++
+class c {};
- // C++
- class c {};
+void test(int *p) {
+ c *pc = (c *) p; // warn
+}
+```
- void test(int *p) {
- c *pc = (c *) p; // warn
- }
+(alpha-core-conversion)=
-.. _alpha-core-Conversion:
+#### alpha.core.Conversion (C, C++, ObjC)
-alpha.core.Conversion (C, C++, ObjC)
-""""""""""""""""""""""""""""""""""""
Loss of sign/precision in implicit conversions.
-.. code-block:: c
-
- void test(unsigned U, signed S) {
- if (S > 10) {
- if (U < S) {
- }
- }
- if (S < -10) {
- if (U < S) { // warn (loss of sign)
- }
- }
- }
+```c
+void test(unsigned U, signed S) {
+ if (S > 10) {
+ if (U < S) {
+ }
+ }
+ if (S < -10) {
+ if (U < S) { // warn (loss of sign)
+ }
+ }
+}
- void test() {
- long long A = 1LL << 60;
- short X = A; // warn (loss of precision)
- }
+void test() {
+ long long A = 1LL << 60;
+ short X = A; // warn (loss of precision)
+}
+```
-.. _alpha-core-DynamicTypeChecker:
+(alpha-core-dynamictypechecker)=
-alpha.core.DynamicTypeChecker (ObjC)
-""""""""""""""""""""""""""""""""""""
-Check for cases where the dynamic and the static type of an object are unrelated.
+#### alpha.core.DynamicTypeChecker (ObjC)
+Check for cases where the dynamic and the static type of an object are unrelated.
-.. code-block:: objc
+```objc
+id date = [NSDate date];
- id date = [NSDate date];
+// Warning: Object has a dynamic type 'NSDate *' which is
+// incompatible with static type 'NSNumber *'"
+NSNumber *number = date;
+[number doubleValue];
+```
- // Warning: Object has a dynamic type 'NSDate *' which is
- // incompatible with static type 'NSNumber *'"
- NSNumber *number = date;
- [number doubleValue];
+(alpha-core-pointerarithm)=
-.. _alpha-core-PointerArithm:
+#### alpha.core.PointerArithm (C)
-alpha.core.PointerArithm (C)
-""""""""""""""""""""""""""""
Check for pointer arithmetic on locations other than array elements.
-.. code-block:: c
+```c
+void test() {
+ int x;
+ int *p;
+ p = &x + 1; // warn
+}
+```
- void test() {
- int x;
- int *p;
- p = &x + 1; // warn
- }
+(alpha-core-stackaddressasyncescape)=
-.. _alpha-core-StackAddressAsyncEscape:
+#### alpha.core.StackAddressAsyncEscape (ObjC)
-alpha.core.StackAddressAsyncEscape (ObjC)
-"""""""""""""""""""""""""""""""""""""""""
Check that addresses to stack memory do not escape the function that involves dispatch_after or dispatch_async.
-This checker is a part of ``core.StackAddressEscape``, but is temporarily disabled until some false positives are fixed.
-
-.. code-block:: c
-
- dispatch_block_t test_block_inside_block_async_leak() {
- int x = 123;
- void (^inner)(void) = ^void(void) {
- int y = x;
- ++y;
- };
- void (^outer)(void) = ^void(void) {
- int z = x;
- ++z;
- inner();
- };
- return outer; // warn: address of stack-allocated block is captured by a
- // returned block
- }
+This checker is a part of `core.StackAddressEscape`, but is temporarily disabled until some false positives are fixed.
+
+```c
+dispatch_block_t test_block_inside_block_async_leak() {
+ int x = 123;
+ void (^inner)(void) = ^void(void) {
+ int y = x;
+ ++y;
+ };
+ void (^outer)(void) = ^void(void) {
+ int z = x;
+ ++z;
+ inner();
+ };
+ return outer; // warn: address of stack-allocated block is captured by a
+ // returned block
+}
+```
+
+(alpha-core-stdvariant)=
-.. _alpha-core-StdVariant:
+#### alpha.core.StdVariant (C++)
-alpha.core.StdVariant (C++)
-"""""""""""""""""""""""""""
-Check if a value of active type is retrieved from an ``std::variant`` instance with ``std::get``.
+Check if a value of active type is retrieved from an `std::variant` instance with `std::get`.
In case of bad variant type access (the accessed type differs from the active type)
a warning is emitted. Currently, this checker does not take exception handling into account.
-.. code-block:: cpp
+```cpp
+void test() {
+ std::variant<int, char> v = 25;
+ char c = stg::get<char>(v); // warn: "int" is the active alternative
+}
+```
- void test() {
- std::variant<int, char> v = 25;
- char c = stg::get<char>(v); // warn: "int" is the active alternative
- }
+(alpha-core-testafterdivzero)=
-.. _alpha-core-TestAfterDivZero:
+#### alpha.core.TestAfterDivZero (C)
-alpha.core.TestAfterDivZero (C)
-"""""""""""""""""""""""""""""""
Check for division by variable that is later compared against 0.
Either the comparison is useless or there is division by zero.
-.. code-block:: c
+```c
+void test(int x) {
+ var = 77 / x;
+ if (x == 0) { } // warn
+}
+```
- void test(int x) {
- var = 77 / x;
- if (x == 0) { } // warn
- }
+(alpha-core-storetoimmutable)=
-.. _alpha-core-StoreToImmutable:
+#### alpha.core.StoreToImmutable (C, C++)
-alpha.core.StoreToImmutable (C, C++)
-""""""""""""""""""""""""""""""""""""
Check for writes to immutable memory regions. This implements part of SEI CERT Rule ENV30-C.
This checker detects attempts to write to memory regions that are marked as immutable,
including const variables, string literals, and other const-qualified memory.
-.. literalinclude:: checkers/storetoimmutable_example.cpp
- :language: cpp
+```{literalinclude} checkers/storetoimmutable_example.cpp
+:language: cpp
+```
**Solution**
Avoid writing to const-qualified memory regions. If you need to modify the data,
remove the const qualifier from the original declaration or use a mutable copy.
-alpha.cplusplus
-^^^^^^^^^^^^^^^
+### alpha.cplusplus
+
+(alpha-cplusplus-deletewithnonvirtualdtor)=
-.. _alpha-cplusplus-DeleteWithNonVirtualDtor:
+#### alpha.cplusplus.DeleteWithNonVirtualDtor (C++)
-alpha.cplusplus.DeleteWithNonVirtualDtor (C++)
-""""""""""""""""""""""""""""""""""""""""""""""
Reports destructions of polymorphic objects with a non-virtual destructor in their base class.
-.. code-block:: cpp
+```cpp
+class NonVirtual {};
+class NVDerived : public NonVirtual {};
- class NonVirtual {};
- class NVDerived : public NonVirtual {};
+NonVirtual *create() {
+ NonVirtual *x = new NVDerived(); // note: Casting from 'NVDerived' to
+ // 'NonVirtual' here
+ return x;
+}
- NonVirtual *create() {
- NonVirtual *x = new NVDerived(); // note: Casting from 'NVDerived' to
- // 'NonVirtual' here
- return x;
- }
+void foo() {
+ NonVirtual *x = create();
+ delete x; // warn: destruction of a polymorphic object with no virtual
+ // destructor
+}
+```
- void foo() {
- NonVirtual *x = create();
- delete x; // warn: destruction of a polymorphic object with no virtual
- // destructor
- }
+(alpha-cplusplus-invalidatediterator)=
-.. _alpha-cplusplus-InvalidatedIterator:
+#### alpha.cplusplus.InvalidatedIterator (C++)
-alpha.cplusplus.InvalidatedIterator (C++)
-"""""""""""""""""""""""""""""""""""""""""
Check for use of invalidated iterators.
-.. code-block:: cpp
-
- void bad_copy_assign_operator_list1(std::list &L1,
- const std::list &L2) {
- auto i0 = L1.cbegin();
- L1 = L2;
- *i0; // warn: invalidated iterator accessed
- }
+```cpp
+void bad_copy_assign_operator_list1(std::list &L1,
+ const std::list &L2) {
+ auto i0 = L1.cbegin();
+ L1 = L2;
+ *i0; // warn: invalidated iterator accessed
+}
+```
+(alpha-cplusplus-iteratorrange)=
-.. _alpha-cplusplus-IteratorRange:
+#### alpha.cplusplus.IteratorRange (C++)
-alpha.cplusplus.IteratorRange (C++)
-"""""""""""""""""""""""""""""""""""
Check for iterators used outside their valid ranges.
-.. code-block:: cpp
+```cpp
+void simple_bad_end(const std::vector &v) {
+ auto i = v.end();
+ *i; // warn: iterator accessed outside of its range
+}
+```
- void simple_bad_end(const std::vector &v) {
- auto i = v.end();
- *i; // warn: iterator accessed outside of its range
- }
+(alpha-cplusplus-mismatchediterator)=
-.. _alpha-cplusplus-MismatchedIterator:
+#### alpha.cplusplus.MismatchedIterator (C++)
-alpha.cplusplus.MismatchedIterator (C++)
-""""""""""""""""""""""""""""""""""""""""
Check for use of iterators of different containers where iterators of the same container are expected.
-.. code-block:: cpp
-
- void bad_insert3(std::vector &v1, std::vector &v2) {
- v2.insert(v1.cbegin(), v2.cbegin(), v2.cend()); // warn: container accessed
- // using foreign
- // iterator argument
- v1.insert(v1.cbegin(), v1.cbegin(), v2.cend()); // warn: iterators of
- // different containers
- // used where the same
- // container is
- // expected
- v1.insert(v1.cbegin(), v2.cbegin(), v1.cend()); // warn: iterators of
- // different containers
- // used where the same
- // container is
- // expected
- }
+```cpp
+void bad_insert3(std::vector &v1, std::vector &v2) {
+ v2.insert(v1.cbegin(), v2.cbegin(), v2.cend()); // warn: container accessed
+ // using foreign
+ // iterator argument
+ v1.insert(v1.cbegin(), v1.cbegin(), v2.cend()); // warn: iterators of
+ // different containers
+ // used where the same
+ // container is
+ // expected
+ v1.insert(v1.cbegin(), v2.cbegin(), v1.cend()); // warn: iterators of
+ // different containers
+ // used where the same
+ // container is
+ // expected
+}
+```
+
+(alpha-cplusplus-smartptr)=
-.. _alpha-cplusplus-SmartPtr:
+#### alpha.cplusplus.SmartPtr (C++)
-alpha.cplusplus.SmartPtr (C++)
-""""""""""""""""""""""""""""""
Check for dereference of null smart pointers.
-.. code-block:: cpp
+```cpp
+void deref_smart_ptr() {
+ std::unique_ptr<int> P;
+ *P; // warn: dereference of a default constructed smart unique_ptr
+}
+```
- void deref_smart_ptr() {
- std::unique_ptr<int> P;
- *P; // warn: dereference of a default constructed smart unique_ptr
- }
+### alpha.deadcode
+(alpha-deadcode-unreachablecode)=
-alpha.deadcode
-^^^^^^^^^^^^^^
-.. _alpha-deadcode-UnreachableCode:
+#### alpha.deadcode.UnreachableCode (C, C++)
-alpha.deadcode.UnreachableCode (C, C++)
-"""""""""""""""""""""""""""""""""""""""
Check unreachable code.
-.. code-block:: cpp
+```cpp
+// C
+int test() {
+ int x = 1;
+ while(x);
+ return x; // warn
+}
- // C
- int test() {
- int x = 1;
- while(x);
- return x; // warn
- }
+// C++
+void test() {
+ int a = 2;
- // C++
- void test() {
- int a = 2;
+ while (a > 1)
+ a--;
- while (a > 1)
- a--;
+ if (a > 1)
+ a++; // warn
+}
- if (a > 1)
- a++; // warn
- }
+// Objective-C
+void test(id x) {
+ return;
+ [x retain]; // warn
+}
+```
- // Objective-C
- void test(id x) {
- return;
- [x retain]; // warn
- }
+### alpha.fuchsia
-alpha.fuchsia
-^^^^^^^^^^^^^
+(alpha-fuchsia-lock)=
-.. _alpha-fuchsia-lock:
+#### alpha.fuchsia.Lock
-alpha.fuchsia.Lock
-""""""""""""""""""
-Similarly to :ref:`alpha.unix.PthreadLock <alpha-unix-PthreadLock>`, checks for
+Similarly to {ref}`alpha.unix.PthreadLock <alpha-unix-PthreadLock>`, checks for
the locking/unlocking of fuchsia mutexes.
-.. code-block:: cpp
-
- spin_lock_t mtx1;
+```cpp
+spin_lock_t mtx1;
- void bad1(void)
- {
- spin_lock(&mtx1);
- spin_lock(&mtx1); // warn: This lock has already been acquired
- }
+void bad1(void)
+{
+ spin_lock(&mtx1);
+ spin_lock(&mtx1); // warn: This lock has already been acquired
+}
+```
-alpha.llvm
-^^^^^^^^^^
+### alpha.llvm
-.. _alpha-llvm-Conventions:
+(alpha-llvm-conventions)=
-alpha.llvm.Conventions
-""""""""""""""""""""""
+#### alpha.llvm.Conventions
Check code for LLVM codebase conventions:
-* A StringRef should not be bound to a temporary std::string whose lifetime is shorter than the StringRef's.
-* Clang AST nodes should not have fields that can allocate memory.
+- A StringRef should not be bound to a temporary std::string whose lifetime is shorter than the StringRef's.
+- Clang AST nodes should not have fields that can allocate memory.
+### alpha.osx
-alpha.osx
-^^^^^^^^^
+(alpha-osx-cocoa-directivarassignment)=
-.. _alpha-osx-cocoa-DirectIvarAssignment:
+#### alpha.osx.cocoa.DirectIvarAssignment (ObjC)
-alpha.osx.cocoa.DirectIvarAssignment (ObjC)
-"""""""""""""""""""""""""""""""""""""""""""
Check for direct assignments to instance variables.
+```objc
+ at interface MyClass : NSObject {}
+ at property (readonly) id A;
+- (void) foo;
+ at end
-.. code-block:: objc
+ at implementation MyClass
+- (void) foo {
+ _A = 0; // warn
+}
+ at end
+```
- @interface MyClass : NSObject {}
- @property (readonly) id A;
- - (void) foo;
- @end
+(alpha-osx-cocoa-directivarassignmentforannotatedfunctions)=
- @implementation MyClass
- - (void) foo {
- _A = 0; // warn
- }
- @end
+#### alpha.osx.cocoa.DirectIvarAssignmentForAnnotatedFunctions (ObjC)
-.. _alpha-osx-cocoa-DirectIvarAssignmentForAnnotatedFunctions:
-
-alpha.osx.cocoa.DirectIvarAssignmentForAnnotatedFunctions (ObjC)
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Check for direct assignments to instance variables in
-the methods annotated with ``objc_no_direct_instance_variable_assignment``.
-
-.. code-block:: objc
-
- @interface MyClass : NSObject {}
- @property (readonly) id A;
- - (void) fAnnotated __attribute__((
- annotate("objc_no_direct_instance_variable_assignment")));
- - (void) fNotAnnotated;
- @end
-
- @implementation MyClass
- - (void) fAnnotated {
- _A = 0; // warn
- }
- - (void) fNotAnnotated {
- _A = 0; // no warn
- }
- @end
+the methods annotated with `objc_no_direct_instance_variable_assignment`.
+
+```objc
+ at interface MyClass : NSObject {}
+ at property (readonly) id A;
+- (void) fAnnotated __attribute__((
+ annotate("objc_no_direct_instance_variable_assignment")));
+- (void) fNotAnnotated;
+ at end
+
+ at implementation MyClass
+- (void) fAnnotated {
+ _A = 0; // warn
+}
+- (void) fNotAnnotated {
+ _A = 0; // no warn
+}
+ at end
+```
+(alpha-osx-cocoa-instancevariableinvalidation)=
-.. _alpha-osx-cocoa-InstanceVariableInvalidation:
+#### alpha.osx.cocoa.InstanceVariableInvalidation (ObjC)
-alpha.osx.cocoa.InstanceVariableInvalidation (ObjC)
-"""""""""""""""""""""""""""""""""""""""""""""""""""
Check that the invalidatable instance variables are
invalidated in the methods annotated with objc_instance_variable_invalidator.
-.. code-block:: objc
+```objc
+ at protocol Invalidation <NSObject>
+- (void) invalidate
+ __attribute__((annotate("objc_instance_variable_invalidator")));
+ at end
- @protocol Invalidation <NSObject>
- - (void) invalidate
- __attribute__((annotate("objc_instance_variable_invalidator")));
- @end
+ at interface InvalidationImpObj : NSObject <Invalidation>
+ at end
- @interface InvalidationImpObj : NSObject <Invalidation>
- @end
+ at interface SubclassInvalidationImpObj : InvalidationImpObj {
+ InvalidationImpObj *var;
+}
+- (void)invalidate;
+ at end
- @interface SubclassInvalidationImpObj : InvalidationImpObj {
- InvalidationImpObj *var;
- }
- - (void)invalidate;
- @end
+ at implementation SubclassInvalidationImpObj
+- (void) invalidate {}
+ at end
+// warn: var needs to be invalidated or set to nil
+```
- @implementation SubclassInvalidationImpObj
- - (void) invalidate {}
- @end
- // warn: var needs to be invalidated or set to nil
+(alpha-osx-cocoa-missinginvalidationmethod)=
-.. _alpha-osx-cocoa-MissingInvalidationMethod:
+#### alpha.osx.cocoa.MissingInvalidationMethod (ObjC)
-alpha.osx.cocoa.MissingInvalidationMethod (ObjC)
-""""""""""""""""""""""""""""""""""""""""""""""""
Check that the invalidation methods are present in classes that contain invalidatable instance variables.
-.. code-block:: objc
+```objc
+ at protocol Invalidation <NSObject>
+- (void)invalidate
+ __attribute__((annotate("objc_instance_variable_invalidator")));
+ at end
- @protocol Invalidation <NSObject>
- - (void)invalidate
- __attribute__((annotate("objc_instance_variable_invalidator")));
- @end
+ at interface NeedInvalidation : NSObject <Invalidation>
+ at end
- @interface NeedInvalidation : NSObject <Invalidation>
- @end
+ at interface MissingInvalidationMethodDecl : NSObject {
+ NeedInvalidation *Var; // warn
+}
+ at end
- @interface MissingInvalidationMethodDecl : NSObject {
- NeedInvalidation *Var; // warn
- }
- @end
+ at implementation MissingInvalidationMethodDecl
+ at end
+```
- @implementation MissingInvalidationMethodDecl
- @end
+(alpha-osx-cocoa-localizability-pluralmisusechecker)=
-.. _alpha-osx-cocoa-localizability-PluralMisuseChecker:
+#### alpha.osx.cocoa.localizability.PluralMisuseChecker (ObjC)
-alpha.osx.cocoa.localizability.PluralMisuseChecker (ObjC)
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Warns against using one vs. many plural pattern in code when generating localized strings.
-.. code-block:: objc
-
- NSString *reminderText =
- NSLocalizedString(@"None", @"Indicates no reminders");
- if (reminderCount == 1) {
- // Warning: Plural cases are not supported across all languages.
- // Use a .stringsdict file instead
- reminderText =
- NSLocalizedString(@"1 Reminder", @"Indicates single reminder");
- } else if (reminderCount >= 2) {
- // Warning: Plural cases are not supported across all languages.
- // Use a .stringsdict file instead
- reminderText =
- [NSString stringWithFormat:
- NSLocalizedString(@"%@ Reminders", @"Indicates multiple reminders"),
- reminderCount];
- }
+```objc
+NSString *reminderText =
+ NSLocalizedString(@"None", @"Indicates no reminders");
+if (reminderCount == 1) {
+ // Warning: Plural cases are not supported across all languages.
+ // Use a .stringsdict file instead
+ reminderText =
+ NSLocalizedString(@"1 Reminder", @"Indicates single reminder");
+} else if (reminderCount >= 2) {
+ // Warning: Plural cases are not supported across all languages.
+ // Use a .stringsdict file instead
+ reminderText =
+ [NSString stringWithFormat:
+ NSLocalizedString(@"%@ Reminders", @"Indicates multiple reminders"),
+ reminderCount];
+}
+```
-alpha.security
-^^^^^^^^^^^^^^
+### alpha.security
-.. _alpha-security-ReturnPtrRange:
+(alpha-security-returnptrrange)=
+
+#### alpha.security.ReturnPtrRange (C)
-alpha.security.ReturnPtrRange (C)
-"""""""""""""""""""""""""""""""""
Check for an out-of-bound pointer being returned to callers.
-.. code-block:: c
+```c
+static int A[10];
- static int A[10];
+int *test() {
+ int *p = A + 10;
+ return p; // warn
+}
- int *test() {
- int *p = A + 10;
- return p; // warn
- }
+int test(void) {
+ int x;
+ return x; // warn: undefined or garbage returned
+}
+```
- int test(void) {
- int x;
- return x; // warn: undefined or garbage returned
- }
+### alpha.unix
-alpha.unix
-^^^^^^^^^^
+(alpha-unix-pthreadlock)=
-.. _alpha-unix-PthreadLock:
+#### alpha.unix.PthreadLock (C)
-alpha.unix.PthreadLock (C)
-""""""""""""""""""""""""""
Simple lock -> unlock checker.
-Applies to: ``pthread_mutex_lock, pthread_rwlock_rdlock, pthread_rwlock_wrlock, lck_mtx_lock, lck_rw_lock_exclusive``
-``lck_rw_lock_shared, pthread_mutex_trylock, pthread_rwlock_tryrdlock, pthread_rwlock_tryrwlock, lck_mtx_try_lock,
-lck_rw_try_lock_exclusive, lck_rw_try_lock_shared, pthread_mutex_unlock, pthread_rwlock_unlock, lck_mtx_unlock, lck_rw_done``.
+Applies to: `pthread_mutex_lock, pthread_rwlock_rdlock, pthread_rwlock_wrlock, lck_mtx_lock, lck_rw_lock_exclusive`
+`lck_rw_lock_shared, pthread_mutex_trylock, pthread_rwlock_tryrdlock, pthread_rwlock_tryrwlock, lck_mtx_try_lock,
+lck_rw_try_lock_exclusive, lck_rw_try_lock_shared, pthread_mutex_unlock, pthread_rwlock_unlock, lck_mtx_unlock, lck_rw_done`.
**Options**
-* ``WarnOnLockOrderReversal`` (boolean). If set to true, the checker will warn
+- `WarnOnLockOrderReversal` (boolean). If set to true, the checker will warn
on non-LIFO unlock order (possible lock order reversal). Defaults to false
because detecting real lock order violations requires cross-path analysis of
acquisition order, which the analyzer's single-path engine does not support.
-.. code-block:: c
+```c
+pthread_mutex_t mtx;
- pthread_mutex_t mtx;
+void test() {
+ pthread_mutex_lock(&mtx);
+ pthread_mutex_lock(&mtx);
+ // warn: this lock has already been acquired
+}
- void test() {
- pthread_mutex_lock(&mtx);
- pthread_mutex_lock(&mtx);
- // warn: this lock has already been acquired
- }
+// The following warnings require WarnOnLockOrderReversal=true:
- // The following warnings require WarnOnLockOrderReversal=true:
+lck_mtx_t lck1, lck2;
- lck_mtx_t lck1, lck2;
+void test() {
+ lck_mtx_lock(&lck1);
+ lck_mtx_lock(&lck2);
+ lck_mtx_unlock(&lck1);
+ // warn: this was not the most recently acquired lock
+}
- void test() {
- lck_mtx_lock(&lck1);
- lck_mtx_lock(&lck2);
- lck_mtx_unlock(&lck1);
- // warn: this was not the most recently acquired lock
- }
+lck_mtx_t lck1, lck2;
- lck_mtx_t lck1, lck2;
+void test() {
+ if (lck_mtx_try_lock(&lck1) == 0)
+ return;
- void test() {
- if (lck_mtx_try_lock(&lck1) == 0)
- return;
+ lck_mtx_lock(&lck2);
+ lck_mtx_unlock(&lck1);
+ // warn: this was not the most recently acquired lock
+}
+```
- lck_mtx_lock(&lck2);
- lck_mtx_unlock(&lck1);
- // warn: this was not the most recently acquired lock
- }
+(alpha-unix-simplestream)=
-.. _alpha-unix-SimpleStream:
+#### alpha.unix.SimpleStream (C)
-alpha.unix.SimpleStream (C)
-"""""""""""""""""""""""""""
-Check for misuses of stream APIs. Check for misuses of stream APIs: ``fopen, fclose``
-(demo checker, the subject of the demo (`Slides <https://llvm.org/devmtg/2012-11/Zaks-Rose-Checker24Hours.pdf>`_ ,
-`Video <https://youtu.be/kdxlsP5QVPw>`_) by Anna Zaks and Jordan Rose presented at the
-`2012 LLVM Developers' Meeting <https://llvm.org/devmtg/2012-11/>`_).
+Check for misuses of stream APIs. Check for misuses of stream APIs: `fopen, fclose`
+(demo checker, the subject of the demo ([Slides](https://llvm.org/devmtg/2012-11/Zaks-Rose-Checker24Hours.pdf) ,
+[Video](https://youtu.be/kdxlsP5QVPw)) by Anna Zaks and Jordan Rose presented at the
+[2012 LLVM Developers' Meeting](https://llvm.org/devmtg/2012-11/)).
-.. code-block:: c
+```c
+void test() {
+ FILE *F = fopen("myfile.txt", "w");
+} // warn: opened file is never closed
- void test() {
- FILE *F = fopen("myfile.txt", "w");
- } // warn: opened file is never closed
+void test() {
+ FILE *F = fopen("myfile.txt", "w");
- void test() {
- FILE *F = fopen("myfile.txt", "w");
+ if (F)
+ fclose(F);
- if (F)
- fclose(F);
+ fclose(F); // warn: closing a previously closed file stream
+}
+```
- fclose(F); // warn: closing a previously closed file stream
- }
+(alpha-unix-cstring-bufferoverlap)=
-.. _alpha-unix-cstring-BufferOverlap:
+#### alpha.unix.cstring.BufferOverlap (C)
-alpha.unix.cstring.BufferOverlap (C)
-""""""""""""""""""""""""""""""""""""
-Checks for overlap in two buffer arguments. Applies to: ``memcpy, mempcpy, wmemcpy, wmempcpy``.
+Checks for overlap in two buffer arguments. Applies to: `memcpy, mempcpy, wmemcpy, wmempcpy`.
-.. code-block:: c
+```c
+void test() {
+ int a[4] = {0};
+ memcpy(a + 2, a + 1, 8); // warn
+}
+```
- void test() {
- int a[4] = {0};
- memcpy(a + 2, a + 1, 8); // warn
- }
+(alpha-unix-cstring-outofbounds)=
-.. _alpha-unix-cstring-OutOfBounds:
+#### alpha.unix.cstring.OutOfBounds (C)
-alpha.unix.cstring.OutOfBounds (C)
-""""""""""""""""""""""""""""""""""
Check for out-of-bounds access in string functions, such as:
-``memcpy, bcopy, strcpy, strncpy, strcat, strncat, memmove, memcmp, memset`` and more.
+`memcpy, bcopy, strcpy, strncpy, strcat, strncat, memmove, memcmp, memset` and more.
This check also works with string literals, except there is a known bug in that
the analyzer cannot detect embedded NULL characters when determining the string length.
-.. code-block:: c
+```c
+void test1() {
+ const char str[] = "Hello world";
+ char buffer[] = "Hello world";
+ memcpy(buffer, str, sizeof(str) + 1); // warn
+}
- void test1() {
- const char str[] = "Hello world";
- char buffer[] = "Hello world";
- memcpy(buffer, str, sizeof(str) + 1); // warn
- }
+void test2() {
+ const char str[] = "Hello world";
+ char buffer[] = "Helloworld";
+ memcpy(buffer, str, sizeof(str)); // warn
+}
+```
- void test2() {
- const char str[] = "Hello world";
- char buffer[] = "Helloworld";
- memcpy(buffer, str, sizeof(str)); // warn
- }
+### alpha.WebKit
-alpha.WebKit
-^^^^^^^^^^^^
+#### alpha.webkit.ForwardDeclChecker
-alpha.webkit.ForwardDeclChecker
-"""""""""""""""""""""""""""""""
Check for local variables, member variables, and function arguments that are forward declared.
-.. code-block:: cpp
+```cpp
+struct Obj;
+Obj* provide();
- struct Obj;
- Obj* provide();
+struct Foo {
+ Obj* ptr; // warn
+};
- struct Foo {
- Obj* ptr; // warn
- };
+ void foo() {
+ Obj* obj = provide(); // warn
+ consume(obj); // warn
+ }
+```
- void foo() {
- Obj* obj = provide(); // warn
- consume(obj); // warn
- }
+(alpha-webkit-nouncheckedptrmemberchecker)=
-.. _alpha-webkit-NoUncheckedPtrMemberChecker:
+#### alpha.webkit.MemoryUnsafeCastChecker
-alpha.webkit.MemoryUnsafeCastChecker
-""""""""""""""""""""""""""""""""""""""
Check for all casts from a base type to its derived type as these might be memory-unsafe.
Example:
-.. code-block:: cpp
-
- class Base { };
- class Derived : public Base { };
+```cpp
+class Base { };
+class Derived : public Base { };
- void f(Base* base) {
- Derived* derived = static_cast<Derived*>(base); // ERROR
- }
+void f(Base* base) {
+ Derived* derived = static_cast<Derived*>(base); // ERROR
+}
+```
For all cast operations (C-style casts, static_cast, reinterpret_cast, dynamic_cast), if the source type a `Base*` and the destination type is `Derived*`, where `Derived` inherits from `Base`, the static analyzer should signal an error.
@@ -3817,106 +3754,106 @@ This applies to:
For types like this, instead of using built in casts, the programmer will use helper functions that internally perform the appropriate type check and disable static analysis.
-alpha.webkit.NoDeleteChecker
-"""""""""""""""""""""""""""""""
-Check that ``[[clang::annotate_type("webkit.nodelete")]]`` annotation does not appear on a function which could delete an object.
+#### alpha.webkit.NoDeleteChecker
+
+Check that `[[clang::annotate_type("webkit.nodelete")]]` annotation does not appear on a function which could delete an object.
-.. code-block:: cpp
+```cpp
+void [[clang::annotate_type("webkit.nodelete")]] someFunction(RefCountable* obj) { // warn
+ delete obj;
+};
- void [[clang::annotate_type("webkit.nodelete")]] someFunction(RefCountable* obj) { // warn
- delete obj;
- };
+Foo [[clang::annotate_type("webkit.nodelete")]] trivialFunction(RefCountable* obj) {
+ return obj->anotherTrivialFunction();
+};
+```
- Foo [[clang::annotate_type("webkit.nodelete")]] trivialFunction(RefCountable* obj) {
- return obj->anotherTrivialFunction();
- };
+`[[clang::annotate_type("webkit.nodelete")]]` annotation makes the function ignored for the purpose of other WebKit smart pointer checkers.
+For example, `alpha.webkit.UncountedCallArgsChecker` will ignore a function call with this annotation.
-``[[clang::annotate_type("webkit.nodelete")]]`` annotation makes the function ignored for the purpose of other WebKit smart pointer checkers.
-For example, ``alpha.webkit.UncountedCallArgsChecker`` will ignore a function call with this annotation.
+#### alpha.webkit.NoUncheckedPtrMemberChecker
-alpha.webkit.NoUncheckedPtrMemberChecker
-""""""""""""""""""""""""""""""""""""""""
Raw pointers and references to an object which supports CheckedPtr or CheckedRef can't be used as class members. Only CheckedPtr, CheckedRef, RefPtr, or Ref are allowed.
-.. code-block:: cpp
+```cpp
+struct CheckableObj {
+ void incrementCheckedPtrCount() {}
+ void decrementCheckedPtrCount() {}
+};
- struct CheckableObj {
- void incrementCheckedPtrCount() {}
- void decrementCheckedPtrCount() {}
- };
+struct Foo {
+ CheckableObj* ptr; // warn
+ CheckableObj& ptr; // warn
+ // ...
+};
+```
- struct Foo {
- CheckableObj* ptr; // warn
- CheckableObj& ptr; // warn
- // ...
- };
+See [WebKit Guidelines for Safer C++ Programming](https://github.com/WebKit/WebKit/wiki/Safer-CPP-Guidelines) for details.
-See `WebKit Guidelines for Safer C++ Programming <https://github.com/WebKit/WebKit/wiki/Safer-CPP-Guidelines>`_ for details.
+#### alpha.webkit.NoUnretainedMemberChecker
-alpha.webkit.NoUnretainedMemberChecker
-""""""""""""""""""""""""""""""""""""""""
Raw pointers and references to a NS or CF object can't be used as class members or ivars. Only RetainPtr is allowed for CF types regardless of whether ARC is enabled or disabled. Only RetainPtr or OSObjectPtr is allowed for NS types when ARC is disabled.
-.. code-block:: cpp
+```cpp
+struct Foo {
+ NSObject *ptr; // warn
+ dispatch_queue_t queue; // warn
+ // ...
+};
+```
- struct Foo {
- NSObject *ptr; // warn
- dispatch_queue_t queue; // warn
- // ...
- };
+See [WebKit Guidelines for Safer C++ Programming](https://github.com/WebKit/WebKit/wiki/Safer-CPP-Guidelines) for details.
-See `WebKit Guidelines for Safer C++ Programming <https://github.com/WebKit/WebKit/wiki/Safer-CPP-Guidelines>`_ for details.
+#### alpha.webkit.UnretainedLambdaCapturesChecker
-alpha.webkit.UnretainedLambdaCapturesChecker
-""""""""""""""""""""""""""""""""""""""""""""
Raw pointers and references to NS or CF types can't be captured in lambdas. Only RetainPtr is allowed for CF types regardless of whether ARC is enabled or disabled, and only RetainPtr or OSObjectPtr is allowed for NS types when ARC is disabled.
-.. code-block:: cpp
+```cpp
+void foo(NSObject *a, NSObject *b, dispatch_queue_t c) {
+ [&, a](){ // warn about 'a'
+ do_something(b); // warn about 'b'
+ dispatch_queue_get_specific(c, "some"); // warn about 'c'
+ };
+};
+```
- void foo(NSObject *a, NSObject *b, dispatch_queue_t c) {
- [&, a](){ // warn about 'a'
- do_something(b); // warn about 'b'
- dispatch_queue_get_specific(c, "some"); // warn about 'c'
- };
- };
+(alpha-webkit-uncountedcallargschecker)=
-.. _alpha-webkit-UncountedCallArgsChecker:
+#### alpha.webkit.UncountedCallArgsChecker
-alpha.webkit.UncountedCallArgsChecker
-"""""""""""""""""""""""""""""""""""""
The goal of this rule is to make sure that lifetime of any dynamically allocated ref-countable object passed as a call argument spans past the end of the call. This applies to call to any function, method, lambda, function pointer or functor. Ref-countable types aren't supposed to be allocated on stack so we check arguments for parameters of raw pointers and references to uncounted types.
Here are some examples of situations that we warn about as they *might* be potentially unsafe. The logic is that either we're able to guarantee that an argument is safe or it's considered if not a bug then bug-prone.
- .. code-block:: cpp
-
- RefCountable* provide_uncounted();
- void consume(RefCountable*);
-
- // In these cases we can't make sure callee won't directly or indirectly call `deref()` on the argument which could make it unsafe from such point until the end of the call.
-
- void foo1() {
- consume(provide_uncounted()); // warn
- }
-
- void foo2() {
- RefCountable* uncounted = provide_uncounted();
- consume(uncounted); // warn
- }
+> ```cpp
+> RefCountable* provide_uncounted();
+> void consume(RefCountable*);
+>
+> // In these cases we can't make sure callee won't directly or indirectly call `deref()` on the argument which could make it unsafe from such point until the end of the call.
+>
+> void foo1() {
+> consume(provide_uncounted()); // warn
+> }
+>
+> void foo2() {
+> RefCountable* uncounted = provide_uncounted();
+> consume(uncounted); // warn
+> }
+> ```
Although we are enforcing member variables to be ref-counted by `webkit.NoUncountedMemberChecker` any method of the same class still has unrestricted access to these. Since from a caller's perspective we can't guarantee a particular member won't get modified by callee (directly or indirectly) we don't consider values obtained from members safe.
Note: It's likely this heuristic could be made more precise with fewer false positives - for example calls to free functions that don't have any parameter other than the pointer should be safe as the callee won't be able to tamper with the member unless it's a global variable.
- .. code-block:: cpp
-
- struct Foo {
- RefPtr<RefCountable> member;
- void consume(RefCountable*) { /* ... */ }
- void bugprone() {
- consume(member.get()); // warn
- }
- };
+> ```cpp
+> struct Foo {
+> RefPtr<RefCountable> member;
+> void consume(RefCountable*) { /* ... */ }
+> void bugprone() {
+> consume(member.get()); // warn
+> }
+> };
+> ```
The implementation of this rule is a heuristic - we define a whitelist of kinds of values that are considered safe to be passed as arguments. If we can't prove an argument is safe it's considered an error.
@@ -3924,42 +3861,42 @@ Allowed kinds of arguments:
- values obtained from ref-counted objects (including temporaries as those survive the call too)
- .. code-block:: cpp
+ ```cpp
+ RefCountable* provide_uncounted();
+ void consume(RefCountable*);
- RefCountable* provide_uncounted();
- void consume(RefCountable*);
-
- void foo() {
- RefPtr<RefCountable> rc = makeRef(provide_uncounted());
- consume(rc.get()); // ok
- consume(makeRef(provide_uncounted()).get()); // ok
- }
+ void foo() {
+ RefPtr<RefCountable> rc = makeRef(provide_uncounted());
+ consume(rc.get()); // ok
+ consume(makeRef(provide_uncounted()).get()); // ok
+ }
+ ```
- forwarding uncounted arguments from caller to callee
- .. code-block:: cpp
-
- void foo(RefCountable& a) {
- bar(a); // ok
- }
-
- Caller of ``foo()`` is responsible for ``a``'s lifetime.
+ ```cpp
+ void foo(RefCountable& a) {
+ bar(a); // ok
+ }
+ ```
-- ``this`` pointer
+ Caller of `foo()` is responsible for `a`'s lifetime.
- .. code-block:: cpp
+- `this` pointer
- void Foo::foo() {
- baz(this); // ok
- }
+ ```cpp
+ void Foo::foo() {
+ baz(this); // ok
+ }
+ ```
- Caller of ``foo()`` is responsible for keeping the memory pointed to by ``this`` pointer safe.
+ Caller of `foo()` is responsible for keeping the memory pointed to by `this` pointer safe.
- constants
- .. code-block:: cpp
-
- foo(nullptr, NULL, 0); // ok
+ ```cpp
+ foo(nullptr, NULL, 0); // ok
+ ```
We also define a set of safe transformations which if passed a safe value as an input provide (usually it's the return value) a safe value (or an object that provides safe values). This is also a heuristic.
@@ -3967,282 +3904,280 @@ We also define a set of safe transformations which if passed a safe value as an
- getters of ref-counted types
- member overloaded operators
- casts
-- unary operators like ``&`` or ``*``
+- unary operators like `&` or `*`
+
+#### alpha.webkit.UncheckedCallArgsChecker
-alpha.webkit.UncheckedCallArgsChecker
-"""""""""""""""""""""""""""""""""""""
The goal of this rule is to make sure that lifetime of any dynamically allocated CheckedPtr capable object passed as a call argument keeps its memory region past the end of the call. This applies to call to any function, method, lambda, function pointer or functor. CheckedPtr capable objects aren't supposed to be allocated on stack so we check arguments for parameters of raw pointers and references to unchecked types.
The rules of when to use and not to use CheckedPtr / CheckedRef are same as alpha.webkit.UncountedCallArgsChecker for ref-counted objects.
-alpha.webkit.UncheckedLambdaCapturesChecker
-"""""""""""""""""""""""""""""""""""""""""""
+#### alpha.webkit.UncheckedLambdaCapturesChecker
+
Raw pointers and references to unchecked types can't be captured in lambdas. Only CheckedPtr or CheckedRef is allowed.
-.. code-block:: cpp
+```cpp
+struct CheckedObject {
+ void incrementCheckedPtr() {}
+ void decrementCheckedPtr() {}
+};
- struct CheckedObject {
- void incrementCheckedPtr() {}
- void decrementCheckedPtr() {}
- };
+void foo(CheckedObject* a, CheckedObject& b) {
+ [&, a](){ // warn about 'a'
+ do_something(b); // warn about 'b'
+ };
+};
+```
- void foo(CheckedObject* a, CheckedObject& b) {
- [&, a](){ // warn about 'a'
- do_something(b); // warn about 'b'
- };
- };
+#### alpha.webkit.UnretainedCallArgsChecker
-alpha.webkit.UnretainedCallArgsChecker
-""""""""""""""""""""""""""""""""""""""
The goal of this rule is to make sure that lifetime of any dynamically allocated NS or CF objects passed as a call argument keeps its memory region past the end of the call. This applies to call to any function, method, lambda, function pointer or functor. NS or CF objects aren't supposed to be allocated on stack so we check arguments for parameters of raw pointers and references to unretained types.
The rules of when to use and not to use RetainPtr or OSObjectPtr are same as alpha.webkit.UncountedCallArgsChecker for ref-counted objects.
-alpha.webkit.UncountedLocalVarsChecker
-""""""""""""""""""""""""""""""""""""""
+#### alpha.webkit.UncountedLocalVarsChecker
+
The goal of this rule is to make sure that any uncounted local variable is backed by a ref-counted object with lifetime that is strictly larger than the scope of the uncounted local variable. To be on the safe side we require the scope of an uncounted variable to be embedded in the scope of ref-counted object that backs it.
These are examples of cases that we consider safe:
- .. code-block:: cpp
-
- void foo1() {
- RefPtr<RefCountable> counted;
- // The scope of uncounted is EMBEDDED in the scope of counted.
- {
- RefCountable* uncounted = counted.get(); // ok
- }
- }
-
- void foo2(RefPtr<RefCountable> counted_param) {
- RefCountable* uncounted = counted_param.get(); // ok
- }
-
- void FooClass::foo_method() {
- RefCountable* uncounted = this; // ok
- }
+> ```cpp
+> void foo1() {
+> RefPtr<RefCountable> counted;
+> // The scope of uncounted is EMBEDDED in the scope of counted.
+> {
+> RefCountable* uncounted = counted.get(); // ok
+> }
+> }
+>
+> void foo2(RefPtr<RefCountable> counted_param) {
+> RefCountable* uncounted = counted_param.get(); // ok
+> }
+>
+> void FooClass::foo_method() {
+> RefCountable* uncounted = this; // ok
+> }
+> ```
Here are some examples of situations that we warn about as they *might* be potentially unsafe. The logic is that either we're able to guarantee that a local variable is safe or it's considered unsafe.
- .. code-block:: cpp
-
- void foo1() {
- RefCountable* uncounted = new RefCountable; // warn
- }
-
- RefCountable* global_uncounted;
- void foo2() {
- RefCountable* uncounted = global_uncounted; // warn
- }
+> ```cpp
+> void foo1() {
+> RefCountable* uncounted = new RefCountable; // warn
+> }
+>
+> RefCountable* global_uncounted;
+> void foo2() {
+> RefCountable* uncounted = global_uncounted; // warn
+> }
+>
+> void foo3() {
+> RefPtr<RefCountable> counted;
+> // The scope of uncounted is not EMBEDDED in the scope of counted.
+> RefCountable* uncounted = counted.get(); // warn
+> }
+> ```
+
+#### alpha.webkit.UncheckedLocalVarsChecker
- void foo3() {
- RefPtr<RefCountable> counted;
- // The scope of uncounted is not EMBEDDED in the scope of counted.
- RefCountable* uncounted = counted.get(); // warn
- }
-
-alpha.webkit.UncheckedLocalVarsChecker
-""""""""""""""""""""""""""""""""""""""
The goal of this rule is to make sure that any unchecked local variable is backed by a CheckedPtr or CheckedRef with lifetime that is strictly larger than the scope of the unchecked local variable. To be on the safe side we require the scope of an unchecked variable to be embedded in the scope of CheckedPtr/CheckRef object that backs it.
These are examples of cases that we consider safe:
- .. code-block:: cpp
-
- void foo1() {
- CheckedPtr<RefCountable> counted;
- // The scope of uncounted is EMBEDDED in the scope of counted.
- {
- RefCountable* uncounted = counted.get(); // ok
- }
- }
-
- void foo2(CheckedPtr<RefCountable> counted_param) {
- RefCountable* uncounted = counted_param.get(); // ok
- }
-
- void FooClass::foo_method() {
- RefCountable* uncounted = this; // ok
- }
+> ```cpp
+> void foo1() {
+> CheckedPtr<RefCountable> counted;
+> // The scope of uncounted is EMBEDDED in the scope of counted.
+> {
+> RefCountable* uncounted = counted.get(); // ok
+> }
+> }
+>
+> void foo2(CheckedPtr<RefCountable> counted_param) {
+> RefCountable* uncounted = counted_param.get(); // ok
+> }
+>
+> void FooClass::foo_method() {
+> RefCountable* uncounted = this; // ok
+> }
+> ```
Here are some examples of situations that we warn about as they *might* be potentially unsafe. The logic is that either we're able to guarantee that a local variable is safe or it's considered unsafe.
- .. code-block:: cpp
-
- void foo1() {
- RefCountable* uncounted = new RefCountable; // warn
- }
-
- RefCountable* global_uncounted;
- void foo2() {
- RefCountable* uncounted = global_uncounted; // warn
- }
-
- void foo3() {
- RefPtr<RefCountable> counted;
- // The scope of uncounted is not EMBEDDED in the scope of counted.
- RefCountable* uncounted = counted.get(); // warn
- }
+> ```cpp
+> void foo1() {
+> RefCountable* uncounted = new RefCountable; // warn
+> }
+>
+> RefCountable* global_uncounted;
+> void foo2() {
+> RefCountable* uncounted = global_uncounted; // warn
+> }
+>
+> void foo3() {
+> RefPtr<RefCountable> counted;
+> // The scope of uncounted is not EMBEDDED in the scope of counted.
+> RefCountable* uncounted = counted.get(); // warn
+> }
+> ```
+
+#### alpha.webkit.UnretainedLocalVarsChecker
-alpha.webkit.UnretainedLocalVarsChecker
-"""""""""""""""""""""""""""""""""""""""
The goal of this rule is to make sure that any NS or CF local variable is backed by a RetainPtr or OSObjectPtr with lifetime that is strictly larger than the scope of the unretained local variable. To be on the safe side we require the scope of an unretained variable to be embedded in the scope of RetainPtr or OSObjectPtr object that backs it.
The rules of when to use and not to use RetainPtr or OSObjectPtr are same as alpha.webkit.UncountedCallArgsChecker for ref-counted objects.
These are examples of cases that we consider safe:
- .. code-block:: cpp
-
- void foo1() {
- RetainPtr<NSObject> retained;
- // The scope of unretained is EMBEDDED in the scope of retained.
- {
- NSObject* unretained = retained.get(); // ok
- }
- }
-
- void foo2(RetainPtr<NSObject> retained_param) {
- NSObject* unretained = retained_param.get(); // ok
- }
-
- void FooClass::foo_method() {
- NSObject* unretained = this; // ok
- }
+> ```cpp
+> void foo1() {
+> RetainPtr<NSObject> retained;
+> // The scope of unretained is EMBEDDED in the scope of retained.
+> {
+> NSObject* unretained = retained.get(); // ok
+> }
+> }
+>
+> void foo2(RetainPtr<NSObject> retained_param) {
+> NSObject* unretained = retained_param.get(); // ok
+> }
+>
+> void FooClass::foo_method() {
+> NSObject* unretained = this; // ok
+> }
+> ```
Here are some examples of situations that we warn about as they *might* be potentially unsafe. The logic is that either we're able to guarantee that a local variable is safe or it's considered unsafe.
- .. code-block:: cpp
-
- void foo1() {
- NSObject* unretained = [[NSObject alloc] init]; // warn
- }
-
- NSObject* global_unretained;
- void foo2() {
- NSObject* unretained = global_unretained; // warn
- }
-
- void foo3() {
- RetainPtr<NSObject> retained;
- // The scope of unretained is not EMBEDDED in the scope of retained.
- NSObject* unretained = retained.get(); // warn
- }
+> ```cpp
+> void foo1() {
+> NSObject* unretained = [[NSObject alloc] init]; // warn
+> }
+>
+> NSObject* global_unretained;
+> void foo2() {
+> NSObject* unretained = global_unretained; // warn
+> }
+>
+> void foo3() {
+> RetainPtr<NSObject> retained;
+> // The scope of unretained is not EMBEDDED in the scope of retained.
+> NSObject* unretained = retained.get(); // warn
+> }
+> ```
+
+#### webkit.RetainPtrCtorAdoptChecker
-webkit.RetainPtrCtorAdoptChecker
-""""""""""""""""""""""""""""""""
The goal of this rule is to make sure the constructors of RetainPtr and OSObjectPtr as well as adoptNS, adoptCF, and adoptOSObject are used correctly.
When creating a RetainPtr or OSObjectPtr with +1 semantics, adoptNS, adoptCF, or adoptOSObject should be used, and in +0 semantics, RetainPtr or OSObjectPtr constructor should be used.
Warn otherwise.
These are examples of cases that we consider correct:
- .. code-block:: cpp
-
- RetainPtr ptr = adoptNS([[NSObject alloc] init]); // ok
- RetainPtr ptr = CGImageGetColorSpace(image); // ok
- OSObjectPtr ptr = adoptOSObject(dispatch_queue_create("some queue", nullptr)); // ok
+> ```cpp
+> RetainPtr ptr = adoptNS([[NSObject alloc] init]); // ok
+> RetainPtr ptr = CGImageGetColorSpace(image); // ok
+> OSObjectPtr ptr = adoptOSObject(dispatch_queue_create("some queue", nullptr)); // ok
+> ```
Here are some examples of cases that we consider incorrect use of RetainPtr constructor and adoptCF
- .. code-block:: cpp
-
- RetainPtr ptr = [[NSObject alloc] init]; // warn
- auto ptr = adoptCF(CGImageGetColorSpace(image)); // warn
- OSObjectPtr ptr = dispatch_queue_create("some queue", nullptr); // warn
+> ```cpp
+> RetainPtr ptr = [[NSObject alloc] init]; // warn
+> auto ptr = adoptCF(CGImageGetColorSpace(image)); // warn
+> OSObjectPtr ptr = dispatch_queue_create("some queue", nullptr); // warn
+> ```
-Debug Checkers
----------------
+## Debug Checkers
-.. _debug-checkers:
+(debug-checkers-1)=
-
-debug
-^^^^^
+### debug
Checkers used for debugging the analyzer.
-:doc:`developer-docs/DebugChecks` page contains a detailed description.
+{doc}`developer-docs/DebugChecks` page contains a detailed description.
+
+(debug-analysisorder)=
-.. _debug-AnalysisOrder:
+#### debug.AnalysisOrder
-debug.AnalysisOrder
-"""""""""""""""""""
Print callbacks that are called during analysis in order.
-.. _debug-ConfigDumper:
+(debug-configdumper)=
+
+#### debug.ConfigDumper
-debug.ConfigDumper
-""""""""""""""""""
Dump config table.
-.. _debug-DumpCFG Display:
+(debug-dumpcfg-display)=
+
+#### debug.DumpCFG Display
-debug.DumpCFG Display
-"""""""""""""""""""""
Control-Flow Graphs.
-.. _debug-DumpCallGraph:
+(debug-dumpcallgraph)=
+
+#### debug.DumpCallGraph
-debug.DumpCallGraph
-"""""""""""""""""""
Display Call Graph.
-.. _debug-DumpCalls:
+(debug-dumpcalls)=
+
+#### debug.DumpCalls
-debug.DumpCalls
-"""""""""""""""
Print calls as they are traversed by the engine.
-.. _debug-DumpDominators:
+(debug-dumpdominators)=
+
+#### debug.DumpDominators
-debug.DumpDominators
-""""""""""""""""""""
Print the dominance tree for a given CFG.
-.. _debug-DumpLiveVars:
+(debug-dumplivevars)=
+
+#### debug.DumpLiveVars
-debug.DumpLiveVars
-""""""""""""""""""
Print results of live variable analysis.
-.. _debug-DumpTraversal:
+(debug-dumptraversal)=
+
+#### debug.DumpTraversal
-debug.DumpTraversal
-"""""""""""""""""""
Print branch conditions as they are traversed by the engine.
-.. _debug-ExprInspection:
+(debug-exprinspection)=
+
+#### debug.ExprInspection
-debug.ExprInspection
-""""""""""""""""""""
Check the analyzer's understanding of expressions.
-.. _debug-Stats:
+(debug-stats)=
+
+#### debug.Stats
-debug.Stats
-"""""""""""
Emit warnings with analyzer statistics.
-.. _debug-TaintTest:
+(debug-tainttest)=
+
+#### debug.TaintTest
-debug.TaintTest
-"""""""""""""""
Mark tainted symbols as such.
-.. _debug-ViewCFG:
+(debug-viewcfg)=
+
+#### debug.ViewCFG
-debug.ViewCFG
-"""""""""""""
View Control-Flow Graphs using GraphViz.
-.. _debug-ViewCallGraph:
+(debug-viewcallgraph)=
+
+#### debug.ViewCallGraph
-debug.ViewCallGraph
-"""""""""""""""""""
View Call Graph using GraphViz.
-.. _debug-ViewExplodedGraph:
+(debug-viewexplodedgraph)=
+
+#### debug.ViewExplodedGraph
-debug.ViewExplodedGraph
-"""""""""""""""""""""""
View Exploded Graphs using GraphViz.
+
diff --git a/clang/docs/analyzer/developer-docs.md b/clang/docs/analyzer/developer-docs.md
index a925cf7ca02e1..0dd0466046ac5 100644
--- a/clang/docs/analyzer/developer-docs.md
+++ b/clang/docs/analyzer/developer-docs.md
@@ -1,15 +1,16 @@
-Developer Docs
-==============
+# Developer Docs
Contents:
-.. toctree::
- :maxdepth: 2
+```{toctree}
+:maxdepth: 2
+
+developer-docs/DebugChecks
+developer-docs/IPA
+developer-docs/InitializerLists
+developer-docs/nullability
+developer-docs/RegionStore
+developer-docs/PerformanceInvestigation
+developer-docs/Statistics
+```
- developer-docs/DebugChecks
- developer-docs/IPA
- developer-docs/InitializerLists
- developer-docs/nullability
- developer-docs/RegionStore
- developer-docs/PerformanceInvestigation
- developer-docs/Statistics
diff --git a/clang/docs/analyzer/developer-docs/DebugChecks.md b/clang/docs/analyzer/developer-docs/DebugChecks.md
index b3b908941317e..831afed6fc4a6 100644
--- a/clang/docs/analyzer/developer-docs/DebugChecks.md
+++ b/clang/docs/analyzer/developer-docs/DebugChecks.md
@@ -1,9 +1,8 @@
-============
-Debug Checks
-============
+# Debug Checks
-.. contents::
- :local:
+```{contents}
+:local: true
+```
The analyzer contains a number of checkers which can aid in debugging. Enable
them by using the "-analyzer-checker=" flag, followed by the name of the
@@ -26,8 +25,7 @@ ambiguity, like this: `-analyze-function="c:@S at Window@F at overloaded#I#"`.
Use the `clang-extdef-mapping` tool to find the USR for different functions.
-General Analysis Dumpers
-========================
+## General Analysis Dumpers
These checkers are used to dump the results of various infrastructural analyses
to stderr. Some checkers also have "view" variants, which will display a graph
@@ -36,26 +34,20 @@ using a 'dot' format viewer (such as Graphviz on macOS) instead.
- debug.DumpCallGraph, debug.ViewCallGraph: Show the call graph generated for
the current translation unit. This is used to determine the order in which to
analyze functions when inlining is enabled.
-
- debug.DumpCFG, debug.ViewCFG: Show the CFG generated for each top-level
function being analyzed.
-
- debug.DumpDominators: Shows the dominance tree for the CFG of each top-level
function.
-
- debug.DumpLiveVars: Show the results of live variable analysis for each
top-level function being analyzed.
-
- debug.DumpLiveExprs: Show the results of live expression analysis for each
top-level function being analyzed.
-
- debug.ViewExplodedGraph: Show the Exploded Graphs generated for the
analysis of different functions in the input translation unit. When there
are several functions analyzed, display one graph per function. Beware
that these graphs may grow very large, even for small functions.
-Path Tracking
-=============
+## Path Tracking
These checkers print information about the path taken by the analyzer engine.
@@ -63,14 +55,11 @@ These checkers print information about the path taken by the analyzer engine.
path traversal. This is indented to show the call stack, but does NOT do any
special handling of branches, meaning different paths could end up
interleaved.
-
- debug.DumpTraversal: Prints the name of each branch statement encountered
during a path traversal ("IfStmt", "WhileStmt", etc). Currently used to check
whether the analysis engine is doing BFS or DFS.
-
-State Checking
-==============
+## State Checking
These checkers will print out information about the analyzer state in the form
of analysis warnings. They are intended for use with the -verify functionality
@@ -80,7 +69,6 @@ in regression tests.
carries taint. At the time of this writing, taint was only introduced by the
checks under experimental.security.taint.TaintPropagation; this checker may
eventually move to the security.taint package.
-
- debug.ExprInspection: Responds to certain function calls, which are modeled
after builtins. These function calls should affect the program state other
than the evaluation of their arguments; to use them, you will need to declare
@@ -89,30 +77,29 @@ in regression tests.
(FIXME: debug.ExprInspection should probably be renamed, since it no longer only
inspects expressions.)
+### ExprInspection checks
-ExprInspection checks
----------------------
-
-- ``void clang_analyzer_eval(bool);``
+- `void clang_analyzer_eval(bool);`
Prints TRUE if the argument is known to have a non-zero value, FALSE if the
argument is known to have a zero or null value, and UNKNOWN if the argument
- isn't sufficiently constrained on this path. You can use this to test other
- values by using expressions like "x == 5". Note that this functionality is
+ isn't sufficiently constrained on this path. You can use this to test other
+ values by using expressions like "x == 5". Note that this functionality is
currently DISABLED in inlined functions, since different calls to the same
inlined function could provide different information, making it difficult to
write proper -verify directives.
- In C, the argument can be typed as 'int' or as '_Bool'.
-
- Example usage::
+ In C, the argument can be typed as 'int' or as '\_Bool'.
- clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}
- if (!x) return;
- clang_analyzer_eval(x); // expected-warning{{TRUE}}
+ Example usage:
+ ```
+ clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}
+ if (!x) return;
+ clang_analyzer_eval(x); // expected-warning{{TRUE}}
+ ```
-- ``void clang_analyzer_checkInlined(bool);``
+- `void clang_analyzer_checkInlined(bool);`
If a call occurs within an inlined function, prints TRUE or FALSE according to
the value of its argument. If a call occurs outside an inlined function,
@@ -128,47 +115,53 @@ ExprInspection checks
also be analyzed as a top-level function (in which case both TRUE and FALSE
would be printed), depending on the value of the -analyzer-inlining option.
- In C, the argument can be typed as 'int' or as '_Bool'.
+ In C, the argument can be typed as 'int' or as '\_Bool'.
- Example usage::
+ Example usage:
- int inlined() {
- clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
- return 42;
- }
+ ```
+ int inlined() {
+ clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
+ return 42;
+ }
- void topLevel() {
- clang_analyzer_checkInlined(false); // no-warning (not inlined)
- int value = inlined();
- // This assertion will not be valid if the previous call was not inlined.
- clang_analyzer_eval(value == 42); // expected-warning{{TRUE}}
- }
+ void topLevel() {
+ clang_analyzer_checkInlined(false); // no-warning (not inlined)
+ int value = inlined();
+ // This assertion will not be valid if the previous call was not inlined.
+ clang_analyzer_eval(value == 42); // expected-warning{{TRUE}}
+ }
+ ```
-- ``void clang_analyzer_warnIfReached();``
+- `void clang_analyzer_warnIfReached();`
Generate a warning if this line of code gets reached by the analyzer.
- Example usage::
+ Example usage:
- if (true) {
- clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
- }
- else {
- clang_analyzer_warnIfReached(); // no-warning
- }
+ ```
+ if (true) {
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ }
+ else {
+ clang_analyzer_warnIfReached(); // no-warning
+ }
+ ```
-- ``void clang_analyzer_numTimesReached();``
+- `void clang_analyzer_numTimesReached();`
Same as above, but include the number of times this call expression
gets reached by the analyzer during the current analysis.
- Example usage::
+ Example usage:
- for (int x = 0; x < 3; ++x) {
- clang_analyzer_numTimesReached(); // expected-warning{{3}}
- }
+ ```
+ for (int x = 0; x < 3; ++x) {
+ clang_analyzer_numTimesReached(); // expected-warning{{3}}
+ }
+ ```
-- ``void clang_analyzer_warnOnDeadSymbol(int);``
+- `void clang_analyzer_warnOnDeadSymbol(int);`
Subscribe for a delayed warning when the symbol that represents the value of
the argument is garbage-collected by the analyzer.
@@ -184,15 +177,16 @@ ExprInspection checks
dying. However, if the argument is not a symbol but a concrete value,
no warning would be issued.
- Example usage::
+ Example usage:
- do {
- int x = generate_some_integer();
- clang_analyzer_warnOnDeadSymbol(x);
- } while(0); // expected-warning{{SYMBOL DEAD}}
+ ```
+ do {
+ int x = generate_some_integer();
+ clang_analyzer_warnOnDeadSymbol(x);
+ } while(0); // expected-warning{{SYMBOL DEAD}}
+ ```
-
-- ``void clang_analyzer_explain(a single argument of any type);``
+- `void clang_analyzer_explain(a single argument of any type);`
This function explains the value of its argument in a human-readable manner
in the warning message. You can make as many overrides of its prototype
@@ -201,51 +195,57 @@ ExprInspection checks
the function declaration is not allowed), you may append an arbitrary suffix
to the function name, without affecting functionality.
- Example usage::
+ Example usage:
- void clang_analyzer_explain(int);
- void clang_analyzer_explain(void *);
+ ```
+ void clang_analyzer_explain(int);
+ void clang_analyzer_explain(void *);
- // Useful in C code
- void clang_analyzer_explain_int(int);
+ // Useful in C code
+ void clang_analyzer_explain_int(int);
- void foo(int param, void *ptr) {
- clang_analyzer_explain(param); // expected-warning{{argument 'param'}}
- clang_analyzer_explain_int(param); // expected-warning{{argument 'param'}}
- if (!ptr)
- clang_analyzer_explain(ptr); // expected-warning{{memory address '0'}}
- }
+ void foo(int param, void *ptr) {
+ clang_analyzer_explain(param); // expected-warning{{argument 'param'}}
+ clang_analyzer_explain_int(param); // expected-warning{{argument 'param'}}
+ if (!ptr)
+ clang_analyzer_explain(ptr); // expected-warning{{memory address '0'}}
+ }
+ ```
-- ``void clang_analyzer_dump( /* a single argument of any type */);``
+- `void clang_analyzer_dump( /* a single argument of any type */);`
Similar to clang_analyzer_explain, but produces a raw dump of the value,
same as SVal::dump().
- Example usage::
+ Example usage:
- void clang_analyzer_dump(int);
- void foo(int x) {
- clang_analyzer_dump(x); // expected-warning{{reg_$0<x>}}
- }
+ ```
+ void clang_analyzer_dump(int);
+ void foo(int x) {
+ clang_analyzer_dump(x); // expected-warning{{reg_$0<x>}}
+ }
+ ```
-- ``size_t clang_analyzer_getExtent(void *);``
+- `size_t clang_analyzer_getExtent(void *);`
This function returns the value that represents the extent of a memory region
pointed to by the argument. This value is often difficult to obtain otherwise,
because no valid code that produces this value. However, it may be useful
for testing purposes, to see how well does the analyzer model region extents.
- Example usage::
+ Example usage:
- void foo() {
- int x, *y;
- size_t xs = clang_analyzer_getExtent(&x);
- clang_analyzer_explain(xs); // expected-warning{{'4'}}
- size_t ys = clang_analyzer_getExtent(&y);
- clang_analyzer_explain(ys); // expected-warning{{'8'}}
- }
+ ```
+ void foo() {
+ int x, *y;
+ size_t xs = clang_analyzer_getExtent(&x);
+ clang_analyzer_explain(xs); // expected-warning{{'4'}}
+ size_t ys = clang_analyzer_getExtent(&y);
+ clang_analyzer_explain(ys); // expected-warning{{'8'}}
+ }
+ ```
-- ``void clang_analyzer_printState();``
+- `void clang_analyzer_printState();`
Dumps the current ProgramState to the stderr. Quickly lookup the program state
at any execution point without ViewExplodedGraph or re-compiling the program.
@@ -254,44 +254,50 @@ ExprInspection checks
produce a warning, so it gets printed on the console before all other
ExprInspection warnings.
- Example usage::
+ Example usage:
- void foo() {
- int x = 1;
- clang_analyzer_printState(); // Read the stderr!
- }
+ ```
+ void foo() {
+ int x = 1;
+ clang_analyzer_printState(); // Read the stderr!
+ }
+ ```
-- ``void clang_analyzer_hashDump(int);``
+- `void clang_analyzer_hashDump(int);`
The analyzer can generate a hash to identify reports. To debug what information
is used to calculate this hash it is possible to dump the hashed string as a
warning of an arbitrary expression using the function above.
- Example usage::
+ Example usage:
- void foo() {
- int x = 1;
- clang_analyzer_hashDump(x); // expected-warning{{hashed string for x}}
- }
+ ```
+ void foo() {
+ int x = 1;
+ clang_analyzer_hashDump(x); // expected-warning{{hashed string for x}}
+ }
+ ```
-- ``void clang_analyzer_denote(int, const char *);``
+- `void clang_analyzer_denote(int, const char *);`
Denotes symbols with strings. A subsequent call to clang_analyzer_express()
will expresses another symbol in terms of these string. Useful for testing
relationships between different symbols.
- Example usage::
+ Example usage:
- void foo(int x) {
- clang_analyzer_denote(x, "$x");
- clang_analyzer_express(x + 1); // expected-warning{{$x + 1}}
- }
+ ```
+ void foo(int x) {
+ clang_analyzer_denote(x, "$x");
+ clang_analyzer_express(x + 1); // expected-warning{{$x + 1}}
+ }
+ ```
-- ``void clang_analyzer_express(int);``
+- `void clang_analyzer_express(int);`
See clang_analyzer_denote().
-- ``void clang_analyzer_isTainted(a single argument of any type);``
+- `void clang_analyzer_isTainted(a single argument of any type);`
Queries the analyzer whether the expression used as argument is tainted or not.
This is useful in tests, where we don't want to issue warning for all tainted
@@ -300,56 +306,62 @@ ExprInspection checks
introduce and let you focus on the `expected-warning`'s that you really care
about.
- Example usage::
+ Example usage:
+
+ ```
+ int read_integer() {
+ int n;
+ clang_analyzer_isTainted(n); // expected-warning{{NO}}
+ scanf("%d", &n);
+ clang_analyzer_isTainted(n); // expected-warning{{YES}}
+ clang_analyzer_isTainted(n + 2); // expected-warning{{YES}}
+ clang_analyzer_isTainted(n > 0); // expected-warning{{YES}}
+ int next_tainted_value = n; // no-warning
+ return n;
+ }
+ ```
- int read_integer() {
- int n;
- clang_analyzer_isTainted(n); // expected-warning{{NO}}
- scanf("%d", &n);
- clang_analyzer_isTainted(n); // expected-warning{{YES}}
- clang_analyzer_isTainted(n + 2); // expected-warning{{YES}}
- clang_analyzer_isTainted(n > 0); // expected-warning{{YES}}
- int next_tainted_value = n; // no-warning
- return n;
- }
+- `clang_analyzer_dumpExtent(a single argument of any type)`
-- ``clang_analyzer_dumpExtent(a single argument of any type)``
-- ``clang_analyzer_dumpElementCount(a single argument of any type)``
+- `clang_analyzer_dumpElementCount(a single argument of any type)`
Dumps out the extent and the element count of the argument.
- Example usage::
+ Example usage:
- void array() {
- int a[] = {1, 3};
- clang_analyzer_dumpExtent(a); // expected-warning {{8 S64b}}
- clang_analyzer_dumpElementCount(a); // expected-warning {{2 S64b}}
- }
+ ```
+ void array() {
+ int a[] = {1, 3};
+ clang_analyzer_dumpExtent(a); // expected-warning {{8 S64b}}
+ clang_analyzer_dumpElementCount(a); // expected-warning {{2 S64b}}
+ }
+ ```
-- ``clang_analyzer_value(a single argument of integer or pointer type)``
+- `clang_analyzer_value(a single argument of integer or pointer type)`
Prints an associated value for the given argument.
Supported argument types are integers, enums and pointers.
The value can be represented either as a range set or as a concrete integer.
- For the rest of the types function prints ``n/a`` (aka not available).
+ For the rest of the types function prints `n/a` (aka not available).
**Note:** This function will print nothing when clang uses Z3 as the
constraint manager (which is an unsupported and badly broken analysis mode
that's distinct from the supported and stable "Z3 refutation" aka "Z3
crosscheck" mode).
- Example usage::
+ Example usage:
- void print(char c, unsigned u) {
- clang_analyzer_value(c); // expected-warning {{8s:{ [-128, 127] }}}
- if(u != 42)
- clang_analyzer_value(u); // expected-warning {{32u:{ [0, 41], [43, 4294967295] }}}
- else
- clang_analyzer_value(u); // expected-warning {{32u:42}}
- }
+ ```
+ void print(char c, unsigned u) {
+ clang_analyzer_value(c); // expected-warning {{8s:{ [-128, 127] }}}
+ if(u != 42)
+ clang_analyzer_value(u); // expected-warning {{32u:{ [0, 41], [43, 4294967295] }}}
+ else
+ clang_analyzer_value(u); // expected-warning {{32u:42}}
+ }
+ ```
-Statistics
-==========
+## Statistics
The debug.Stats checker collects various information about the analysis of each
function, such as how many blocks were reached and if the analyzer timed out.
@@ -359,9 +371,9 @@ statistics within the analyzer engine. Note the Stats checker (which produces at
least one bug report per function) may actually change the values reported by
-analyzer-stats.
-Output testing checkers
-=======================
+## Output testing checkers
- debug.ReportStmts reports a warning at **every** statement, making it a very
useful tool for testing thoroughly bug report construction and output
emission.
+
diff --git a/clang/docs/analyzer/developer-docs/IPA.md b/clang/docs/analyzer/developer-docs/IPA.md
index 7be14f4c2e065..37bf1eb6a8623 100644
--- a/clang/docs/analyzer/developer-docs/IPA.md
+++ b/clang/docs/analyzer/developer-docs/IPA.md
@@ -1,47 +1,41 @@
-Inlining
-========
+# Inlining
There are several options that control which calls the analyzer will consider for
-inlining. The major one is ``-analyzer-config ipa``:
+inlining. The major one is `-analyzer-config ipa`:
-* ``analyzer-config ipa=none`` - All inlining is disabled. This is the only mode
+- `analyzer-config ipa=none` - All inlining is disabled. This is the only mode
available in LLVM 3.1 and earlier and in Xcode 4.3 and earlier.
-
-* ``analyzer-config ipa=basic-inlining`` - Turns on inlining for C functions, C++
- static member functions, and blocks -- essentially, the calls that behave
- like simple C function calls. This is essentially the mode used in
- Xcode 4.4.
-
-* ``analyzer-config ipa=inlining`` - Turns on inlining when we can confidently find
- the function/method body corresponding to the call. (C functions, static
+- `analyzer-config ipa=basic-inlining` - Turns on inlining for C functions, C++
+ : static member functions, and blocks -- essentially, the calls that behave
+ like simple C function calls. This is essentially the mode used in
+ Xcode 4.4.
+- `analyzer-config ipa=inlining` - Turns on inlining when we can confidently find
+ : the function/method body corresponding to the call. (C functions, static
functions, devirtualized C++ methods, Objective-C class methods, Objective-C
instance methods when ExprEngine is confident about the dynamic type of the
instance).
+- `analyzer-config ipa=dynamic` - Inline instance methods for which the type is
+ : determined at runtime and we are not 100% sure that our type info is
+ correct. For virtual calls, inline the most plausible definition.
+- `analyzer-config ipa=dynamic-bifurcate` - Same as -analyzer-config ipa=dynamic,
+ : but the path is split. We inline on one branch and do not inline on the
+ other. This mode does not drop the coverage in cases when the parent class
+ has code that is only exercised when some of its methods are overridden.
-* ``analyzer-config ipa=dynamic`` - Inline instance methods for which the type is
- determined at runtime and we are not 100% sure that our type info is
- correct. For virtual calls, inline the most plausible definition.
-
-* ``analyzer-config ipa=dynamic-bifurcate`` - Same as -analyzer-config ipa=dynamic,
- but the path is split. We inline on one branch and do not inline on the
- other. This mode does not drop the coverage in cases when the parent class
- has code that is only exercised when some of its methods are overridden.
+Currently, `-analyzer-config ipa=dynamic-bifurcate` is the default mode.
-Currently, ``-analyzer-config ipa=dynamic-bifurcate`` is the default mode.
-
-While ``-analyzer-config ipa`` determines in general how aggressively the analyzer
+While `-analyzer-config ipa` determines in general how aggressively the analyzer
will try to inline functions, several additional options control which types of
functions can inlined, in an all-or-nothing way. These options use the
analyzer's configuration table, so they are all specified as follows:
- ``-analyzer-config OPTION=VALUE``
+> `-analyzer-config OPTION=VALUE`
-c++-inlining
-------------
+## c++-inlining
This option controls which C++ member functions may be inlined.
- ``-analyzer-config c++-inlining=[none | methods | constructors | destructors]``
+> `-analyzer-config c++-inlining=[none | methods | constructors | destructors]`
Each of these modes implies that all the previous member function kinds will be
inlined as well; it doesn't make sense to inline destructors without inlining
@@ -56,12 +50,11 @@ destructors will not be inlined. Additionally, no C++ member functions will be
inlined under -analyzer-config ipa=none or -analyzer-config ipa=basic-inlining,
regardless of the setting of the c++-inlining mode.
-c++-template-inlining
-^^^^^^^^^^^^^^^^^^^^^
+### c++-template-inlining
This option controls whether C++ templated functions may be inlined.
- ``-analyzer-config c++-template-inlining=[true | false]``
+> `-analyzer-config c++-template-inlining=[true | false]`
Currently, template functions are considered for inlining by default.
@@ -70,14 +63,13 @@ of false positives, either by considering paths that the caller considers
impossible (by some unstated precondition), or by inlining some but not all
of a deep implementation of a function.
-c++-stdlib-inlining
-^^^^^^^^^^^^^^^^^^^
+### c++-stdlib-inlining
This option controls whether functions from the C++ standard library, including
methods of the container classes in the Standard Template Library, should be
considered for inlining.
- ``-analyzer-config c++-stdlib-inlining=[true | false]``
+> `-analyzer-config c++-stdlib-inlining=[true | false]`
Currently, C++ standard library functions are considered for inlining by
default.
@@ -88,13 +80,12 @@ positive due to poor modeling of the STL leads to a poor user experience, since
most users would not be comfortable adding assertions to system headers in order
to silence analyzer warnings.
-c++-container-inlining
-^^^^^^^^^^^^^^^^^^^^^^
+### c++-container-inlining
This option controls whether constructors and destructors of "container" types
should be considered for inlining.
- ``-analyzer-config c++-container-inlining=[true | false]``
+> `-analyzer-config c++-container-inlining=[true | false]`
Currently, these constructors and destructors are NOT considered for inlining
by default.
@@ -105,21 +96,18 @@ with the latter specified in the C++11 standard. The analyzer currently does a
fairly poor job of modeling certain data structure invariants of container-like
objects. For example, these three expressions should be equivalent:
-
-.. code-block:: cpp
-
- std::distance(c.begin(), c.end()) == 0
- c.begin() == c.end()
- c.empty()
+```cpp
+std::distance(c.begin(), c.end()) == 0
+c.begin() == c.end()
+c.empty()
+```
Many of these issues are avoided if containers always have unknown, symbolic
state, which is what happens when their constructors are treated as opaque.
In the future, we may decide specific containers are "safe" to model through
inlining, or choose to model them directly using checkers instead.
-
-Basics of Implementation
-------------------------
+## Basics of Implementation
The low-level mechanism of inlining a function is handled in
ExprEngine::inlineCall and ExprEngine::processCallExit.
@@ -135,23 +123,18 @@ reasonable steps:
1. The CoreEngine realizes we're at the end of an inlined call and generates a
CallExitBegin node.
-
2. ExprEngine takes over (in processCallExit) and finds the return value of the
function, if it has one. This is bound to the expression that triggered the
call. (In the case of calls without origin expressions, such as destructors,
this step is skipped.)
-
3. Dead symbols and bindings are cleaned out from the state, including any local
bindings.
-
4. A CallExitEnd node is generated, which marks the transition back to the
caller's StackFrame.
-
5. Custom post-call checks are processed and the final nodes are pushed back
onto the work list, so that evaluation of the caller can continue.
-Retry Without Inlining
-^^^^^^^^^^^^^^^^^^^^^^
+### Retry Without Inlining
In some cases, we would like to retry analysis without inlining a particular
call.
@@ -162,31 +145,30 @@ function.
When this situation is detected, we walk up the path to find the first node
before inlining was started and enqueue it on the WorkList with a special
-ReplayWithoutInlining bit added to it (ExprEngine::replayWithoutInlining). The
+ReplayWithoutInlining bit added to it (ExprEngine::replayWithoutInlining). The
path is then re-analyzed from that point without inlining that particular call.
-Deciding When to Inline
-^^^^^^^^^^^^^^^^^^^^^^^
+### Deciding When to Inline
In general, the analyzer attempts to inline as much as possible, since it
-provides a better summary of what actually happens in the program. There are
+provides a better summary of what actually happens in the program. There are
some cases, however, where the analyzer chooses not to inline:
-- If there is no definition available for the called function or method. In
+- If there is no definition available for the called function or method. In
this case, there is no opportunity to inline.
- If the CFG cannot be constructed for a called function, or the liveness
- cannot be computed. These are prerequisites for analyzing a function body,
+ cannot be computed. These are prerequisites for analyzing a function body,
with or without inlining.
- If the StackFrame chain for a given ExplodedNode reaches a maximum cutoff
- depth. This prevents unbounded analysis due to infinite recursion, but also
+ depth. This prevents unbounded analysis due to infinite recursion, but also
serves as a useful cutoff for performance reasons.
-- If the function is variadic. This is not a hard limitation, but an engineering
+- If the function is variadic. This is not a hard limitation, but an engineering
limitation.
- Tracked by: <rdar://problem/12147064> Support inlining of variadic functions
+ Tracked by: \<<rdar://problem/12147064>> Support inlining of variadic functions
- In C++, constructors are not inlined unless the destructor call will be
processed by the ExprEngine. Thus, if the CFG was built without nodes for
@@ -199,7 +181,7 @@ some cases, however, where the analyzer chooses not to inline:
or operator 'delete', nor does it inline the constructors and destructors
associated with these. See "C++ Caveats" below.
-- Calls resulting in "dynamic dispatch" are specially handled. See more below.
+- Calls resulting in "dynamic dispatch" are specially handled. See more below.
- The FunctionSummaries map stores additional information about declarations,
some of which is collected at runtime based on previous analyses.
@@ -207,9 +189,7 @@ some cases, however, where the analyzer chooses not to inline:
context (for example, if the maximum block count was exceeded; see
"Retry Without Inlining").
-
-Dynamic Calls and Devirtualization
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+### Dynamic Calls and Devirtualization
"Dynamic" calls are those that are resolved at runtime, such as C++ virtual
method calls and Objective-C message sends. Due to the path-sensitive nature of
@@ -217,18 +197,17 @@ the analysis, the analyzer may be able to reason about the dynamic type of the
object whose method is being called and thus "devirtualize" the call.
This path-sensitive devirtualization occurs when the analyzer can determine what
-method would actually be called at runtime. This is possible when the type
+method would actually be called at runtime. This is possible when the type
information is constrained enough for a simulated C++/Objective-C object that
the analyzer can make such a decision.
-DynamicTypeInfo
-^^^^^^^^^^^^^^^
+### DynamicTypeInfo
As the analyzer analyzes a path, it may accrue information to refine the
-knowledge about the type of an object. This can then be used to make better
+knowledge about the type of an object. This can then be used to make better
decisions about the target method of a call.
-Such type information is tracked as DynamicTypeInfo. This is path-sensitive
+Such type information is tracked as DynamicTypeInfo. This is path-sensitive
data that is stored in ProgramState, which defines a mapping from MemRegions to
an (optional) DynamicTypeInfo.
@@ -236,26 +215,26 @@ If no DynamicTypeInfo has been explicitly set for a MemRegion, it will be lazily
inferred from the region's type or associated symbol. Information from symbolic
regions is weaker than from true typed regions.
- EXAMPLE: A C++ object declared "A obj" is known to have the class 'A', but a
- reference "A &ref" may dynamically be a subclass of 'A'.
+> EXAMPLE: A C++ object declared "A obj" is known to have the class 'A', but a
+>
+> : reference "A &ref" may dynamically be a subclass of 'A'.
The DynamicTypePropagation checker gathers and propagates DynamicTypeInfo,
updating it as information is observed along a path that can refine that type
information for a region.
- WARNING: Not all of the existing analyzer code has been retrofitted to use
- DynamicTypeInfo, nor is it universally appropriate. In particular,
- DynamicTypeInfo always applies to a region with all casts stripped
- off, but sometimes the information provided by casts can be useful.
-
+> WARNING: Not all of the existing analyzer code has been retrofitted to use
+>
+> : DynamicTypeInfo, nor is it universally appropriate. In particular,
+> DynamicTypeInfo always applies to a region with all casts stripped
+> off, but sometimes the information provided by casts can be useful.
-RuntimeDefinition
-^^^^^^^^^^^^^^^^^
+### RuntimeDefinition
The basis of devirtualization is CallEvent's getRuntimeDefinition() method,
-which returns a RuntimeDefinition object. When asked to provide a definition,
+which returns a RuntimeDefinition object. When asked to provide a definition,
the CallEvents for dynamic calls will use the DynamicTypeInfo in their
-ProgramState to attempt to devirtualize the call. In the case of no dynamic
+ProgramState to attempt to devirtualize the call. In the case of no dynamic
dispatch, or perfectly constrained devirtualization, the resulting
RuntimeDefinition contains a Decl corresponding to the definition of the called
function, and RuntimeDefinition::mayHaveOtherDefinitions will return FALSE.
@@ -267,17 +246,16 @@ corresponding to the object being called (i.e., the "receiver" in Objective-C
parlance), which ExprEngine uses to decide whether or not the call should be
inlined.
-Inlining Dynamic Calls
-^^^^^^^^^^^^^^^^^^^^^^
+### Inlining Dynamic Calls
The -analyzer-config ipa option has five different modes: none, basic-inlining,
inlining, dynamic, and dynamic-bifurcate. Under -analyzer-config ipa=dynamic,
all dynamic calls are inlined, whether we are certain or not that this will
actually be the definition used at runtime. Under -analyzer-config ipa=inlining,
-only "near-perfect" devirtualized calls are inlined*, and other dynamic calls
+only "near-perfect" devirtualized calls are inlined\*, and other dynamic calls
are evaluated conservatively (as if no definition were available).
-* Currently, no Objective-C messages are not inlined under
+- Currently, no Objective-C messages are not inlined under
-analyzer-config ipa=inlining, even if we are reasonably confident of the type
of the receiver. We plan to enable this once we have tested our heuristics
more thoroughly.
@@ -290,11 +268,9 @@ As stated above, -analyzer-config ipa=basic-inlining does not inline any C++
member functions or Objective-C method calls, even if they are non-virtual or
can be safely devirtualized.
+### Bifurcation
-Bifurcation
-^^^^^^^^^^^
-
-ExprEngine::BifurcateCall implements the ``-analyzer-config ipa=dynamic-bifurcate``
+ExprEngine::BifurcateCall implements the `-analyzer-config ipa=dynamic-bifurcate`
mode.
When a call is made on an object with imprecise dynamic type information
@@ -304,19 +280,18 @@ RuntimeDefinition object) with a path-sensitive "mode" in the ProgramState.
Currently, there are 2 modes:
-* ``DynamicDispatchModeInlined`` - Models the case where the dynamic type information
- of the receiver (MemoryRegion) is assumed to be perfectly constrained so
- that a given definition of a method is expected to be the code actually
- called. When this mode is set, ExprEngine uses the Decl from
- RuntimeDefinition to inline any dynamically dispatched call sent to this
- receiver because the function definition is considered to be fully resolved.
-
-* ``DynamicDispatchModeConservative`` - Models the case where the dynamic type
- information is assumed to be incorrect, for example, implies that the method
- definition is overridden in a subclass. In such cases, ExprEngine does not
- inline the methods sent to the receiver (MemoryRegion), even if a candidate
- definition is available. This mode is conservative about simulating the
- effects of a call.
+- `DynamicDispatchModeInlined` - Models the case where the dynamic type information
+ : of the receiver (MemoryRegion) is assumed to be perfectly constrained so
+ that a given definition of a method is expected to be the code actually
+ called. When this mode is set, ExprEngine uses the Decl from
+ RuntimeDefinition to inline any dynamically dispatched call sent to this
+ receiver because the function definition is considered to be fully resolved.
+- `DynamicDispatchModeConservative` - Models the case where the dynamic type
+ : information is assumed to be incorrect, for example, implies that the method
+ definition is overridden in a subclass. In such cases, ExprEngine does not
+ inline the methods sent to the receiver (MemoryRegion), even if a candidate
+ definition is available. This mode is conservative about simulating the
+ effects of a call.
Going forward along the symbolic execution path, ExprEngine consults the mode
of the receiver's MemRegion to make decisions on whether the calls should be
@@ -328,29 +303,24 @@ class is subclassed. The disadvantages of this mode are a (considerable?)
performance hit and the possibility of false positives on the path where the
conservative mode is used.
-Objective-C Message Heuristics
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+### Objective-C Message Heuristics
ExprEngine relies on a set of heuristics to partition the set of Objective-C
method calls into those that require bifurcation and those that do not. Below
are the cases when the DynamicTypeInfo of the object is considered precise
(cannot be a subclass):
- - If the object was created with +alloc or +new and initialized with an -init
- method.
-
- - If the calls are property accesses using dot syntax. This is based on the
- assumption that children rarely override properties, or do so in an
- essentially compatible way.
-
- - If the class interface is declared inside the main source file. In this case
- it is unlikely that it will be subclassed.
+> - If the object was created with +alloc or +new and initialized with an -init
+> method.
+> - If the calls are property accesses using dot syntax. This is based on the
+> assumption that children rarely override properties, or do so in an
+> essentially compatible way.
+> - If the class interface is declared inside the main source file. In this case
+> it is unlikely that it will be subclassed.
+> - If the method is not declared outside of main source file, either by the
+> receiver's class or by any superclasses.
- - If the method is not declared outside of main source file, either by the
- receiver's class or by any superclasses.
-
-C++ Caveats
-^^^^^^^^^^^
+### C++ Caveats
C++11 [class.cdtor]p4 describes how the vtable of an object is modified as it is
being constructed or destructed; that is, the type of the object depends on
@@ -359,21 +329,17 @@ DynamicTypeInfo in the DynamicTypePropagation checker.
There are several limitations in the current implementation:
-* Temporaries are poorly modeled right now because we're not confident in the
+- Temporaries are poorly modeled right now because we're not confident in the
placement of their destructors in the CFG. We currently won't inline their
constructors unless the destructor is trivial, and don't process their
destructors at all, not even to invalidate the region.
-
-* 'new' is poorly modeled due to some nasty CFG/design issues. This is tracked
- in PR12014. 'delete' is not modeled at all.
-
-* Arrays of objects are modeled very poorly right now. ExprEngine currently
+- 'new' is poorly modeled due to some nasty CFG/design issues. This is tracked
+ in PR12014. 'delete' is not modeled at all.
+- Arrays of objects are modeled very poorly right now. ExprEngine currently
only simulates the first constructor and first destructor. Because of this,
ExprEngine does not inline any constructors or destructors for arrays.
-
-CallEvent
-^^^^^^^^^
+### CallEvent
A CallEvent represents a specific call to a function, method, or other body of
code. It is path-sensitive, containing both the current state (ProgramStateRef)
@@ -381,16 +347,18 @@ and stack space (StackFrame), and provides uniform access to the argument
values and return type of a call, no matter how the call is written in the
source or what sort of code body is being invoked.
- NOTE: For those familiar with Cocoa, CallEvent is roughly equivalent to
- NSInvocation.
+> NOTE: For those familiar with Cocoa, CallEvent is roughly equivalent to
+>
+> : NSInvocation.
CallEvent should be used whenever there is logic dealing with function calls
that does not care how the call occurred.
Examples include checking that arguments satisfy preconditions (such as
-__attribute__((nonnull))), and attempting to inline a call.
+\_\_attribute\_\_((nonnull))), and attempting to inline a call.
CallEvents are reference-counted objects managed by a CallEventManager. While
there is no inherent issue with persisting them (say, in a ProgramState's GDM),
they are intended for short-lived use, and can be recreated from CFGElements or
non-top-level StackFrames fairly easily.
+
diff --git a/clang/docs/analyzer/developer-docs/InitializerLists.md b/clang/docs/analyzer/developer-docs/InitializerLists.md
index f91cdb19ce8bb..06e0e08ca4b6e 100644
--- a/clang/docs/analyzer/developer-docs/InitializerLists.md
+++ b/clang/docs/analyzer/developer-docs/InitializerLists.md
@@ -1,7 +1,6 @@
-================
-Initializer List
-================
-This discussion took place in https://reviews.llvm.org/D35216
+# Initializer List
+
+This discussion took place in <https://reviews.llvm.org/D35216>
"Escape symbols when creating std::initializer_list".
It touches problems of modelling C++ standard library constructs in general,
@@ -23,11 +22,11 @@ passed into initializer list expressions to immediately escape.
This fix is overly conservative though. So i did a bit of investigation as to
how model std::initializer_list better.
-According to the standard, ``std::initializer_list<T>`` is an object that has
-methods ``begin(), end(), and size()``, where ``begin()`` returns a pointer to continuous
-array of ``size()`` objects of type T, and end() is equal to begin() plus size().
+According to the standard, `std::initializer_list<T>` is an object that has
+methods `begin(), end(), and size()`, where `begin()` returns a pointer to continuous
+array of `size()` objects of type T, and end() is equal to begin() plus size().
The standard does hint that it should be possible to implement
-``std::initializer_list<T>`` as a pair of pointers, or as a pointer and a size
+`std::initializer_list<T>` as a pair of pointers, or as a pointer and a size
integer, however specific fields that the object would contain are an
implementation detail.
@@ -36,21 +35,21 @@ Or, at least, it should be possible to explain to the analyzer that the list
somehow "takes hold" of the values put into it. Initializer lists can also be
copied, which is a separate story that i'm not trying to address here.
-The obvious approach to modeling ``std::initializer_list`` in a checker would be to
+The obvious approach to modeling `std::initializer_list` in a checker would be to
construct a SymbolMetadata for the memory region of the initializer list object,
-which would be of type ``T*`` and represent ``begin()``, so we'd trivially model ``begin()``
+which would be of type `T*` and represent `begin()`, so we'd trivially model `begin()`
as a function that returns this symbol. The array pointed to by that symbol
-would be ``bindLoc()``ed to contain the list's contents (probably as a ``CompoundVal``
+would be ``` bindLoc()``ed to contain the list's contents (probably as a ``CompoundVal ```
to produce less bindings in the store). Extent of this array would represent
-``size()`` and would be equal to the length of the list as written.
+`size()` and would be equal to the length of the list as written.
So this sounds good, however apparently it does nothing to address our false
-positives: when the list escapes, our ``RegionStoreManager`` is not magically
+positives: when the list escapes, our `RegionStoreManager` is not magically
guessing that the metadata symbol attached to it, together with its contents,
should also escape. In fact, it's impossible to trigger a pointer escape from
within the checker.
-Approach (1): If only we enabled ``ProgramState::bindLoc(..., notifyChanges=true)``
+Approach (1): If only we enabled `ProgramState::bindLoc(..., notifyChanges=true)`
to cause pointer escapes (not only region changes) (which sounds like the right
thing to do anyway) such checker would be able to solve the false positives by
triggering escapes when binding list elements to the list. However, it'd be as
@@ -74,7 +73,7 @@ to escape. This puts a stress on the checkers, but with a smart data map it
wouldn't be a problem.
Approach (4): We could allow checkers to trigger pointer escapes in arbitrary
-moments. If we allow doing this within ``checkPointerEscape`` callback itself, we
+moments. If we allow doing this within `checkPointerEscape` callback itself, we
would be able to express facts like "when this region escapes, that metadata
symbol attached to it should also escape". This sounds like an ultimate freedom,
with maximum stress on the checkers - still not too much stress when we have
@@ -87,10 +86,9 @@ performance overhead, and clarity seems nice.
At this point, I am a bit wondering about two questions.
-* When should something belong to a checker and when should something belong to the engine?
+- When should something belong to a checker and when should something belong to the engine?
Sometimes we model library aspects in the engine and model language constructs in checkers.
-
-* What is the checker programming model that we are aiming for? Maximum freedom or more easy checker development?
+- What is the checker programming model that we are aiming for? Maximum freedom or more easy checker development?
I think if we aim for maximum freedom, we do not need to worry about the
potential stress on checkers, and we can introduce abstractions to mitigate that
@@ -102,10 +100,9 @@ of complicating the API.
Right now I have no preference or objections between the alternatives but there
are some random thoughts:
-* Maybe it would be great to have a guideline how to evolve the analyzer and
+- Maybe it would be great to have a guideline how to evolve the analyzer and
follow it, so it can help us to decide in similar situations
-
-* I do care about performance in this case. The reason is that we have a
+- I do care about performance in this case. The reason is that we have a
limited performance budget. And I think we should not expect most of the checker
writers to add modeling of language constructs. So, in my opinion, it is ok to
have less nice/more verbose API for language modeling if we can have better
@@ -115,7 +112,7 @@ are some random thoughts:
**Artem:** These are some great questions, i guess it'd be better to discuss
them more openly. As a quick dump of my current mood:
-* To me it seems obvious that we need to aim for a checker API that is both
+- To me it seems obvious that we need to aim for a checker API that is both
simple and powerful. This can probably by keeping the API as powerful as
necessary while providing a layer of simple ready-made solutions on top of it.
Probably a few reusable components for assembling checkers. And this layer
@@ -123,23 +120,21 @@ them more openly. As a quick dump of my current mood:
extend it when something is lacking, instead of falling back to the complex
omnipotent API. I'm thinking of AST matchers vs. AST visitors as a roughly
similar situation: matchers are not omnipotent, but they're so nice.
-
-* Separation between core and checkers is usually quite strange. Once we have
+- Separation between core and checkers is usually quite strange. Once we have
shared state traits, i generally wouldn't mind having region store or range
constraint manager as checkers (though it's probably not worth it to transform
them - just a mood). The main thing to avoid here would be the situation when
the checker overwrites stuff written by the core because it thinks it has a
better idea what's going on, so the core should provide a good default behavior.
-
-* Yeah, i totally care about performance as well, and if i try to implement
+- Yeah, i totally care about performance as well, and if i try to implement
approach, i'd make sure it's good.
**Artem:**
-> Approach (2): We could teach the Store to scan itself for bindings to
-> metadata-symbolic-based regions during scanReachableSymbols() whenever
-> a region turns out to be reachable. This requires no work on checker side,
-> but it sounds performance-heavy.
+\> Approach (2): We could teach the Store to scan itself for bindings to
+\> metadata-symbolic-based regions during scanReachableSymbols() whenever
+\> a region turns out to be reachable. This requires no work on checker side,
+\> but it sounds performance-heavy.
Nope, this approach is wrong. Metadata symbols may become out-of-date: when the
object changes, metadata symbols attached to it aren't changing (because symbols
@@ -148,7 +143,7 @@ value in different moments of time, but at most one of them represents the
actual metadata value. So we'd be escaping more stuff than necessary.
If only we had "ghost fields"
-(https://lists.llvm.org/pipermail/cfe-dev/2016-May/049000.html), it would have
+(<https://lists.llvm.org/pipermail/cfe-dev/2016-May/049000.html>), it would have
been much easier, because the ghost field would only contain the actual
metadata, and the Store would always know about it. This example adds to my
belief that ghost fields are exactly what we need for most C++ checkers.
@@ -162,7 +157,7 @@ with different identifiers. This wouldn't specify how the memory is reachable,
but it would allow for transfer functions to get at those regions and it would
allow for invalidation.
-For ``std::initializer_list`` this reachable region would the region for the backing
+For `std::initializer_list` this reachable region would the region for the backing
array and the transfer functions for begin() and end() yield the beginning and
end element regions for it.
@@ -188,18 +183,18 @@ invalidation for free.
**Artem:**
-> In this case, I would be fine with some sort of ``AbstractStorageMemoryRegion``
-> that meant "here is a memory region and somewhere reachable from here exists
-> another region of type T". Or even multiple regions with different
-> identifiers. This wouldn't specify how the memory is reachable, but it would
-> allow for transfer functions to get at those regions and it would allow for
-> invalidation.
+\> In this case, I would be fine with some sort of `AbstractStorageMemoryRegion`
+\> that meant "here is a memory region and somewhere reachable from here exists
+\> another region of type T". Or even multiple regions with different
+\> identifiers. This wouldn't specify how the memory is reachable, but it would
+\> allow for transfer functions to get at those regions and it would allow for
+\> invalidation.
Yeah, this is what we can easily implement now as a
symbolic-region-based-on-a-metadata-symbol (though we can make a new region
class for that if we eg. want it typed). The problem is that the relation
between such storage region and its parent object region is essentially
-immaterial, similarly to the relation between ``SymbolRegionValue`` and its parent
+immaterial, similarly to the relation between `SymbolRegionValue` and its parent
region. Region contents are mutable: today the abstract storage is reachable
from its parent object, tomorrow it's not, and maybe something else becomes
reachable, something that isn't even abstract. So the parent region for the
@@ -207,9 +202,9 @@ abstract storage is most of the time at best a "nice to know" thing - we cannot
rely on it to do any actual work. We'd anyway need to rely on the checker to do
the job.
-> For std::initializer_list this reachable region would the region for the
-> backing array and the transfer functions for begin() and end() yield the
-> beginning and end element regions for it.
+\> For std::initializer_list this reachable region would the region for the
+\> backing array and the transfer functions for begin() and end() yield the
+\> beginning and end element regions for it.
So maybe in fact for std::initializer_list it may work fine because you cannot
change the data after the object is constructed - so this region's contents are
@@ -217,30 +212,30 @@ essentially immutable. For the future, i feel as if it is a dead end.
I'd like to consider another funny example. Suppose we're trying to model
-.. code-block:: cpp
-
- std::unique_ptr. Consider::
-
- void bar(const std::unique_ptr<int> &x);
-
- void foo(std::unique_ptr<int> &x) {
- int *a = x.get(); // (a, 0, direct): &AbstractStorageRegion
- *a = 1; // (AbstractStorageRegion, 0, direct): 1 S32b
- int *b = new int;
- *b = 2; // (SymRegion{conj_$0<int *>}, 0 ,direct): 2 S32b
- x.reset(b); // Checker map: x -> SymRegion{conj_$0<int *>}
- bar(x); // 'a' doesn't escape (the pointer was unique), 'b' does.
- clang_analyzer_eval(*a == 1); // Making this true is up to the checker.
- clang_analyzer_eval(*b == 2); // Making this unknown is up to the checker.
- }
-
-The checker doesn't totally need to ensure that ``*a == 1`` passes - even though the
-pointer was unique, it could theoretically have ``.get()``-ed above and the code
+```cpp
+std::unique_ptr. Consider::
+
+ void bar(const std::unique_ptr<int> &x);
+
+ void foo(std::unique_ptr<int> &x) {
+ int *a = x.get(); // (a, 0, direct): &AbstractStorageRegion
+ *a = 1; // (AbstractStorageRegion, 0, direct): 1 S32b
+ int *b = new int;
+ *b = 2; // (SymRegion{conj_$0<int *>}, 0 ,direct): 2 S32b
+ x.reset(b); // Checker map: x -> SymRegion{conj_$0<int *>}
+ bar(x); // 'a' doesn't escape (the pointer was unique), 'b' does.
+ clang_analyzer_eval(*a == 1); // Making this true is up to the checker.
+ clang_analyzer_eval(*b == 2); // Making this unknown is up to the checker.
+ }
+```
+
+The checker doesn't totally need to ensure that `*a == 1` passes - even though the
+pointer was unique, it could theoretically have `.get()`-ed above and the code
could of course break the uniqueness invariant (though we'd probably want it).
-The checker can say that "even if ``*a`` did escape, it was not because it was
+The checker can say that "even if `*a` did escape, it was not because it was
stuffed directly into bar()".
-The checker's direct responsibility, however, is to solve the ``*b == 2`` thing
+The checker's direct responsibility, however, is to solve the `*b == 2` thing
(which is in fact the problem we're dealing with in this patch - escaping the
storage region of the object).
@@ -259,18 +254,18 @@ would be their superregion) is actually useful, the mutability of their contents
is expressed naturally, and the store automagically sees reachable symbols, live
symbols, escapes, invalidations, whatever.
-> In my view this differs from ghost variables in that (1) this storage does
-> actually exist (it is just a library implementation detail where that storage
-> lives) and (2) it is perfectly valid for a pointer into that storage to be
-> returned and for another part of the program to read or write from that
-> storage. (Well, in this case just read since it is allowed to be read-only
-> memory).
+\> In my view this differs from ghost variables in that (1) this storage does
+\> actually exist (it is just a library implementation detail where that storage
+\> lives) and (2) it is perfectly valid for a pointer into that storage to be
+\> returned and for another part of the program to read or write from that
+\> storage. (Well, in this case just read since it is allowed to be read-only
+\> memory).
-> What I'm not OK with is modeling abstract analysis state (for example, the
-> count of a NSMutableArray or the typestate of a file handle) as a value stored
-> in some ginned up region in the store.This takes an easy problem that the
-> analyzer does well at (modeling typestate) and turns it into a hard one that
-> the analyzer is bad at (reasoning about the contents of the heap).
+\> What I'm not OK with is modeling abstract analysis state (for example, the
+\> count of a NSMutableArray or the typestate of a file handle) as a value stored
+\> in some ginned up region in the store.This takes an easy problem that the
+\> analyzer does well at (modeling typestate) and turns it into a hard one that
+\> the analyzer is bad at (reasoning about the contents of the heap).
Yeah, i tend to agree on that. For simple typestates, this is probably an
overkill, so let's definitely put aside the idea of "ghost symbolic regions"
@@ -283,13 +278,13 @@ have a choice between re-doing this modeling in every such checker (which is
something analyzer is indeed good at, but at a price of making checkers heavy)
or instead relying on the Store to do exactly what it's designed to do.
-> I think the key criterion here is: "is the region accessible from outside
-> the library". That is, does the library expose the region as a pointer that
-> can be read to or written from in the client program? If so, then it makes
-> sense for this to be in the store: we are modeling reachable storage as
-> storage. But if we're just modeling arbitrary analysis facts that need to be
-> invalidated when a pointer escapes then we shouldn't try to gin up storage
-> for them just to get invalidation for free.
+\> I think the key criterion here is: "is the region accessible from outside
+\> the library". That is, does the library expose the region as a pointer that
+\> can be read to or written from in the client program? If so, then it makes
+\> sense for this to be in the store: we are modeling reachable storage as
+\> storage. But if we're just modeling arbitrary analysis facts that need to be
+\> invalidated when a pointer escapes then we shouldn't try to gin up storage
+\> for them just to get invalidation for free.
As a metaphor, i'd probably compare it to body farms - the difference between
ghost member variables and metadata symbols seems to me like the difference
@@ -299,7 +294,7 @@ FunctionDecl's body in a body farm to have a local variable, even if such
variable doesn't actually exist, even if it cannot be seen from outside the
function call. I'm not seeing immediate practical difference between "it does
actually exist" and "it doesn't actually exist, just a handy abstraction".
-Similarly, i think it's fine if we have a ``CXXRecordDecl`` with
+Similarly, i think it's fine if we have a `CXXRecordDecl` with
implementation-defined contents, and try to farm up a member variable as a handy
abstraction (we don't even need to know its name or offset, only that it's there
somewhere).
@@ -309,7 +304,7 @@ somewhere).
We've discussed it in person with Devin, and he provided more points to think
about:
-* If the initializer list consists of non-POD data, constructors of list's
+- If the initializer list consists of non-POD data, constructors of list's
objects need to take the sub-region of the list's region as this-region In the
current (v2) version of this patch, these objects are constructed elsewhere and
then trivial-copied into the list's metadata pointer region, which may be
@@ -318,10 +313,10 @@ about:
analyzer's core, which would not be able to predict that it needs to take a
checker-specific region as this-region, which makes it harder, though it might
be mitigated by sharing the checker state traits.
-
-* Because "ghost variables" are not material to the user, we need to somehow
+- Because "ghost variables" are not material to the user, we need to somehow
make super sure that they don't make it into the diagnostic messages.
So, because this needs further digging into overall C++ support and rises too
many questions, i'm delaying a better approach to this problem and will fall
back to the original trivial patch.
+
diff --git a/clang/docs/analyzer/developer-docs/PerformanceInvestigation.md b/clang/docs/analyzer/developer-docs/PerformanceInvestigation.md
index 9956f55777744..3d3ad508e444e 100644
--- a/clang/docs/analyzer/developer-docs/PerformanceInvestigation.md
+++ b/clang/docs/analyzer/developer-docs/PerformanceInvestigation.md
@@ -1,71 +1,70 @@
-=========================
-Performance Investigation
-=========================
+# Performance Investigation
Multiple factors contribute to the time it takes to analyze a file with Clang Static Analyzer.
A translation unit contains multiple entry points, each of which take multiple steps to analyze.
-Performance analysis using ``-ftime-trace``
-===========================================
+## Performance analysis using `-ftime-trace`
-You can add the ``-ftime-trace=file.json`` option to break down the analysis time into individual entry points and steps within each entry point.
-You can explore the generated JSON file in a Chromium browser using the ``chrome://tracing`` URL,
-or using `perfetto <https://ui.perfetto.dev>`_ or `speedscope <https://speedscope.app>`_.
+You can add the `-ftime-trace=file.json` option to break down the analysis time into individual entry points and steps within each entry point.
+You can explore the generated JSON file in a Chromium browser using the `chrome://tracing` URL,
+or using [perfetto](https://ui.perfetto.dev) or [speedscope](https://speedscope.app).
Once you narrow down to specific analysis steps you are interested in, you can more effectively employ heavier profilers,
-such as `Perf <https://perfwiki.github.io/main/>`_ and `Callgrind <https://valgrind.org/docs/manual/cl-manual.html>`_.
+such as [Perf](https://perfwiki.github.io/main/) and [Callgrind](https://valgrind.org/docs/manual/cl-manual.html).
-Each analysis step has a time scope in the trace, corresponds to processing of an exploded node, and is designated with a ``ProgramPoint``.
-If the ``ProgramPoint`` is associated with a location, you can see it on the scope metadata label.
+Each analysis step has a time scope in the trace, corresponds to processing of an exploded node, and is designated with a `ProgramPoint`.
+If the `ProgramPoint` is associated with a location, you can see it on the scope metadata label.
Here is an example of a time trace produced with
-.. code-block:: bash
- :caption: Clang Static Analyzer invocation to generate a time trace of string.c analysis.
+```{code-block} bash
+:caption: Clang Static Analyzer invocation to generate a time trace of string.c analysis.
- clang -cc1 -analyze -verify clang/test/Analysis/string.c \
- -analyzer-checker=core,unix,alpha.unix.cstring,debug.ExprInspection \
- -ftime-trace=trace.json -ftime-trace-granularity=1
+clang -cc1 -analyze -verify clang/test/Analysis/string.c \
+ -analyzer-checker=core,unix,alpha.unix.cstring,debug.ExprInspection \
+ -ftime-trace=trace.json -ftime-trace-granularity=1
+```
-.. image:: ../images/speedscope.png
+```{image} ../images/speedscope.png
+```
On the speedscope screenshot above, under the first time ruler is the bird's-eye view of the entire trace that spans a little over 60 milliseconds.
Under the second ruler (focused on the 18.09-18.13ms time point) you can see a narrowed-down portion.
-The second box ("HandleCode memset...") that spans entire screen (and actually extends beyond it) corresponds to the analysis of ``memset16_region_cast()`` entry point that is defined in the "string.c" test file on line 1627.
+The second box ("HandleCode memset...") that spans entire screen (and actually extends beyond it) corresponds to the analysis of `memset16_region_cast()` entry point that is defined in the "string.c" test file on line 1627.
Below it, you can find multiple sub-scopes each corresponding to processing of a single exploded node.
-- First: a ``PostStmt`` for some statement on line 1634. This scope has a selected subscope "CheckerManager::runCheckersForCallEvent (Pre)" that takes 5 microseconds.
+- First: a `PostStmt` for some statement on line 1634. This scope has a selected subscope "CheckerManager::runCheckersForCallEvent (Pre)" that takes 5 microseconds.
- Four other nodes, too small to be discernible at this zoom level
-- Last on this screenshot: another ``PostStmt`` for a statement on line 1635.
+- Last on this screenshot: another `PostStmt` for a statement on line 1635.
-In addition to the ``-ftime-trace`` option, you can use ``-ftime-trace-granularity`` to fine-tune the time trace.
+In addition to the `-ftime-trace` option, you can use `-ftime-trace-granularity` to fine-tune the time trace.
-- ``-ftime-trace-granularity=NN`` dumps only time scopes that are longer than NN microseconds.
-- ``-ftime-trace-verbose`` enables some additional dumps in the frontend related to template instantiations.
+- `-ftime-trace-granularity=NN` dumps only time scopes that are longer than NN microseconds.
+- `-ftime-trace-verbose` enables some additional dumps in the frontend related to template instantiations.
At the moment, it has no effect on the traces from the static analyzer.
Note: Both Chrome-tracing and speedscope tools might struggle with time traces above 100 MB in size.
Luckily, in most cases the default max-steps boundary of 225 000 produces the traces of approximately that size
for a single entry point.
-You can use ``-analyze-function=get_global_options`` together with ``-ftime-trace`` to narrow down analysis to a specific entry point.
+You can use `-analyze-function=get_global_options` together with `-ftime-trace` to narrow down analysis to a specific entry point.
+## Performance analysis using `perf`
-Performance analysis using ``perf``
-===================================
-
-`Perf <https://perfwiki.github.io/main/>`_ is a tool for conducting sampling-based profiling.
+[Perf](https://perfwiki.github.io/main/) is a tool for conducting sampling-based profiling.
It's easy to start profiling, you only have 2 prerequisites.
-Build with ``-fno-omit-frame-pointer`` and debug info (``-g``).
-You can use release builds, but probably the easiest is to set the ``CMAKE_BUILD_TYPE=RelWithDebInfo``
-along with ``CMAKE_CXX_FLAGS="-fno-omit-frame-pointer"`` when configuring ``llvm``.
-Here is how to `get started <https://llvm.org/docs/CMake.html#quick-start>`_ if you are in trouble.
+Build with `-fno-omit-frame-pointer` and debug info (`-g`).
+You can use release builds, but probably the easiest is to set the `CMAKE_BUILD_TYPE=RelWithDebInfo`
+along with `CMAKE_CXX_FLAGS="-fno-omit-frame-pointer"` when configuring `llvm`.
+Here is how to [get started](https://llvm.org/docs/CMake.html#quick-start) if you are in trouble.
-.. code-block:: bash
- :caption: Running the Clang Static Analyzer through ``perf`` to gather samples of the execution.
+```{code-block} bash
+:caption: Running the Clang Static Analyzer through ``perf`` to gather samples of the
+: execution.
- # -F: Sampling frequency, use `-F max` for maximal frequency
- # -g: Enable call-graph recording for both kernel and user space
- perf record -F 99 -g -- clang -cc1 -analyze -verify clang/test/Analysis/string.c \
- -analyzer-checker=core,unix,alpha.unix.cstring,debug.ExprInspection
+# -F: Sampling frequency, use `-F max` for maximal frequency
+# -g: Enable call-graph recording for both kernel and user space
+perf record -F 99 -g -- clang -cc1 -analyze -verify clang/test/Analysis/string.c \
+ -analyzer-checker=core,unix,alpha.unix.cstring,debug.ExprInspection
+```
Once you have the profile data, you can use it to produce a Flame graph.
A Flame graph is a visual representation of the stack frames of the samples.
@@ -73,65 +72,67 @@ Common stack frame prefixes are squashed together, making up a wider bar.
The wider the bar, the more time was spent under that particular stack frame,
giving a sense of how the overall execution time was spent.
-Clone the `FlameGraph <https://github.com/brendangregg/FlameGraph>`_ git repository,
-as we will use some scripts from there to convert the ``perf`` samples into a Flame graph.
+Clone the [FlameGraph](https://github.com/brendangregg/FlameGraph) git repository,
+as we will use some scripts from there to convert the `perf` samples into a Flame graph.
It's also useful to check out Brendan Gregg's (the author of FlameGraph)
-`homepage <https://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html>`_.
-
-
-.. code-block:: bash
- :caption: Converting the ``perf`` profile into a Flamegraph, then opening it in Firefox.
+[homepage](https://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html).
- perf script | /path/to/FlameGraph/stackcollapse-perf.pl > perf.folded
- /path/to/FlameGraph/flamegraph.pl perf.folded > perf.svg
- firefox perf.svg
+```{code-block} bash
+:caption: Converting the ``perf`` profile into a Flamegraph, then opening it in Firefox.
-.. image:: ../images/flamegraph.png
+perf script | /path/to/FlameGraph/stackcollapse-perf.pl > perf.folded
+/path/to/FlameGraph/flamegraph.pl perf.folded > perf.svg
+firefox perf.svg
+```
+```{image} ../images/flamegraph.png
+```
-Performance analysis using ``uftrace``
-======================================
+## Performance analysis using `uftrace`
-`uftrace <https://github.com/namhyung/uftrace/wiki/Tutorial#getting-started>`_ is a great tool to generate rich profile data
+[uftrace](https://github.com/namhyung/uftrace/wiki/Tutorial#getting-started) is a great tool to generate rich profile data
that you can use to focus and drill down into the timeline of your application.
We will use it to generate Chromium trace JSON.
-In contrast to ``perf``, this approach statically instruments every function, so it should be more precise and thorough than the sampling-based approaches like ``perf``.
-In contrast to using ``-ftime-trace``, functions don't need to opt-in to be profiled using ``llvm::TimeTraceScope``.
+In contrast to `perf`, this approach statically instruments every function, so it should be more precise and thorough than the sampling-based approaches like `perf`.
+In contrast to using `-ftime-trace`, functions don't need to opt-in to be profiled using `llvm::TimeTraceScope`.
All functions are profiled due to automatic static instrumentation.
There is only one prerequisite to use this tool.
-You need to build the binary you are about to instrument using ``-pg`` or ``-finstrument-functions``.
+You need to build the binary you are about to instrument using `-pg` or `-finstrument-functions`.
This will make it run substantially slower but allows rich instrumentation.
It will also consume many gigabites of storage for a single trace unless filter flags are used during recording.
-.. code-block:: bash
- :caption: Recording with ``uftrace``, then dumping the result as a Chrome trace JSON.
+```{code-block} bash
+:caption: Recording with ``uftrace``, then dumping the result as a Chrome trace JSON.
- uftrace record clang -cc1 -analyze -verify clang/test/Analysis/string.c \
- -analyzer-checker=core,unix,alpha.unix.cstring,debug.ExprInspection
- uftrace dump --filter=".*::AnalysisConsumer::HandleTranslationUnit" --time-filter=300 --chrome > trace.json
+uftrace record clang -cc1 -analyze -verify clang/test/Analysis/string.c \
+ -analyzer-checker=core,unix,alpha.unix.cstring,debug.ExprInspection
+uftrace dump --filter=".*::AnalysisConsumer::HandleTranslationUnit" --time-filter=300 --chrome > trace.json
+```
-.. image:: ../images/uftrace_detailed.png
+```{image} ../images/uftrace_detailed.png
+```
-In this picture, you can see the functions below the Static Analyzer's entry point, which takes at least 300 nanoseconds to run, visualized by Chrome's ``about:tracing`` page
+In this picture, you can see the functions below the Static Analyzer's entry point, which takes at least 300 nanoseconds to run, visualized by Chrome's `about:tracing` page
You can also see how deep function calls we may have due to AST visitors.
Using different filters can reduce the number of functions to record.
-For the common options, refer to the ``uftrace`` `documentation <https://github.com/namhyung/uftrace/blob/master/doc/uftrace-record.md#common-options>`_.
+For the common options, refer to the `uftrace` [documentation](https://github.com/namhyung/uftrace/blob/master/doc/uftrace-record.md#common-options).
Similar filters can be applied for dumping too. That way you can reuse the same (detailed)
recording to selectively focus on some special part using a refinement of the filter flags.
-Remember, the trace JSON needs to fit into Chrome's ``about:tracing`` or `speedscope <https://speedscope.app>`_,
+Remember, the trace JSON needs to fit into Chrome's `about:tracing` or [speedscope](https://speedscope.app),
thus it needs to be of a limited size.
If you do not apply filters on recording, you will collect a large trace and every dump operation
would need to sieve through the much larger recording which may be annoying if done repeatedly.
If the trace JSON is still too large to load, have a look at the dump as plain text and look for frequent entries that refer to non-interesting parts.
-Once you have some of those, add them as ``--hide`` flags to the ``uftrace dump`` call.
+Once you have some of those, add them as `--hide` flags to the `uftrace dump` call.
To see what functions appear frequently in the trace, use this command:
-.. code-block:: bash
+```bash
+cat trace.json | grep -Po '"name":"(.+)"' | sort | uniq -c | sort -nr | head -n 50
+```
- cat trace.json | grep -Po '"name":"(.+)"' | sort | uniq -c | sort -nr | head -n 50
+`uftrace` can also dump the report as a Flame graph using `uftrace dump --flame-graph`.
-``uftrace`` can also dump the report as a Flame graph using ``uftrace dump --flame-graph``.
diff --git a/clang/docs/analyzer/developer-docs/RegionStore.md b/clang/docs/analyzer/developer-docs/RegionStore.md
index c963e5b720fe6..5c5a5eaa8ab60 100644
--- a/clang/docs/analyzer/developer-docs/RegionStore.md
+++ b/clang/docs/analyzer/developer-docs/RegionStore.md
@@ -1,13 +1,12 @@
-============
-Region Store
-============
+# Region Store
+
The analyzer "Store" represents the contents of memory regions. It is an opaque
-functional data structure stored in each ``ProgramState``; the only class that
+functional data structure stored in each `ProgramState`; the only class that
can modify the store is its associated StoreManager.
Currently (Feb. 2013), the only StoreManager implementation being used is
-``RegionStoreManager``. This store records bindings to memory regions using a
-"base region + offset" key. (This allows ``*p`` and ``p[0]`` to map to the same
+`RegionStoreManager`. This store records bindings to memory regions using a
+"base region + offset" key. (This allows `*p` and `p[0]` to map to the same
location, among other benefits.)
Regions are grouped into "clusters", which roughly correspond to "regions with
@@ -17,55 +16,51 @@ such as invalidation.
Regions that do not have a known offset use a special "symbolic" offset. These
keys store both the original region, and the "concrete offset region" -- the
last region whose offset is entirely concrete. (For example, in the expression
-``foo.bar[1][i].baz``, the concrete offset region is the array ``foo.bar[1]``,
-since that has a known offset from the start of the top-level ``foo`` struct.)
-
+`foo.bar[1][i].baz`, the concrete offset region is the array `foo.bar[1]`,
+since that has a known offset from the start of the top-level `foo` struct.)
-Binding Invalidation
---------------------
+## Binding Invalidation
Supporting both concrete and symbolic offsets makes things a bit tricky. Here's
an example:
-.. code-block:: cpp
-
- foo[0] = 0;
- foo[1] = 1;
- foo[i] = i;
+```cpp
+foo[0] = 0;
+foo[1] = 1;
+foo[i] = i;
+```
-After the third assignment, nothing can be said about the value of ``foo[0]``,
-because ``foo[i]`` may have overwritten it! Thus, *binding to a region with a
+After the third assignment, nothing can be said about the value of `foo[0]`,
+because `foo[i]` may have overwritten it! Thus, *binding to a region with a
symbolic offset invalidates the entire concrete offset region.* We know
-``foo[i]`` is somewhere within ``foo``, so we don't have to invalidate
+`foo[i]` is somewhere within `foo`, so we don't have to invalidate
anything else, but we do have to be conservative about all other bindings within
-``foo``.
+`foo`.
Continuing the example:
-.. code-block:: cpp
+```cpp
+foo[i] = i;
+foo[0] = 0;
+```
- foo[i] = i;
- foo[0] = 0;
-
-After this latest assignment, nothing can be said about the value of ``foo[i]``,
-because ``foo[0]`` may have overwritten it! *Binding to a region R with a
+After this latest assignment, nothing can be said about the value of `foo[i]`,
+because `foo[0]` may have overwritten it! *Binding to a region R with a
concrete offset invalidates any symbolic offset bindings whose concrete offset
-region is a super-region **or** sub-region of R.* All we know about ``foo[i]``
-is that it is somewhere within ``foo``, so changing *anything* within ``foo``
-might change ``foo[i]``, and changing *all* of ``foo`` (or its base region) will
-*definitely* change ``foo[i]``.
+region is a super-region \*\*or\** sub-region of R.\* All we know about `foo[i]`
+is that it is somewhere within `foo`, so changing *anything* within `foo`
+might change `foo[i]`, and changing *all* of `foo` (or its base region) will
+*definitely* change `foo[i]`.
-This logic could be improved by using the current constraints on ``i``, at the
+This logic could be improved by using the current constraints on `i`, at the
cost of speed. The latter case could also be improved by matching region kinds,
-i.e. changing ``foo[0].a`` is unlikely to affect ``foo[i].b``, no matter what
-``i`` is.
+i.e. changing `foo[0].a` is unlikely to affect `foo[i].b`, no matter what
+`i` is.
-For more detail, read through ``RegionStoreManager::removeSubRegionBindings`` in
+For more detail, read through `RegionStoreManager::removeSubRegionBindings` in
RegionStore.cpp.
-
-ObjCIvarRegions
----------------
+## ObjCIvarRegions
Objective-C instance variables require a bit of special handling. Like struct
fields, they are not base regions, and when their parent object region is
@@ -82,9 +77,7 @@ object, RegionStore offsets are computed from the start of the instance
variable. Thus it is not valid to assume that all bindings with non-symbolic
offsets start from the base region!
-
-Region Invalidation
--------------------
+## Region Invalidation
Unlike binding invalidation, region invalidation occurs when the entire
contents of a region may have changed---say, because it has been passed to a
@@ -97,7 +90,7 @@ arithmetic.
Region invalidation typically does even more than this, however. Because it
usually represents the complete escape of a region from the analyzer's model,
its *contents* must also be transitively invalidated. (For example, if a region
-``p`` of type ``int **`` is invalidated, the contents of ``*p`` and ``**p`` may
+`p` of type `int **` is invalidated, the contents of `*p` and `**p` may
have changed as well.) The algorithm that traverses this transitive closure of
accessible regions is known as ClusterAnalysis, and is also used for finding
all live bindings in the store (in order to throw away the dead ones). The name
@@ -106,9 +99,7 @@ refers to the same concept: during invalidation and liveness analysis, all
bindings within a cluster must be treated in the same way for a conservative
model of program behavior.
-
-Default Bindings
-----------------
+## Default Bindings
Most bindings in RegionStore are simple scalar values -- integers and pointers.
These are known as "Direct" bindings. However, RegionStore supports a second
@@ -123,16 +114,16 @@ the base region is reached, at which point the RegionStore will pick an
appropriate default value for the region (usually a symbolic value, but
sometimes zero, for static data, or "uninitialized", for stack variables).
-.. code-block:: cpp
-
- int manyInts[10];
- manyInts[1] = 42; // Creates a Direct binding for manyInts[1].
- print(manyInts[1]); // Retrieves the Direct binding for manyInts[1];
- print(manyInts[0]); // There is no Direct binding for manyInts[0].
- // Is there a Default binding for the entire array?
- // There is not, but it is a stack variable, so we use
- // "uninitialized" as the default value (and emit a
- // diagnostic!).
+```cpp
+int manyInts[10];
+manyInts[1] = 42; // Creates a Direct binding for manyInts[1].
+print(manyInts[1]); // Retrieves the Direct binding for manyInts[1];
+print(manyInts[0]); // There is no Direct binding for manyInts[0].
+ // Is there a Default binding for the entire array?
+ // There is not, but it is a stack variable, so we use
+ // "uninitialized" as the default value (and emit a
+ // diagnostic!).
+```
NOTE: The fact that bindings are stored as a base region plus an offset limits
the Default Binding strategy, because in C aggregates can contain other
@@ -140,9 +131,7 @@ aggregates. In the current implementation of RegionStore, there is no way to
distinguish a Default binding for an entire aggregate from a Default binding
for the sub-aggregate at offset 0.
-
-Lazy Bindings (LazyCompoundVal)
--------------------------------
+## Lazy Bindings (LazyCompoundVal)
RegionStore implements an optimization for copying aggregates (structs and
arrays) called "lazy bindings", implemented using a special SVal called
@@ -168,16 +157,17 @@ LazyCompoundVal region, and look up *that* region in the previous store.
Here's a concrete example:
-.. code-block:: cpp
-
- CGPoint p;
- p.x = 42; // A Direct binding is made to the FieldRegion 'p.x'.
- CGPoint p2 = p; // A LazyCompoundVal is created for 'p', along with a
- // snapshot of the current store state. This value is then
- // used as a Default binding for the VarRegion 'p2'.
- return p2.x; // The binding for FieldRegion 'p2.x' is requested.
- // There is no Direct binding, so we look for a Default
- // binding to 'p2' and find the LCV.
- // Because it's a LCV, we look at our requested region
- // and see that it's the '.x' field. We ask for the value
- // of 'p.x' within the snapshot, and get back 42.
+```cpp
+CGPoint p;
+p.x = 42; // A Direct binding is made to the FieldRegion 'p.x'.
+CGPoint p2 = p; // A LazyCompoundVal is created for 'p', along with a
+ // snapshot of the current store state. This value is then
+ // used as a Default binding for the VarRegion 'p2'.
+return p2.x; // The binding for FieldRegion 'p2.x' is requested.
+ // There is no Direct binding, so we look for a Default
+ // binding to 'p2' and find the LCV.
+ // Because it's a LCV, we look at our requested region
+ // and see that it's the '.x' field. We ask for the value
+ // of 'p.x' within the snapshot, and get back 42.
+```
+
diff --git a/clang/docs/analyzer/developer-docs/Statistics.md b/clang/docs/analyzer/developer-docs/Statistics.md
index 355759d468282..7d882854f1bd6 100644
--- a/clang/docs/analyzer/developer-docs/Statistics.md
+++ b/clang/docs/analyzer/developer-docs/Statistics.md
@@ -1,32 +1,30 @@
-===================
-Analysis Statistics
-===================
+# Analysis Statistics
Clang Static Analyzer enjoys two facilities to collect statistics: per translation unit and per entry point.
-We use `llvm/ADT/Statistic.h`_ for numbers describing the entire translation unit.
-We use `clang/StaticAnalyzer/Core/PathSensitive/EntryPointStats.h`_ to collect data for each symbolic-execution entry point.
-
-.. _llvm/ADT/Statistic.h: https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/ADT/Statistic.h#L171
-.. _clang/StaticAnalyzer/Core/PathSensitive/EntryPointStats.h: https://github.com/llvm/llvm-project/blob/main/clang/include/clang/StaticAnalyzer/Core/PathSensitive/EntryPointStats.h
+We use [llvm/ADT/Statistic.h][llvm/adt/statistic.h] for numbers describing the entire translation unit.
+We use [clang/StaticAnalyzer/Core/PathSensitive/EntryPointStats.h][clang/staticanalyzer/core/pathsensitive/entrypointstats.h] to collect data for each symbolic-execution entry point.
In many cases, it makes sense to collect statistics on both translation-unit level and entry-point level. You can use the two macros defined in EntryPointStats.h for that:
-- ``STAT_COUNTER`` for additive statistics, for example, "the number of steps executed", "the number of functions inlined".
-- ``STAT_MAX`` for maximizing statistics, for example, "the maximum environment size", or "the longest execution path".
+- `STAT_COUNTER` for additive statistics, for example, "the number of steps executed", "the number of functions inlined".
+- `STAT_MAX` for maximizing statistics, for example, "the maximum environment size", or "the longest execution path".
-If you want to define a statistic that makes sense only for the entire translation unit, for example, "the number of entry points", Statistic.h defines two macros: ``STATISTIC`` and ``ALWAYS_ENABLED_STATISTIC``.
-You should prefer ``ALWAYS_ENABLED_STATISTIC`` unless you have a good reason not to.
-``STATISTIC`` is controlled by ``LLVM_ENABLE_STATS`` / ``LLVM_FORCE_ENABLE_STATS``.
-However, note that with ``LLVM_ENABLE_STATS`` disabled, only storage of the values is disabled, the computations producing those values still carry on unless you took an explicit precaution to make them conditional too.
+If you want to define a statistic that makes sense only for the entire translation unit, for example, "the number of entry points", Statistic.h defines two macros: `STATISTIC` and `ALWAYS_ENABLED_STATISTIC`.
+You should prefer `ALWAYS_ENABLED_STATISTIC` unless you have a good reason not to.
+`STATISTIC` is controlled by `LLVM_ENABLE_STATS` / `LLVM_FORCE_ENABLE_STATS`.
+However, note that with `LLVM_ENABLE_STATS` disabled, only storage of the values is disabled, the computations producing those values still carry on unless you took an explicit precaution to make them conditional too.
If you want to define a statistic only for entry point, EntryPointStats.h has four classes at your disposal:
+- `UnsignedEPStat` - an unsigned value assigned at most once per entry point. For example: "the number of source characters in an entry-point body". If no value is assigned during analysis of an entry point, the corresponding CSV cell will be empty.
+- `CounterEPStat` - an additive statistic. It starts with 0 and you can add to it as many times as needed. For example: "the number of bugs discovered".
+- `UnsignedMaxEPStat` - a maximizing statistic. It starts with 0 and when you join it with a value, it picks the maximum of the previous value and the new one. For example, "the longest execution path of a bug".
-- ``UnsignedEPStat`` - an unsigned value assigned at most once per entry point. For example: "the number of source characters in an entry-point body". If no value is assigned during analysis of an entry point, the corresponding CSV cell will be empty.
-- ``CounterEPStat`` - an additive statistic. It starts with 0 and you can add to it as many times as needed. For example: "the number of bugs discovered".
-- ``UnsignedMaxEPStat`` - a maximizing statistic. It starts with 0 and when you join it with a value, it picks the maximum of the previous value and the new one. For example, "the longest execution path of a bug".
-
-To produce a CSV file with all the statistics collected per entry point, use the ``dump-entry-point-stats-to-csv=<file>.csv`` parameter.
+To produce a CSV file with all the statistics collected per entry point, use the `dump-entry-point-stats-to-csv=<file>.csv` parameter.
Note, EntryPointStats.h is not meant to be complete, and if you feel it is lacking certain kind of statistic, odds are that it does.
Feel free to extend it!
+
+[clang/staticanalyzer/core/pathsensitive/entrypointstats.h]: https://github.com/llvm/llvm-project/blob/main/clang/include/clang/StaticAnalyzer/Core/PathSensitive/EntryPointStats.h
+[llvm/adt/statistic.h]: https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/ADT/Statistic.h#L171
+
diff --git a/clang/docs/analyzer/developer-docs/nullability.md b/clang/docs/analyzer/developer-docs/nullability.md
index dc24793a8f4fc..a51b90ef7a34d 100644
--- a/clang/docs/analyzer/developer-docs/nullability.md
+++ b/clang/docs/analyzer/developer-docs/nullability.md
@@ -1,108 +1,104 @@
-==================
-Nullability Checks
-==================
+# Nullability Checks
This document is a high level description of the nullablility checks.
These checks intended to use the annotations that is described in this
-RFC: https://discourse.llvm.org/t/rfc-nullability-qualifiers/35672
-(`Mailman <https://lists.llvm.org/pipermail/cfe-dev/2015-March/041779.html>`_)
+RFC: <https://discourse.llvm.org/t/rfc-nullability-qualifiers/35672>
+([Mailman](https://lists.llvm.org/pipermail/cfe-dev/2015-March/041779.html))
Let's consider the following 2 categories:
**1) nullable**
-If a pointer ``p`` has a nullable annotation and no explicit null check or assert, we should warn in the following cases:
+If a pointer `p` has a nullable annotation and no explicit null check or assert, we should warn in the following cases:
-* ``p`` gets implicitly converted into nonnull pointer, for example, we are passing it to a function that takes a nonnull parameter.
-* ``p`` gets dereferenced
+- `p` gets implicitly converted into nonnull pointer, for example, we are passing it to a function that takes a nonnull parameter.
+- `p` gets dereferenced
Taking a branch on nullable pointers are the same like taking branch on null unspecified pointers.
Explicit cast from nullable to nonnull:
-.. code-block:: cpp
+```cpp
+__nullable id foo;
+id bar = foo;
+takesNonNull((_nonnull) bar); // should not warn here (backward compatibility hack)
+anotherTakesNonNull(bar); // would be great to warn here, but not necessary(*)
+```
- __nullable id foo;
- id bar = foo;
- takesNonNull((_nonnull) bar); // should not warn here (backward compatibility hack)
- anotherTakesNonNull(bar); // would be great to warn here, but not necessary(*)
-
-Because bar corresponds to the same symbol all the time it is not easy to implement the checker that way the cast only suppress the first call but not the second. For this reason in the first implementation after a contradictory cast happens, I will treat bar as nullable unspecified, this way all of the warnings will be suppressed. Treating the symbol as nullable unspecified also has an advantage that in case the takesNonNull function body is being inlined, the will be no warning, when the symbol is dereferenced. In case I have time after the initial version I might spend additional time to try to find a more sophisticated solution, in which we would produce the second warning (*).
+Because bar corresponds to the same symbol all the time it is not easy to implement the checker that way the cast only suppress the first call but not the second. For this reason in the first implementation after a contradictory cast happens, I will treat bar as nullable unspecified, this way all of the warnings will be suppressed. Treating the symbol as nullable unspecified also has an advantage that in case the takesNonNull function body is being inlined, the will be no warning, when the symbol is dereferenced. In case I have time after the initial version I might spend additional time to try to find a more sophisticated solution, in which we would produce the second warning (\*).
**2) nonnull**
-* Dereferencing a nonnull, or sending message to it is ok.
-* Converting nonnull to nullable is Ok.
-* When there is an explicit cast from nonnull to nullable I will trust the cast (it is probable there for a reason, because this cast does not suppress any warnings or errors).
-* But what should we do about null checks?:
-
-.. code-block:: cpp
-
- __nonnull id takesNonnull(__nonnull id x) {
- if (x == nil) {
- // Defensive backward compatible code:
- ....
- return nil; // Should the analyzer cover this piece of code? Should we require the cast (__nonnull)nil?
- }
- ....
- }
+- Dereferencing a nonnull, or sending message to it is ok.
+- Converting nonnull to nullable is Ok.
+- When there is an explicit cast from nonnull to nullable I will trust the cast (it is probable there for a reason, because this cast does not suppress any warnings or errors).
+- But what should we do about null checks?:
+
+```cpp
+__nonnull id takesNonnull(__nonnull id x) {
+ if (x == nil) {
+ // Defensive backward compatible code:
+ ....
+ return nil; // Should the analyzer cover this piece of code? Should we require the cast (__nonnull)nil?
+ }
+ ....
+}
+```
There are these directions:
-* We can either take the branch; this way the branch is analyzed
-* Should we not warn about any nullability issues in that branch? Probably not, it is ok to break the nullability postconditions when the nullability preconditions are violated.
-* We can assume that these pointers are not null and we lose coverage with the analyzer. (This can be implemented either in constraint solver or in the checker itself.)
+- We can either take the branch; this way the branch is analyzed
+- Should we not warn about any nullability issues in that branch? Probably not, it is ok to break the nullability postconditions when the nullability preconditions are violated.
+- We can assume that these pointers are not null and we lose coverage with the analyzer. (This can be implemented either in constraint solver or in the checker itself.)
Other Issues to keep in mind/take care of:
-* Messaging:
+- Messaging:
- * Sending a message to a nullable pointer
+ - Sending a message to a nullable pointer
- * Even though the method might return a nonnull pointer, when it was sent to a nullable pointer the return type will be nullable.
- * The result is nullable unless the receiver is known to be non null.
+ - Even though the method might return a nonnull pointer, when it was sent to a nullable pointer the return type will be nullable.
+ : - The result is nullable unless the receiver is known to be non null.
- * Sending a message to an unspecified or nonnull pointer
+ - Sending a message to an unspecified or nonnull pointer
- * If the pointer is not assumed to be nil, we should be optimistic and use the nullability implied by the method.
+ - If the pointer is not assumed to be nil, we should be optimistic and use the nullability implied by the method.
- * This will not happen automatically, since the AST will have null unspecified in this case.
+ - This will not happen automatically, since the AST will have null unspecified in this case.
-Inlining
---------
+## Inlining
A symbol may need to be treated differently inside an inlined body. For example, consider these conversions from nonnull to nullable in presence of inlining:
-.. code-block:: cpp
+```cpp
+id obj = getNonnull();
+takesNullable(obj);
+takesNonnull(obj);
- id obj = getNonnull();
- takesNullable(obj);
- takesNonnull(obj);
-
- void takesNullable(nullable id obj) {
- obj->ivar // we should assume obj is nullable and warn here
- }
+void takesNullable(nullable id obj) {
+ obj->ivar // we should assume obj is nullable and warn here
+}
+```
With no special treatment, when the takesNullable is inlined the analyzer will not warn when the obj symbol is dereferenced. One solution for this is to reanalyze takesNullable as a top level function to get possible violations. The alternative method, deducing nullability information from the arguments after inlining is not robust enough (for example there might be more parameters with different nullability, but in the given path the two parameters might end up being the same symbol or there can be nested functions that take different view of the nullability of the same symbol). So the symbol will remain nonnull to avoid false positives but the functions that takes nullable parameters will be analyzed separately as well without inlining.
-Annotations on multi level pointers
------------------------------------
+## Annotations on multi level pointers
Tracking multiple levels of annotations for pointers pointing to pointers would make the checker more complicated, because this way a vector of nullability qualifiers would be needed to be tracked for each symbol. This is not a big caveat, since once the top level pointer is dereferenced, the symvol for the inner pointer will have the nullability information. The lack of multi level annotation tracking only observable, when multiple levels of pointers are passed to a function which has a parameter with multiple levels of annotations. So for now the checker support the top level nullability qualifiers only.:
-.. code-block:: cpp
-
- int * __nonnull * __nullable p;
- int ** q = p;
- takesStarNullableStarNullable(q);
+```cpp
+int * __nonnull * __nullable p;
+int ** q = p;
+takesStarNullableStarNullable(q);
+```
-Implementation notes
---------------------
+## Implementation notes
What to track?
-* The checker would track memory regions, and to each relevant region a qualifier information would be attached which is either nullable, nonnull or null unspecified (or contradicted to suppress warnings for a specific region).
-* On a branch, where a nullable pointer is known to be non null, the checker treat it as a same way as a pointer annotated as nonnull.
-* When there is an explicit cast from a null unspecified to either nonnull or nullable I will trust the cast.
-* Unannotated pointers are treated the same way as pointers annotated with nullability unspecified qualifier, unless the region is wrapped in ASSUME_NONNULL macros.
-* We might want to implement a callback for entry points to top level functions, where the pointer nullability assumptions would be made.
+- The checker would track memory regions, and to each relevant region a qualifier information would be attached which is either nullable, nonnull or null unspecified (or contradicted to suppress warnings for a specific region).
+- On a branch, where a nullable pointer is known to be non null, the checker treat it as a same way as a pointer annotated as nonnull.
+- When there is an explicit cast from a null unspecified to either nonnull or nullable I will trust the cast.
+- Unannotated pointers are treated the same way as pointers annotated with nullability unspecified qualifier, unless the region is wrapped in ASSUME_NONNULL macros.
+- We might want to implement a callback for entry points to top level functions, where the pointer nullability assumptions would be made.
+
diff --git a/clang/docs/analyzer/user-docs.md b/clang/docs/analyzer/user-docs.md
index 1ea193b1a651b..13328201a4014 100644
--- a/clang/docs/analyzer/user-docs.md
+++ b/clang/docs/analyzer/user-docs.md
@@ -1,16 +1,17 @@
-User Docs
-=========
+# User Docs
Contents:
-.. toctree::
- :maxdepth: 2
+```{toctree}
+:maxdepth: 2
+
+user-docs/CommandLineUsage
+user-docs/Options
+user-docs/UsingWithXCode
+user-docs/FilingBugs
+user-docs/CrossTranslationUnit
+user-docs/TaintAnalysisConfiguration
+user-docs/Annotations
+user-docs/FAQ
+```
- user-docs/CommandLineUsage
- user-docs/Options
- user-docs/UsingWithXCode
- user-docs/FilingBugs
- user-docs/CrossTranslationUnit
- user-docs/TaintAnalysisConfiguration
- user-docs/Annotations
- user-docs/FAQ
diff --git a/clang/docs/analyzer/user-docs/Annotations.md b/clang/docs/analyzer/user-docs/Annotations.md
index 957fc8d273c6a..dd67dc28a598e 100644
--- a/clang/docs/analyzer/user-docs/Annotations.md
+++ b/clang/docs/analyzer/user-docs/Annotations.md
@@ -1,41 +1,37 @@
-==================
-Source Annotations
-==================
+# Source Annotations
The Clang frontend supports several source-level annotations in the form of
-`GCC-style attributes <https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html>`_
+[GCC-style attributes](https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html)
and pragmas that can help make using the Clang Static Analyzer more useful.
These annotations can both help suppress false positives as well as enhance the
analyzer's ability to find bugs.
This page gives a practical overview of such annotations. For more technical
specifics regarding Clang-specific annotations please see the Clang's list of
-`language extensions <https://clang.llvm.org/docs/LanguageExtensions.html>`_.
+[language extensions](https://clang.llvm.org/docs/LanguageExtensions.html).
Details of "standard" GCC attributes (that Clang also supports) can
-be found in the `GCC manual <https://gcc.gnu.org/onlinedocs/gcc/>`_, with the
+be found in the [GCC manual](https://gcc.gnu.org/onlinedocs/gcc/), with the
majority of the relevant attributes being in the section on
-`function attributes <https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_.
+[function attributes](https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html).
Note that attributes that are labeled **Clang-specific** are not
recognized by GCC. Their use can be conditioned using preprocessor macros
(examples included on this page).
-.. contents::
- :local:
+```{contents}
+:local: true
+```
-General Purpose Annotations
-___________________________
+## General Purpose Annotations
-Null Pointer Checking
-#####################
+### Null Pointer Checking
-Attribute 'nonnull'
--------------------
+#### Attribute 'nonnull'
The analyzer recognizes the GCC attribute 'nonnull', which indicates that a
function expects that a given function parameter is not a null pointer.
Specific details of the syntax of using the 'nonnull' attribute can be found in
-`GCC's documentation <https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-nonnull-function-attribute>`_.
+[GCC's documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-nonnull-function-attribute).
Both the Clang compiler and GCC will flag warnings for simple cases where a
null pointer is directly being passed to a function with a 'nonnull' parameter
@@ -46,23 +42,23 @@ parameter.
**Example**
-.. code-block:: c
+```c
+int bar(int*p, int q, int *r) __attribute__((nonnull(1,3)));
- int bar(int*p, int q, int *r) __attribute__((nonnull(1,3)));
+int foo(int *p, int *q) {
+ return !p ? bar(q, 2, p)
+ : bar(p, 2, q);
+}
+```
- int foo(int *p, int *q) {
- return !p ? bar(q, 2, p)
- : bar(p, 2, q);
- }
+Running `scan-build` over this source produces the following output:
-Running ``scan-build`` over this source produces the following output:
+```{image} ../images/example_attribute_nonnull.png
+```
-.. image:: ../images/example_attribute_nonnull.png
+(custom-assertion-handlers)=
-.. _custom_assertion_handlers:
-
-Custom Assertion Handlers
-#########################
+### Custom Assertion Handlers
The analyzer exploits code assertions by pruning off paths where the
assertion condition is false. The idea is capture any program invariants
@@ -76,24 +72,24 @@ false paths.
In order to exploit assertions, however, the analyzer must understand when it
encounters an "assertion handler". Typically assertions are
implemented with a macro, with the macro performing a check for the assertion
-condition and, when the check fails, calling an assertion handler. For
+condition and, when the check fails, calling an assertion handler. For
example, consider the following code fragment:
-.. code-block:: c
-
- void foo(int *p) {
- assert(p != NULL);
- }
+```c
+void foo(int *p) {
+ assert(p != NULL);
+}
+```
When this code is preprocessed on Mac OS X it expands to the following:
-.. code-block:: c
+```c
+void foo(int *p) {
+ (__builtin_expect(!(p != NULL), 0) ? __assert_rtn(__func__, "t.c", 4, "p != NULL") : (void)0);
+}
+```
- void foo(int *p) {
- (__builtin_expect(!(p != NULL), 0) ? __assert_rtn(__func__, "t.c", 4, "p != NULL") : (void)0);
- }
-
-In this example, the assertion handler is ``__assert_rtn``. When called,
+In this example, the assertion handler is `__assert_rtn`. When called,
most assertion handlers typically print an error and terminate the program. The
analyzer can exploit such semantics by ending the analysis of a path once it
hits a call to an assertion handler.
@@ -111,15 +107,14 @@ it is annotated with the 'noreturn' attribute or the (Clang-specific)
'analyzer_noreturn' attribute. Note that, currently, clang does not support
these attributes on Objective-C methods and C++ methods.
-Attribute 'noreturn'
---------------------
+#### Attribute 'noreturn'
The 'noreturn' attribute is a GCC attribute that can be placed on the
declarations of functions. It means exactly what its name implies: a function
with a 'noreturn' attribute should never return.
Specific details of the syntax of using the 'noreturn' attribute can be found
-in `GCC's documentation <https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-noreturn-function-attribute>`__.
+in [GCC's documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-noreturn-function-attribute).
Not only does the analyzer exploit this information when pruning false paths,
but the compiler also takes it seriously and will generate different code (and
@@ -128,15 +123,14 @@ return.
**Example**
-On Mac OS X, the function prototype for ``__assert_rtn`` (declared in
-``assert.h``) is specifically annotated with the 'noreturn' attribute:
-
-.. code-block:: c
+On Mac OS X, the function prototype for `__assert_rtn` (declared in
+`assert.h`) is specifically annotated with the 'noreturn' attribute:
- void __assert_rtn(const char *, const char *, int, const char *) __attribute__((__noreturn__));
+```c
+void __assert_rtn(const char *, const char *, int, const char *) __attribute__((__noreturn__));
+```
-Attribute 'analyzer_noreturn' (Clang-specific)
-----------------------------------------------
+#### Attribute 'analyzer_noreturn' (Clang-specific)
The Clang-specific 'analyzer_noreturn' attribute is almost identical to
'noreturn' except that it is ignored by the compiler for the purposes of code
@@ -151,72 +145,66 @@ the use of preprocessor macros.
**Example**
-.. code-block:: c
+```c
+#ifndef CLANG_ANALYZER_NORETURN
+#if __has_feature(attribute_analyzer_noreturn)
+#define CLANG_ANALYZER_NORETURN __attribute__((analyzer_noreturn))
+#else
+#define CLANG_ANALYZER_NORETURN
+#endif
+#endif
- #ifndef CLANG_ANALYZER_NORETURN
- #if __has_feature(attribute_analyzer_noreturn)
- #define CLANG_ANALYZER_NORETURN __attribute__((analyzer_noreturn))
- #else
- #define CLANG_ANALYZER_NORETURN
- #endif
- #endif
+void my_assert_rtn(const char *, const char *, int, const char *) CLANG_ANALYZER_NORETURN;
+```
- void my_assert_rtn(const char *, const char *, int, const char *) CLANG_ANALYZER_NORETURN;
+### Dynamic Memory Modeling Annotations
-Dynamic Memory Modeling Annotations
-###################################
+If a project uses custom functions for dynamic memory management (that e.g. act as wrappers around `malloc`/`free` or `new`/`delete` in C++) and the analyzer cannot "see" the \_definitions\_ of these functions, it's possible to annotate their declarations to let the analyzer model their behavior. (Otherwise the analyzer cannot know that the opaque `my_free()` is basically equivalent to a standard `free()` call.)
-If a project uses custom functions for dynamic memory management (that e.g. act as wrappers around ``malloc``/``free`` or ``new``/``delete`` in C++) and the analyzer cannot "see" the _definitions_ of these functions, it's possible to annotate their declarations to let the analyzer model their behavior. (Otherwise the analyzer cannot know that the opaque ``my_free()`` is basically equivalent to a standard ``free()`` call.)
+:::{note}
+**This page only provides a brief list of these annotations.** For a full documentation, see the main [Attributes in Clang](../../AttributeReference.html#ownership-holds-ownership-returns-ownership-takes-clang-static-analyzer) page.
+:::
-.. note::
- **This page only provides a brief list of these annotations.** For a full documentation, see the main `Attributes in Clang <../../AttributeReference.html#ownership-holds-ownership-returns-ownership-takes-clang-static-analyzer>`_ page.
-
-Attribute 'ownership_returns' (Clang-specific)
-----------------------------------------------
+#### Attribute 'ownership_returns' (Clang-specific)
Use this attribute to mark functions that return dynamically allocated memory.
-The first argument is the type of the allocation (e.g. ``malloc``, ``new``, or any other identifier).
+The first argument is the type of the allocation (e.g. `malloc`, `new`, or any other identifier).
An optional second argument is the 1-based index of the function parameter that specifies the allocation size in bytes.
The referenced parameter must have an integral type.
This attribute may appear at most once per function declaration.
-.. code-block:: c
-
- // Without size argument:
- void __attribute((ownership_returns(malloc))) *my_malloc(size_t sz);
-
- // With size argument (describes that the 1st parameter represents the allocation size in bytes):
- void __attribute((ownership_returns(malloc, 1))) *my_sized_malloc(size_t sz);
+```c
+// Without size argument:
+void __attribute((ownership_returns(malloc))) *my_malloc(size_t sz);
-Attribute 'ownership_takes' (Clang-specific)
---------------------------------------------
+// With size argument (describes that the 1st parameter represents the allocation size in bytes):
+void __attribute((ownership_returns(malloc, 1))) *my_sized_malloc(size_t sz);
+```
-Use this attribute to mark functions that deallocate memory. Takes two arguments: the type of the allocation (e.g. ``malloc`` or ``new``) and the index of the parameter that is being deallocated (counting from 1).
+#### Attribute 'ownership_takes' (Clang-specific)
-.. code-block:: c
+Use this attribute to mark functions that deallocate memory. Takes two arguments: the type of the allocation (e.g. `malloc` or `new`) and the index of the parameter that is being deallocated (counting from 1).
- void __attribute((ownership_takes(malloc, 1))) my_free(void *);
+```c
+void __attribute((ownership_takes(malloc, 1))) my_free(void *);
+```
-Attribute 'ownership_holds' (Clang-specific)
---------------------------------------------
+#### Attribute 'ownership_holds' (Clang-specific)
-Use this attribute to mark functions that take ownership of memory and will deallocate it at some unspecified point in the future. Takes two arguments: the type of the allocation (e.g. ``malloc`` or ``new``) and the index of the parameter that is being held (counting from 1).
+Use this attribute to mark functions that take ownership of memory and will deallocate it at some unspecified point in the future. Takes two arguments: the type of the allocation (e.g. `malloc` or `new`) and the index of the parameter that is being held (counting from 1).
-.. code-block:: c
+```c
+void __attribute((ownership_holds(malloc, 2))) store_in_table(int key, record_t *val);
+```
- void __attribute((ownership_holds(malloc, 2))) store_in_table(int key, record_t *val);
+The annotations `ownership_takes` and `ownership_holds` both prevent memory leak reports (concerning the specified parameter); the difference between them is that using taken memory is a use-after-free error, while using held memory is assumed to be legitimate. However, releasing the held memory or passing it to another holding call is reported by the analyzer as an "attempt to release non-owned memory".
-The annotations ``ownership_takes`` and ``ownership_holds`` both prevent memory leak reports (concerning the specified parameter); the difference between them is that using taken memory is a use-after-free error, while using held memory is assumed to be legitimate. However, releasing the held memory or passing it to another holding call is reported by the analyzer as an "attempt to release non-owned memory".
+## Mac OS X API Annotations
+(cocoa-mem)=
-Mac OS X API Annotations
-________________________
-
-.. _cocoa_mem:
-
-Cocoa & Core Foundation Memory Management Annotations
-#####################################################
+### Cocoa & Core Foundation Memory Management Annotations
The analyzer supports the proper management of retain counts for
both Cocoa and Core Foundation objects. This checking is largely based on
@@ -227,19 +215,18 @@ conventions can cause the analyzer to miss bugs or flag false positives.
One can educate the analyzer (and others who read your code) about methods or
functions that deviate from the Cocoa and Core Foundation conventions using the
attributes described here. However, you should consider using proper naming
-conventions or the `objc_method_family <https://clang.llvm.org/docs/LanguageExtensions.html#the-objc-method-family-attribute>`_
+conventions or the [objc_method_family](https://clang.llvm.org/docs/LanguageExtensions.html#the-objc-method-family-attribute)
attribute, if applicable.
-.. _ns_returns_retained:
+(ns-returns-retained)=
-Attribute 'ns_returns_retained' (Clang-specific)
-------------------------------------------------
+#### Attribute 'ns_returns_retained' (Clang-specific)
The GCC-style (Clang-specific) attribute 'ns_returns_retained' allows one to
annotate an Objective-C method or C function as returning a retained Cocoa
object that the caller is responsible for releasing (via sending a
-``release`` message to the object). The Foundation framework defines a
-macro ``NS_RETURNS_RETAINED`` that is functionally equivalent to the
+`release` message to the object). The Foundation framework defines a
+macro `NS_RETURNS_RETAINED` that is functionally equivalent to the
one shown below.
**Placing on Objective-C methods**: For Objective-C methods, this
@@ -254,80 +241,79 @@ functions allows the analyzer to perform extra checking.
**Example**
-.. code-block:: objc
+```objc
+#import <Foundation/Foundation.h>;
- #import <Foundation/Foundation.h>;
+#ifndef __has_feature // Optional.
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#endif
- #ifndef __has_feature // Optional.
- #define __has_feature(x) 0 // Compatibility with non-clang compilers.
- #endif
+#ifndef NS_RETURNS_RETAINED
+#if __has_feature(attribute_ns_returns_retained)
+#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
+#else
+#define NS_RETURNS_RETAINED
+#endif
+#endif
- #ifndef NS_RETURNS_RETAINED
- #if __has_feature(attribute_ns_returns_retained)
- #define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
- #else
- #define NS_RETURNS_RETAINED
- #endif
- #endif
+ at interface MyClass : NSObject {}
+- (NSString*) returnsRetained NS_RETURNS_RETAINED;
+- (NSString*) alsoReturnsRetained;
+ at end
- @interface MyClass : NSObject {}
- - (NSString*) returnsRetained NS_RETURNS_RETAINED;
- - (NSString*) alsoReturnsRetained;
- @end
+ at implementation MyClass
+- (NSString*) returnsRetained {
+ return [[NSString alloc] initWithCString:"no leak here"];
+}
+- (NSString*) alsoReturnsRetained {
+ return [[NSString alloc] initWithCString:"flag a leak"];
+}
+ at end
+```
- @implementation MyClass
- - (NSString*) returnsRetained {
- return [[NSString alloc] initWithCString:"no leak here"];
- }
- - (NSString*) alsoReturnsRetained {
- return [[NSString alloc] initWithCString:"flag a leak"];
- }
- @end
+Running `scan-build` on this source file produces the following output:
-Running ``scan-build`` on this source file produces the following output:
+```{image} ../images/example_ns_returns_retained.png
+```
-.. image:: ../images/example_ns_returns_retained.png
+(ns-returns-not-retained)=
-.. _ns_returns_not_retained:
-
-Attribute 'ns_returns_not_retained' (Clang-specific)
-----------------------------------------------------
+#### Attribute 'ns_returns_not_retained' (Clang-specific)
The 'ns_returns_not_retained' attribute is the complement of
-'`ns_returns_retained`_'. Where a function or method may appear to obey the
+'[ns_returns_retained]'. Where a function or method may appear to obey the
Cocoa conventions and return a retained Cocoa object, this attribute can be
used to indicate that the object reference returned should not be considered as
an "owning" reference being returned to the caller. The Foundation
-framework defines a macro ``NS_RETURNS_NOT_RETAINED`` that is functionally
+framework defines a macro `NS_RETURNS_NOT_RETAINED` that is functionally
equivalent to the one shown below.
-Usage is identical to `ns_returns_retained`_. When using the
+Usage is identical to [ns_returns_retained]. When using the
attribute, be sure to declare it within the proper macro that checks for
its availability, as it is not available in earlier versions of the analyzer:
-.. code-block:objc
-
- #ifndef __has_feature // Optional.
- #define __has_feature(x) 0 // Compatibility with non-clang compilers.
- #endif
+% code-block:objc
+%
+% #ifndef __has_feature // Optional.
+% #define __has_feature(x) 0 // Compatibility with non-clang compilers.
+% #endif
+%
+% #ifndef NS_RETURNS_NOT_RETAINED
+% #if __has_feature(attribute_ns_returns_not_retained)
+% #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
+% #else
+% #define NS_RETURNS_NOT_RETAINED
+% #endif
+% #endif
- #ifndef NS_RETURNS_NOT_RETAINED
- #if __has_feature(attribute_ns_returns_not_retained)
- #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
- #else
- #define NS_RETURNS_NOT_RETAINED
- #endif
- #endif
+(cf-returns-retained)=
-.. _cf_returns_retained:
-
-Attribute 'cf_returns_retained' (Clang-specific)
-------------------------------------------------
+#### Attribute 'cf_returns_retained' (Clang-specific)
The GCC-style (Clang-specific) attribute 'cf_returns_retained' allows one to
annotate an Objective-C method or C function as returning a retained Core
Foundation object that the caller is responsible for releasing. The
-CoreFoundation framework defines a macro ``CF_RETURNS_RETAINED`` that is
+CoreFoundation framework defines a macro `CF_RETURNS_RETAINED` that is
functionally equivalent to the one shown below.
**Placing on Objective-C methods**: With respect to Objective-C methods.,
@@ -349,193 +335,190 @@ interprets the function as:
2. Treating the function as if it its name contained the keywords
"create" or "copy". This means the returned object as a
+1 retain count that must be released by the caller, either by sending a
- ``release`` message (via toll-free bridging to an Objective-C object
- pointer), or calling ``CFRelease`` or a similar function.
+ `release` message (via toll-free bridging to an Objective-C object
+ pointer), or calling `CFRelease` or a similar function.
**Example**
-.. code-block:objc
-
- #import <Cocoa/Cocoa.h>
-
- #ifndef __has_feature // Optional.
- #define __has_feature(x) 0 // Compatibility with non-clang compilers.
- #endif
-
- #ifndef CF_RETURNS_RETAINED
- #if __has_feature(attribute_cf_returns_retained)
- #define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
- #else
- #define CF_RETURNS_RETAINED
- #endif
- #endif
-
- @interface MyClass : NSObject {}
- - (NSDate*) returnsCFRetained CF_RETURNS_RETAINED;
- - (NSDate*) alsoReturnsRetained;
- - (NSDate*) returnsNSRetained NS_RETURNS_RETAINED;
- @end
-
- CF_RETURNS_RETAINED
- CFDateRef returnsRetainedCFDate() {
- return CFDateCreate(0, CFAbsoluteTimeGetCurrent());
- }
-
- @implementation MyClass
- - (NSDate*) returnsCFRetained {
- return (NSDate*) returnsRetainedCFDate(); // No leak.
- }
-
- - (NSDate*) alsoReturnsRetained {
- return (NSDate*) returnsRetainedCFDate(); // Always report a leak.
- }
-
- - (NSDate*) returnsNSRetained {
- return (NSDate*) returnsRetainedCFDate(); // Report a leak when using GC.
- }
- @end
-
-Running ``scan-build`` on this example produces the following output:
-
-.. image:: ../images/example_cf_returns_retained.png
-
-Attribute 'cf_returns_not_retained' (Clang-specific)
-----------------------------------------------------
+% code-block:objc
+%
+% #import <Cocoa/Cocoa.h>
+%
+% #ifndef __has_feature // Optional.
+% #define __has_feature(x) 0 // Compatibility with non-clang compilers.
+% #endif
+%
+% #ifndef CF_RETURNS_RETAINED
+% #if __has_feature(attribute_cf_returns_retained)
+% #define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+% #else
+% #define CF_RETURNS_RETAINED
+% #endif
+% #endif
+%
+% @interface MyClass : NSObject {}
+% - (NSDate*) returnsCFRetained CF_RETURNS_RETAINED;
+% - (NSDate*) alsoReturnsRetained;
+% - (NSDate*) returnsNSRetained NS_RETURNS_RETAINED;
+% @end
+%
+% CF_RETURNS_RETAINED
+% CFDateRef returnsRetainedCFDate() {
+% return CFDateCreate(0, CFAbsoluteTimeGetCurrent());
+% }
+%
+% @implementation MyClass
+% - (NSDate*) returnsCFRetained {
+% return (NSDate*) returnsRetainedCFDate(); // No leak.
+% }
+%
+% - (NSDate*) alsoReturnsRetained {
+% return (NSDate*) returnsRetainedCFDate(); // Always report a leak.
+% }
+%
+% - (NSDate*) returnsNSRetained {
+% return (NSDate*) returnsRetainedCFDate(); // Report a leak when using GC.
+% }
+% @end
+
+Running `scan-build` on this example produces the following output:
+
+```{image} ../images/example_cf_returns_retained.png
+```
+
+#### Attribute 'cf_returns_not_retained' (Clang-specific)
The 'cf_returns_not_retained' attribute is the complement of
-'`cf_returns_retained`_'. Where a function or method may appear to obey the
+'[cf_returns_retained]'. Where a function or method may appear to obey the
Core Foundation or Cocoa conventions and return a retained Core Foundation
object, this attribute can be used to indicate that the object reference
returned should not be considered as an "owning" reference being
returned to the caller. The CoreFoundation framework defines a macro
-**``CF_RETURNS_NOT_RETAINED``** that is functionally equivalent to the one
+**\`\`CF_RETURNS_NOT_RETAINED\`\`** that is functionally equivalent to the one
shown below.
-Usage is identical to cf_returns_retained_. When using the attribute, be sure
+Usage is identical to [cf_returns_retained]. When using the attribute, be sure
to declare it within the proper macro that checks for its availability, as it
is not available in earlier versions of the analyzer:
-.. code-block:objc
-
- #ifndef __has_feature // Optional.
- #define __has_feature(x) 0 // Compatibility with non-clang compilers.
- #endif
+% code-block:objc
+%
+% #ifndef __has_feature // Optional.
+% #define __has_feature(x) 0 // Compatibility with non-clang compilers.
+% #endif
+%
+% #ifndef CF_RETURNS_NOT_RETAINED
+% #if __has_feature(attribute_cf_returns_not_retained)
+% #define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
+% #else
+% #define CF_RETURNS_NOT_RETAINED
+% #endif
+% #endif
- #ifndef CF_RETURNS_NOT_RETAINED
- #if __has_feature(attribute_cf_returns_not_retained)
- #define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
- #else
- #define CF_RETURNS_NOT_RETAINED
- #endif
- #endif
+(ns-consumed)=
-.. _ns_consumed:
-
-Attribute 'ns_consumed' (Clang-specific)
-----------------------------------------
+#### Attribute 'ns_consumed' (Clang-specific)
The 'ns_consumed' attribute can be placed on a specific parameter in either
the declaration of a function or an Objective-C method. It indicates to the
-static analyzer that a ``release`` message is implicitly sent to the
+static analyzer that a `release` message is implicitly sent to the
parameter upon completion of the call to the given function or method. The
-Foundation framework defines a macro ``NS_RELEASES_ARGUMENT`` that
-is functionally equivalent to the ``NS_CONSUMED`` macro shown below.
+Foundation framework defines a macro `NS_RELEASES_ARGUMENT` that
+is functionally equivalent to the `NS_CONSUMED` macro shown below.
**Example**
-.. code-block:objc
-
- #ifndef __has_feature // Optional.
- #define __has_feature(x) 0 // Compatibility with non-clang compilers.
- #endif
-
- #ifndef NS_CONSUMED
- #if __has_feature(attribute_ns_consumed)
- #define NS_CONSUMED __attribute__((ns_consumed))
- #else
- #define NS_CONSUMED
- #endif
- #endif
-
- void consume_ns(id NS_CONSUMED x);
-
- void test() {
- id x = [[NSObject alloc] init];
- consume_ns(x); // No leak!
- }
-
- @interface Foo : NSObject
- + (void) releaseArg:(id) NS_CONSUMED x;
- + (void) releaseSecondArg:(id)x second:(id) NS_CONSUMED y;
- @end
-
- void test_method() {
- id x = [[NSObject alloc] init];
- [Foo releaseArg:x]; // No leak!
- }
-
- void test_method2() {
- id a = [[NSObject alloc] init];
- id b = [[NSObject alloc] init];
- [Foo releaseSecondArg:a second:b]; // 'a' is leaked, but 'b' is released.
- }
-
-Attribute 'cf_consumed' (Clang-specific)
-----------------------------------------
-
-The 'cf_consumed' attribute is practically identical to ns_consumed_. The
+% code-block:objc
+%
+% #ifndef __has_feature // Optional.
+% #define __has_feature(x) 0 // Compatibility with non-clang compilers.
+% #endif
+%
+% #ifndef NS_CONSUMED
+% #if __has_feature(attribute_ns_consumed)
+% #define NS_CONSUMED __attribute__((ns_consumed))
+% #else
+% #define NS_CONSUMED
+% #endif
+% #endif
+%
+% void consume_ns(id NS_CONSUMED x);
+%
+% void test() {
+% id x = [[NSObject alloc] init];
+% consume_ns(x); // No leak!
+% }
+%
+% @interface Foo : NSObject
+% + (void) releaseArg:(id) NS_CONSUMED x;
+% + (void) releaseSecondArg:(id)x second:(id) NS_CONSUMED y;
+% @end
+%
+% void test_method() {
+% id x = [[NSObject alloc] init];
+% [Foo releaseArg:x]; // No leak!
+% }
+%
+% void test_method2() {
+% id a = [[NSObject alloc] init];
+% id b = [[NSObject alloc] init];
+% [Foo releaseSecondArg:a second:b]; // 'a' is leaked, but 'b' is released.
+% }
+
+#### Attribute 'cf_consumed' (Clang-specific)
+
+The 'cf_consumed' attribute is practically identical to [ns_consumed]. The
attribute can be placed on a specific parameter in either the declaration of a
function or an Objective-C method. It indicates to the static analyzer that the
-object reference is implicitly passed to a call to ``CFRelease`` upon
+object reference is implicitly passed to a call to `CFRelease` upon
completion of the call to the given function or method. The CoreFoundation
-framework defines a macro ``CF_RELEASES_ARGUMENT`` that is functionally
-equivalent to the ``CF_CONSUMED`` macro shown below.
+framework defines a macro `CF_RELEASES_ARGUMENT` that is functionally
+equivalent to the `CF_CONSUMED` macro shown below.
Operationally this attribute is nearly identical to 'ns_consumed'.
**Example**
-.. code-block:objc
-
- #ifndef __has_feature // Optional.
- #define __has_feature(x) 0 // Compatibility with non-clang compilers.
- #endif
-
- #ifndef CF_CONSUMED
- #if __has_feature(attribute_cf_consumed)
- #define CF_CONSUMED __attribute__((cf_consumed))
- #else
- #define CF_CONSUMED
- #endif
- #endif
-
- void consume_cf(id CF_CONSUMED x);
- void consume_CFDate(CFDateRef CF_CONSUMED x);
-
- void test() {
- id x = [[NSObject alloc] init];
- consume_cf(x); // No leak!
- }
-
- void test2() {
- CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
- consume_CFDate(date); // No leak, including under GC!
-
- }
-
- @interface Foo : NSObject
- + (void) releaseArg:(CFDateRef) CF_CONSUMED x;
- @end
-
- void test_method() {
- CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
- [Foo releaseArg:date]; // No leak!
- }
-
-.. _ns_consumes_self:
-
-Attribute 'ns_consumes_self' (Clang-specific)
----------------------------------------------
+% code-block:objc
+%
+% #ifndef __has_feature // Optional.
+% #define __has_feature(x) 0 // Compatibility with non-clang compilers.
+% #endif
+%
+% #ifndef CF_CONSUMED
+% #if __has_feature(attribute_cf_consumed)
+% #define CF_CONSUMED __attribute__((cf_consumed))
+% #else
+% #define CF_CONSUMED
+% #endif
+% #endif
+%
+% void consume_cf(id CF_CONSUMED x);
+% void consume_CFDate(CFDateRef CF_CONSUMED x);
+%
+% void test() {
+% id x = [[NSObject alloc] init];
+% consume_cf(x); // No leak!
+% }
+%
+% void test2() {
+% CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
+% consume_CFDate(date); // No leak, including under GC!
+%
+% }
+%
+% @interface Foo : NSObject
+% + (void) releaseArg:(CFDateRef) CF_CONSUMED x;
+% @end
+%
+% void test_method() {
+% CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
+% [Foo releaseArg:date]; // No leak!
+% }
+
+(ns-consumes-self)=
+
+#### Attribute 'ns_consumes_self' (Clang-specific)
The 'ns_consumes_self' attribute can be placed only on an Objective-C method
declaration. It indicates that the receiver of the message is
@@ -547,44 +530,43 @@ follow the standard Cocoa naming conventions.
**Example**
-.. code-block:objc
- #ifndef __has_feature
- #define __has_feature(x) 0 // Compatibility with non-clang compilers.
- #endif
-
- #ifndef NS_CONSUMES_SELF
- #if __has_feature((attribute_ns_consumes_self))
- #define NS_CONSUMES_SELF __attribute__((ns_consumes_self))
- #else
- #define NS_CONSUMES_SELF
- #endif
- #endif
-
- @interface MyClass : NSObject
- - initWith:(MyClass *)x;
- - nonstandardInitWith:(MyClass *)x NS_CONSUMES_SELF NS_RETURNS_RETAINED;
- @end
-
-In this example, ``-nonstandardInitWith:`` has the same ownership
-semantics as the init method ``-initWith:``. The static analyzer will
+% code-block:objc
+% #ifndef __has_feature
+% #define __has_feature(x) 0 // Compatibility with non-clang compilers.
+% #endif
+%
+% #ifndef NS_CONSUMES_SELF
+% #if __has_feature((attribute_ns_consumes_self))
+% #define NS_CONSUMES_SELF __attribute__((ns_consumes_self))
+% #else
+% #define NS_CONSUMES_SELF
+% #endif
+% #endif
+%
+% @interface MyClass : NSObject
+% - initWith:(MyClass *)x;
+% - nonstandardInitWith:(MyClass *)x NS_CONSUMES_SELF NS_RETURNS_RETAINED;
+% @end
+
+In this example, `-nonstandardInitWith:` has the same ownership
+semantics as the init method `-initWith:`. The static analyzer will
observe that the method consumes the receiver, and then returns an object with
a +1 retain count.
-The Foundation framework defines a macro ``NS_REPLACES_RECEIVER`` which is
-functionally equivalent to the combination of ``NS_CONSUMES_SELF`` and
-``NS_RETURNS_RETAINED`` shown above.
+The Foundation framework defines a macro `NS_REPLACES_RECEIVER` which is
+functionally equivalent to the combination of `NS_CONSUMES_SELF` and
+`NS_RETURNS_RETAINED` shown above.
-Libkern Memory Management Annotations
-#####################################
+### Libkern Memory Management Annotations
-`Libkern <https://developer.apple.com/documentation/kernel/osobject?language=objc>`_
-requires developers to inherit all heap allocated objects from ``OSObject`` and
+[Libkern](https://developer.apple.com/documentation/kernel/osobject?language=objc)
+requires developers to inherit all heap allocated objects from `OSObject` and
to perform manual reference counting. The reference counting model is very
similar to MRR (manual retain-release) mode in
-`Objective-C <https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html>`_
+[Objective-C](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html)
or to CoreFoundation reference counting.
Freshly-allocated objects start with a reference count of 1, and calls to
-``retain`` increment it, while calls to ``release`` decrement it. The object is
+`retain` increment it, while calls to `release` decrement it. The object is
deallocated whenever its reference count reaches zero.
Manually incrementing and decrementing reference counts is error-prone:
@@ -603,79 +585,70 @@ values and attributes.
By default, the following summaries are assumed:
-- All functions starting with ``get`` or ``Get``, unless they are returning
- subclasses of ``OSIterator``, are assumed to be returning at +0. That is, the
+- All functions starting with `get` or `Get`, unless they are returning
+ subclasses of `OSIterator`, are assumed to be returning at +0. That is, the
caller has no reference count *obligations* with respect to the reference
count of the returned object and should leave it untouched.
-
- All other functions are assumed to return at +1. That is, the caller has an
*obligation* to release such objects.
-
- Functions are assumed not to change the reference count of their parameters,
- including the implicit ``this`` parameter.
+ including the implicit `this` parameter.
These summaries can be overriden with the following
-`attributes <https://clang.llvm.org/docs/AttributeReference.html#os-returns-not-retained>`_:
+[attributes](https://clang.llvm.org/docs/AttributeReference.html#os-returns-not-retained):
-Attribute 'os_returns_retained'
--------------------------------
+#### Attribute 'os_returns_retained'
-The ``os_returns_retained`` attribute (accessed through the macro
-``LIBKERN_RETURNS_RETAINED``) plays a role identical to `ns_returns_retained`_
-for functions returning ``OSObject`` subclasses. The attribute indicates that
+The `os_returns_retained` attribute (accessed through the macro
+`LIBKERN_RETURNS_RETAINED`) plays a role identical to [ns_returns_retained]
+for functions returning `OSObject` subclasses. The attribute indicates that
it is a callers responsibility to release the returned object.
-Attribute 'os_returns_not_retained'
------------------------------------
+#### Attribute 'os_returns_not_retained'
-The ``os_returns_not_retained`` attribute (accessed through the macro
-``LIBKERN_RETURNS_NOT_RETAINED``) plays a role identical to
-`ns_returns_not_retained`_ for functions returning ``OSObject`` subclasses. The
+The `os_returns_not_retained` attribute (accessed through the macro
+`LIBKERN_RETURNS_NOT_RETAINED`) plays a role identical to
+[ns_returns_not_retained] for functions returning `OSObject` subclasses. The
attribute indicates that the caller should not change the retain count of the
returned object.
-
**Example**
-.. code-block:objc
-
- class MyClass {
- OSObject *f;
- LIBKERN_RETURNS_NOT_RETAINED OSObject *myFieldGetter();
- }
-
- // Note that the annotation only has to be applied to the function declaration.
- OSObject * MyClass::myFieldGetter() {
- return f;
- }
-
-Attribute 'os_consumed'
------------------------
-
-Similarly to `ns_consumed`_ attribute, ``os_consumed`` (accessed through
-``LIBKERN_CONSUMED``) attribute, applied to a parameter, indicates that the
+% code-block:objc
+%
+% class MyClass {
+% OSObject *f;
+% LIBKERN_RETURNS_NOT_RETAINED OSObject *myFieldGetter();
+% }
+%
+% // Note that the annotation only has to be applied to the function declaration.
+% OSObject * MyClass::myFieldGetter() {
+% return f;
+% }
+
+#### Attribute 'os_consumed'
+
+Similarly to [ns_consumed] attribute, `os_consumed` (accessed through
+`LIBKERN_CONSUMED`) attribute, applied to a parameter, indicates that the
call to the function *consumes* the parameter: the callee should either release
it or store it and release it in the destructor, while the caller should assume
one is subtracted from the reference count after the call.
-.. code-block:objc
- IOReturn addToList(LIBKERN_CONSUMED IOPMinformee *newInformee);
+% code-block:objc
+% IOReturn addToList(LIBKERN_CONSUMED IOPMinformee *newInformee);
-Attribute 'os_consumes_this'
-----------------------------
+#### Attribute 'os_consumes_this'
-Similarly to `ns_consumes_self`_, the ``os_consumes_self`` attribute indicates
-that the method call *consumes* the implicit ``this`` argument: the caller
+Similarly to [ns_consumes_self], the `os_consumes_self` attribute indicates
+that the method call *consumes* the implicit `this` argument: the caller
should assume one was subtracted from the reference count of the object after
the call, and the callee has on obligation to either release the argument, or
store it and eventually release it in the destructor.
+% code-block:objc
+% void addThisToList(OSArray *givenList) LIBKERN_CONSUMES_THIS;
-.. code-block:objc
- void addThisToList(OSArray *givenList) LIBKERN_CONSUMES_THIS;
-
-Out Parameters
---------------
+#### Out Parameters
A function can also return an object to a caller by a means of an out parameter
(a pointer-to-OSObject-pointer is passed, and a callee writes a pointer to an
@@ -683,18 +656,18 @@ object into an argument). Currently the analyzer does not track unannotated out
parameters by default, but with annotations we distinguish four separate cases:
**1. Non-retained out parameters**, identified using
-``LIBKERN_RETURNS_NOT_RETAINED`` applied to parameters, e.g.:
+`LIBKERN_RETURNS_NOT_RETAINED` applied to parameters, e.g.:
-.. code-block:objc
- void getterViaOutParam(LIBKERN_RETURNS_NOT_RETAINED OSObject **obj)
+% code-block:objc
+% void getterViaOutParam(LIBKERN_RETURNS_NOT_RETAINED OSObject **obj)
Such functions write a non-retained object into an out parameter, and the
caller has no further obligations.
-**2. Retained out parameters**, identified using ``LIBKERN_RETURNS_RETAINED``:
+**2. Retained out parameters**, identified using `LIBKERN_RETURNS_RETAINED`:
-.. code-block:objc
- void getterViaOutParam(LIBKERN_RETURNS_NOT_RETAINED OSObject **obj)
+% code-block:objc
+% void getterViaOutParam(LIBKERN_RETURNS_NOT_RETAINED OSObject **obj)
In such cases a retained object is written into an out parameter, which the caller has then to release in order to avoid a leak.
@@ -702,34 +675,34 @@ These two cases are simple - but in practice a functions returning an
out-parameter usually also return a return code, and then an out parameter may
or may not be written, which conditionally depends on the exit code, e.g.:
-.. code-block:objc
- bool maybeCreateObject(LIBKERN_RETURNS_RETAINED OSObject **obj);
+% code-block:objc
+% bool maybeCreateObject(LIBKERN_RETURNS_RETAINED OSObject **obj);
For such functions, the usual semantics is that an object is written into on "success", and not written into on "failure".
-For ``LIBKERN_RETURNS_RETAINED`` we assume the following definition of
+For `LIBKERN_RETURNS_RETAINED` we assume the following definition of
success:
-- For functions returning ``OSReturn`` or ``IOReturn`` (any typedef to
- ``kern_return_t``) success is defined as having an output of zero
- (``kIOReturnSuccess`` is zero).
-
+- For functions returning `OSReturn` or `IOReturn` (any typedef to
+ `kern_return_t`) success is defined as having an output of zero
+ (`kIOReturnSuccess` is zero).
- For all others, success is non-zero (e.g. non-nullptr for pointers)
**3. Retained out parameters on zero return** The annotation
-``LIBKERN_RETURNS_RETAINED_ON_ZERO`` states that a retained object is written
+`LIBKERN_RETURNS_RETAINED_ON_ZERO` states that a retained object is written
into if and only if the function returns a zero value:
-.. code-block:objc
- bool OSUnserializeXML(void *data, LIBKERN_RETURNS_RETAINED_ON_ZERO OSString **errString);
+% code-block:objc
+% bool OSUnserializeXML(void *data, LIBKERN_RETURNS_RETAINED_ON_ZERO OSString **errString);
Then the caller has to release an object if the function has returned zero.
**4. Retained out parameters on non-zero return** Similarly,
-``LIBKERN_RETURNS_RETAINED_ON_NONZERO`` specifies that a retained object is
+`LIBKERN_RETURNS_RETAINED_ON_NONZERO` specifies that a retained object is
written into the parameter if and only if the function has returned a non-zero
value.
Note that for non-retained out parameters conditionals do not matter, as the
caller has no obligations regardless of whether an object is written into or
not.
+
diff --git a/clang/docs/analyzer/user-docs/CommandLineUsage.md b/clang/docs/analyzer/user-docs/CommandLineUsage.md
index 2a119b294c945..4db8498ab062e 100644
--- a/clang/docs/analyzer/user-docs/CommandLineUsage.md
+++ b/clang/docs/analyzer/user-docs/CommandLineUsage.md
@@ -1,5 +1,4 @@
-Command Line Usage: scan-build and CodeChecker
-==============================================
+# Command Line Usage: scan-build and CodeChecker
This document provides guidelines for running the static analyzer from the command line on whole projects.
CodeChecker and scan-build are two CLI tools for using CSA on multiple files (translation units).
@@ -7,26 +6,28 @@ Both provide a way of driving the analyzer, detecting compilation flags, and gen
CodeChecker is more actively maintained, provides heuristics for working with multiple versions of popular compilers and it also comes with a web-based GUI for viewing, filtering, categorizing and suppressing the results.
Therefore CodeChecker is recommended in case you need any of the above features or just more customizability in general.
-Machine-readable output
------------------------
+## Machine-readable output
-For a direct analysis of a source file, the ``clang`` driver can write a SARIF report::
+For a direct analysis of a source file, the `clang` driver can write a SARIF report:
- $ clang --analyze --analyzer-output sarif -o report.sarif source.c
+```
+$ clang --analyze --analyzer-output sarif -o report.sarif source.c
+```
-``--analyzer-output`` selects the report format.
-The available formats are ``html``, ``plist``, ``plist-multi-file``, ``plist-html``, ``sarif``, ``sarif-html``, and ``text``.
-``sarif`` writes a SARIF JSON report to the path specified by ``-o``; ``sarif-html`` also creates HTML files for interactive inspection.
-The default format is ``plist``.
+`--analyzer-output` selects the report format.
+The available formats are `html`, `plist`, `plist-multi-file`, `plist-html`, `sarif`, `sarif-html`, and `text`.
+`sarif` writes a SARIF JSON report to the path specified by `-o`; `sarif-html` also creates HTML files for interactive inspection.
+The default format is `plist`.
This direct form analyzes a translation unit.
For project-wide analysis, use a tool such as scan-build or CodeChecker to drive the individual compiler invocations.
-``scan-build`` can emit a SARIF report for each analyzed translation unit with its ``-sarif`` option::
+`scan-build` can emit a SARIF report for each analyzed translation unit with its `-sarif` option:
- $ scan-build -sarif -o reports make
+```
+$ scan-build -sarif -o reports make
+```
-Comparison of CodeChecker and scan-build
-----------------------------------------
+## Comparison of CodeChecker and scan-build
The static analyzer is by design a GUI tool originally intended to be consumed by the XCode IDE.
Its purpose is to find buggy execution paths in the program, and such paths are very hard to comprehend by looking at a non-interactive standard output.
@@ -34,227 +35,240 @@ It is possible, however, to invoke the static analyzer from the command line in
The following tools are used commonly to run the analyzer from the command line.
Both tools are wrapper scripts to drive the analysis and the underlying invocations of the Clang compiler:
-1. scan-build_ is an old and simple command line tool that emits static analyzer warnings as HTML files while compiling your project. You can view the analysis results in your web browser; the utility script ``scan-view`` can provide a trivial HTTP server that servers these result files.
- - Is available as a part of the LLVM project (together with ``scan-view``).
- - Useful for individual developers who simply want to view static analysis results at their desk, or in a very simple collaborative environment.
- - Works on all major platforms (Windows, Linux, macOS) and is available as a package in many Linux distributions.
- - Does not include support for cross-translation-unit analysis.
-
-2. CodeChecker_ is a driver and web server that runs the static analyzer on your projects on demand and maintains a database of issues.
- - Open source, but out-of-tree, i.e. not part of the LLVM project.
- - Perfect for managing large amounts of thee static analyzer warnings in a collaborative environment.
- - Generally much more feature-rich than scan-build.
- - Supports incremental analysis: Results can be stored in a database, subsequent analysis runs can be compared to list the newly added defects.
- - :doc:`CrossTranslationUnit` is supported fully on Linux via CodeChecker.
- - Can also run clang-tidy checks and various other analysis tools.
-
-scan-build
-----------
+1. [scan-build] is an old and simple command line tool that emits static analyzer warnings as HTML files while compiling your project. You can view the analysis results in your web browser; the utility script `scan-view` can provide a trivial HTTP server that servers these result files.
+ : - Is available as a part of the LLVM project (together with `scan-view`).
+ - Useful for individual developers who simply want to view static analysis results at their desk, or in a very simple collaborative environment.
+ - Works on all major platforms (Windows, Linux, macOS) and is available as a package in many Linux distributions.
+ - Does not include support for cross-translation-unit analysis.
+2. [CodeChecker] is a driver and web server that runs the static analyzer on your projects on demand and maintains a database of issues.
+ : - Open source, but out-of-tree, i.e. not part of the LLVM project.
+ - Perfect for managing large amounts of thee static analyzer warnings in a collaborative environment.
+ - Generally much more feature-rich than scan-build.
+ - Supports incremental analysis: Results can be stored in a database, subsequent analysis runs can be compared to list the newly added defects.
+ - {doc}`CrossTranslationUnit` is supported fully on Linux via CodeChecker.
+ - Can also run clang-tidy checks and various other analysis tools.
+
+## scan-build
**scan-build** is a command line utility that enables a user to run the static analyzer over their codebase as part of performing a regular build (from the command line).
-How does it work?
-~~~~~~~~~~~~~~~~~
+### How does it work?
During a project build, as source files are compiled they are also analyzed in tandem by the static analyzer.
Upon completion of the build, results are then presented to the user within a web browser.
-Will it work with any build system?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+### Will it work with any build system?
-**scan-build** has little or no knowledge about how you build your code. It works by overriding the ``CC`` and ``CXX`` environment variables to (hopefully) change your build to use a "fake" compiler instead of the one that would normally build your project. This fake compiler executes either ``clang`` or ``gcc`` (depending on the platform) to compile your code and then executes the static analyzer to analyze your code.
+**scan-build** has little or no knowledge about how you build your code. It works by overriding the `CC` and `CXX` environment variables to (hopefully) change your build to use a "fake" compiler instead of the one that would normally build your project. This fake compiler executes either `clang` or `gcc` (depending on the platform) to compile your code and then executes the static analyzer to analyze your code.
This "poor man's interposition" works amazingly well in many cases and falls down in others. Please consult the information on this page on making the best use of **scan-build**, which includes getting it to work when the aforementioned hack fails to work.
-.. image:: ../images/scan_build_cmd.png
+```{image} ../images/scan_build_cmd.png
+```
-.. image:: ../images/analyzer_html.png
+```{image} ../images/analyzer_html.png
+```
**Viewing static analyzer results in a web browser**
-Basic Usage
-~~~~~~~~~~~
+### Basic Usage
-Basic usage of ``scan-build`` is designed to be simple: just place the word "scan-build" in front of your build command::
+Basic usage of `scan-build` is designed to be simple: just place the word "scan-build" in front of your build command:
- $ scan-build make
- $ scan-build xcodebuild
+```
+$ scan-build make
+$ scan-build xcodebuild
+```
-In the first case ``scan-build`` analyzes the code of a project built with ``make`` and in the second case ``scan-build`` analyzes a project built using ``xcodebuild``.
+In the first case `scan-build` analyzes the code of a project built with `make` and in the second case `scan-build` analyzes a project built using `xcodebuild`.
-Here is the general format for invoking ``scan-build``::
+Here is the general format for invoking `scan-build`:
- $ scan-build [scan-build options] <command> [command options]
+```
+$ scan-build [scan-build options] <command> [command options]
+```
-Operationally, ``scan-build`` literally runs <command> with all of the subsequent options passed to it. For example, one can pass ``-j4`` to ``make`` get a parallel build over 4 cores::
+Operationally, `scan-build` literally runs \<command> with all of the subsequent options passed to it. For example, one can pass `-j4` to `make` get a parallel build over 4 cores:
- $ scan-build make -j4
+```
+$ scan-build make -j4
+```
-In almost all cases, ``scan-build`` makes no effort to interpret the options after the build command; it simply passes them through. In general, ``scan-build`` should support parallel builds, but **not distributed builds**.
+In almost all cases, `scan-build` makes no effort to interpret the options after the build command; it simply passes them through. In general, `scan-build` should support parallel builds, but **not distributed builds**.
-It is also possible to use ``scan-build`` to analyze specific files::
+It is also possible to use `scan-build` to analyze specific files:
- $ scan-build gcc -c t1.c t2.c
+```
+$ scan-build gcc -c t1.c t2.c
+```
-This example causes the files ``t1.c`` and ``t2.c`` to be analyzed.
+This example causes the files `t1.c` and `t2.c` to be analyzed.
-For Windows Users
-~~~~~~~~~~~~~~~~~
+### For Windows Users
Windows users must have Perl installed to use scan-build.
-``scan-build.bat`` script allows you to launch scan-build in the same way as it described in the Basic Usage section above. To invoke scan-build from an arbitrary location, add the path to the folder containing scan-build.bat to your PATH environment variable.
+`scan-build.bat` script allows you to launch scan-build in the same way as it described in the Basic Usage section above. To invoke scan-build from an arbitrary location, add the path to the folder containing scan-build.bat to your PATH environment variable.
If you have unexpected compilation/make problems when running scan-build with MinGW/MSYS the following information may be helpful:
-- If getting unexpected ``"fatal error: no input files"`` while building with MSYS make from the Windows cmd, try one of these solutions:
- - Use MinGW ``mingw32-make`` instead of MSYS ``make`` and exclude the path to MSYS from PATH to prevent ``mingw32-make`` from using MSYS utils. MSYS utils are dependent on the MSYS runtime and they are not intended for being run from the Windows cmd. Specifically, makefile commands with backslashed quotes may be heavily corrupted when passed for execution.
- - Run ``make`` from the sh shell::
+- If getting unexpected `"fatal error: no input files"` while building with MSYS make from the Windows cmd, try one of these solutions:
+ \- Use MinGW `mingw32-make` instead of MSYS `make` and exclude the path to MSYS from PATH to prevent `mingw32-make` from using MSYS utils. MSYS utils are dependent on the MSYS runtime and they are not intended for being run from the Windows cmd. Specifically, makefile commands with backslashed quotes may be heavily corrupted when passed for execution.
+ \- Run `make` from the sh shell:
- $ scan-build [scan-build options] sh -c "make [make options]"
+ ```
+ $ scan-build [scan-build options] sh -c "make [make options]"
+ ```
-- If getting ``"Error : *** target pattern contains no `%'"`` while using GNU Make 3.81, try to use another version of make.
+- If getting `` "Error : *** target pattern contains no `%'" `` while using GNU Make 3.81, try to use another version of make.
-Other Options
-~~~~~~~~~~~~~
+### Other Options
-As mentioned above, extra options can be passed to ``scan-build``. These options prefix the build command. For example::
+As mentioned above, extra options can be passed to `scan-build`. These options prefix the build command. For example:
- $ scan-build -k -V make
- $ scan-build -k -V xcodebuild
+```
+$ scan-build -k -V make
+$ scan-build -k -V xcodebuild
+```
Here is a subset of useful options:
-- **-o**: Target directory for HTML report files. Subdirectories will be created as needed to represent separate "runs" of the analyzer. If this option is not specified, a directory is created in ``/tmp`` to store the reports.
-- **-h** *(or no arguments)*: Display all ``scan-build`` options.
-- **-k**, **--keep-going**: Add a "keep on going" option to the specified build command. This option currently supports ``make`` and ``xcodebuild``. This is a convenience option; one can specify this behavior directly using build options.
+- **-o**: Target directory for HTML report files. Subdirectories will be created as needed to represent separate "runs" of the analyzer. If this option is not specified, a directory is created in `/tmp` to store the reports.
+- **-h** *(or no arguments)*: Display all `scan-build` options.
+- **-k**, **--keep-going**: Add a "keep on going" option to the specified build command. This option currently supports `make` and `xcodebuild`. This is a convenience option; one can specify this behavior directly using build options.
- **-v**: Verbose output from scan-build and the analyzer. **A second and third "-v" increases verbosity**, and is useful for filing bug reports against the analyzer.
- **-V**: View analysis results in a web browser when the build command completes.
-- **--use-analyzer Xcode** *(or)* **--use-analyzer [path to clang]**: ``scan-build`` uses the 'clang' executable relative to itself for static analysis. One can override this behavior with this option by using the 'clang' packaged with Xcode (on OS X) or from the PATH.
+- **--use-analyzer Xcode** *(or)* **--use-analyzer [path to clang]**: `scan-build` uses the 'clang' executable relative to itself for static analysis. One can override this behavior with this option by using the 'clang' packaged with Xcode (on OS X) or from the PATH.
-A complete list of options can be obtained by running ``scan-build`` with no arguments.
+A complete list of options can be obtained by running `scan-build` with no arguments.
-Output of scan-build
-~~~~~~~~~~~~~~~~~~~~
+### Output of scan-build
-The output of scan-build is a set of HTML files, each one which represents a separate bug report. A single ``index.html`` file is generated for surveying all of the bugs. You can then just open ``index.html`` in a web browser to view the bug reports.
+The output of scan-build is a set of HTML files, each one which represents a separate bug report. A single `index.html` file is generated for surveying all of the bugs. You can then just open `index.html` in a web browser to view the bug reports.
-Where the HTML files are generated is specified with a **-o** option to ``scan-build``. If **-o** isn't specified, a directory in ``/tmp`` is created to store the files (``scan-build`` will print a message telling you where they are). If you want to view the reports immediately after the build completes, pass **-V** to ``scan-build``.
+Where the HTML files are generated is specified with a **-o** option to `scan-build`. If **-o** isn't specified, a directory in `/tmp` is created to store the files (`scan-build` will print a message telling you where they are). If you want to view the reports immediately after the build completes, pass **-V** to `scan-build`.
-Recommended Usage Guidelines
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+### Recommended Usage Guidelines
This section describes a few recommendations with running the analyzer.
-Always Analyze a Project in its "Debug" Configuration
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+### Always Analyze a Project in its "Debug" Configuration
Most projects can be built in a "debug" mode that enables assertions. Assertions are picked up by the static analyzer to prune infeasible paths, which in some cases can greatly reduce the number of false positives (bogus error reports) emitted by the tool.
-Another option is to use ``--force-analyze-debug-code`` flag of **scan-build** tool which would enable assertions automatically.
+Another option is to use `--force-analyze-debug-code` flag of **scan-build** tool which would enable assertions automatically.
-Use Verbose Output when Debugging scan-build
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+### Use Verbose Output when Debugging scan-build
-``scan-build`` takes a **-v** option to emit verbose output about what it's doing; two **-v** options emit more information. Redirecting the output of ``scan-build`` to a text file (make sure to redirect standard error) is useful for filing bug reports against ``scan-build`` or the analyzer, as we can see the exact options (and files) passed to the analyzer. For more comprehensible logs, don't perform a parallel build.
+`scan-build` takes a **-v** option to emit verbose output about what it's doing; two **-v** options emit more information. Redirecting the output of `scan-build` to a text file (make sure to redirect standard error) is useful for filing bug reports against `scan-build` or the analyzer, as we can see the exact options (and files) passed to the analyzer. For more comprehensible logs, don't perform a parallel build.
-Run './configure' through scan-build
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+### Run './configure' through scan-build
-If an analyzed project uses an autoconf generated ``configure`` script, you will probably need to run ``configure`` script through ``scan-build`` in order to analyze the project.
+If an analyzed project uses an autoconf generated `configure` script, you will probably need to run `configure` script through `scan-build` in order to analyze the project.
-**Example**::
+**Example**:
- $ scan-build ./configure
- $ scan-build --keep-cc make
+```
+$ scan-build ./configure
+$ scan-build --keep-cc make
+```
-The reason ``configure`` also needs to be run through ``scan-build`` is because ``scan-build`` scans your source files by *interposing* on the compiler. This interposition is currently done by ``scan-build`` temporarily setting the environment variable ``CC`` to ``ccc-analyzer``. The program ``ccc-analyzer`` acts like a fake compiler, forwarding its command line arguments over to the compiler to perform regular compilation and ``clang`` to perform static analysis.
+The reason `configure` also needs to be run through `scan-build` is because `scan-build` scans your source files by *interposing* on the compiler. This interposition is currently done by `scan-build` temporarily setting the environment variable `CC` to `ccc-analyzer`. The program `ccc-analyzer` acts like a fake compiler, forwarding its command line arguments over to the compiler to perform regular compilation and `clang` to perform static analysis.
-Running ``configure`` typically generates makefiles that have hardwired paths to the compiler, and by running ``configure`` through ``scan-build`` that path is set to ``ccc-analyzer``.
+Running `configure` typically generates makefiles that have hardwired paths to the compiler, and by running `configure` through `scan-build` that path is set to `ccc-analyzer`.
-Analyzing iPhone Projects
-~~~~~~~~~~~~~~~~~~~~~~~~~
+### Analyzing iPhone Projects
Conceptually Xcode projects for iPhone applications are nearly the same as their cousins for desktop applications. **scan-build** can analyze these projects as well, but users often encounter problems with just building their iPhone projects from the command line because there are a few extra preparative steps they need to take (e.g., setup code signing).
-Recommendation: use "Build and Analyze"
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+### Recommendation: use "Build and Analyze"
-The absolute easiest way to analyze iPhone projects is to use the `Analyze feature in Xcode <https://developer.apple.com/library/ios/recipes/xcode_help-source_editor/chapters/Analyze.html#//apple_ref/doc/uid/TP40009975-CH4-SW1>`_ (which is based on the static analyzer). There a user can analyze their project right from a menu without most of the setup described later.
+The absolute easiest way to analyze iPhone projects is to use the [Analyze feature in Xcode](https://developer.apple.com/library/ios/recipes/xcode_help-source_editor/chapters/Analyze.html#//apple_ref/doc/uid/TP40009975-CH4-SW1) (which is based on the static analyzer). There a user can analyze their project right from a menu without most of the setup described later.
-`Instructions are available <../xcode.html>`_ on this website on how to use open source builds of the analyzer as a replacement for the one bundled with Xcode.
+[Instructions are available](../xcode.html) on this website on how to use open source builds of the analyzer as a replacement for the one bundled with Xcode.
-Using scan-build directly
-~~~~~~~~~~~~~~~~~~~~~~~~~
+### Using scan-build directly
If you wish to use **scan-build** with your iPhone project, keep the following things in mind:
-- Analyze your project in the ``Debug`` configuration, either by setting this as your configuration with Xcode or by passing ``-configuration Debug`` to ``xcodebuild``.
-- Analyze your project using the ``Simulator`` as your base SDK. It is possible to analyze your code when targeting the device, but this is much easier to do when using Xcode's *Build and Analyze* feature.
-- Check that your code signing SDK is set to the simulator SDK as well, and make sure this option is set to ``Don't Code Sign``.
+- Analyze your project in the `Debug` configuration, either by setting this as your configuration with Xcode or by passing `-configuration Debug` to `xcodebuild`.
+- Analyze your project using the `Simulator` as your base SDK. It is possible to analyze your code when targeting the device, but this is much easier to do when using Xcode's *Build and Analyze* feature.
+- Check that your code signing SDK is set to the simulator SDK as well, and make sure this option is set to `Don't Code Sign`.
-Note that you can most of this without actually modifying your project. For example, if your application targets iPhoneOS 2.2, you could run **scan-build** in the following manner from the command line::
+Note that you can most of this without actually modifying your project. For example, if your application targets iPhoneOS 2.2, you could run **scan-build** in the following manner from the command line:
- $ scan-build xcodebuild -configuration Debug -sdk iphonesimulator2.2
+```
+$ scan-build xcodebuild -configuration Debug -sdk iphonesimulator2.2
+```
-Alternatively, if your application targets iPhoneOS 3.0::
+Alternatively, if your application targets iPhoneOS 3.0:
- $ scan-build xcodebuild -configuration Debug -sdk iphonesimulator3.0
+```
+$ scan-build xcodebuild -configuration Debug -sdk iphonesimulator3.0
+```
-Gotcha: using the right compiler
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+### Gotcha: using the right compiler
-Recall that **scan-build** analyzes your project by using a compiler to compile the project and ``clang`` to analyze your project. The script uses simple heuristics to determine which compiler should be used (it defaults to ``clang`` on Darwin and ``gcc`` on other platforms). When analyzing iPhone projects, **scan-build** may pick the wrong compiler than the one Xcode would use to build your project. For example, this could be because multiple versions of a compiler may be installed on your system, especially if you are developing for the iPhone.
+Recall that **scan-build** analyzes your project by using a compiler to compile the project and `clang` to analyze your project. The script uses simple heuristics to determine which compiler should be used (it defaults to `clang` on Darwin and `gcc` on other platforms). When analyzing iPhone projects, **scan-build** may pick the wrong compiler than the one Xcode would use to build your project. For example, this could be because multiple versions of a compiler may be installed on your system, especially if you are developing for the iPhone.
-When compiling your application to run on the simulator, it is important that **scan-build** finds the correct version of ``gcc/clang``. Otherwise, you may see strange build errors that only happen when you run ``scan-build``.
+When compiling your application to run on the simulator, it is important that **scan-build** finds the correct version of `gcc/clang`. Otherwise, you may see strange build errors that only happen when you run `scan-build`.
-**scan-build** provides the ``--use-cc`` and ``--use-c++`` options to hardwire which compiler scan-build should use for building your code. Note that although you are chiefly interested in analyzing your project, keep in mind that running the analyzer is intimately tied to the build, and not being able to compile your code means it won't get fully analyzed (if at all).
+**scan-build** provides the `--use-cc` and `--use-c++` options to hardwire which compiler scan-build should use for building your code. Note that although you are chiefly interested in analyzing your project, keep in mind that running the analyzer is intimately tied to the build, and not being able to compile your code means it won't get fully analyzed (if at all).
-If you aren't certain which compiler Xcode uses to build your project, try just running ``xcodebuild`` (without **scan-build**). You should see the full path to the compiler that Xcode is using, and use that as an argument to ``--use-cc``.
+If you aren't certain which compiler Xcode uses to build your project, try just running `xcodebuild` (without **scan-build**). You should see the full path to the compiler that Xcode is using, and use that as an argument to `--use-cc`.
-.. _command-line-usage-CodeChecker:
+(command-line-usage-codechecker)=
-CodeChecker
------------
+## CodeChecker
-Basic Usage
-~~~~~~~~~~~
+### Basic Usage
-Install CodeChecker as described here: `CodeChecker Install Guide <https://github.com/Ericsson/codechecker/#Install-guide>`_.
+Install CodeChecker as described here: [CodeChecker Install Guide](https://github.com/Ericsson/codechecker/#Install-guide).
-Create a compilation database. If you use cmake then pass the ``-DCMAKE_EXPORT_COMPILE_COMMANDS=1`` parameter to cmake. Cmake will create a ``compile_commands.json`` file.
-If you have a Makefile based or similar build system then you can log the build commands with the help of CodeChecker::
+Create a compilation database. If you use cmake then pass the `-DCMAKE_EXPORT_COMPILE_COMMANDS=1` parameter to cmake. Cmake will create a `compile_commands.json` file.
+If you have a Makefile based or similar build system then you can log the build commands with the help of CodeChecker:
- make clean
- CodeChecker log -b "make" -o compile_commands.json
+```
+make clean
+CodeChecker log -b "make" -o compile_commands.json
+```
-Analyze your project::
+Analyze your project:
- CodeChecker analyze compile_commands.json -o ./reports
+```
+CodeChecker analyze compile_commands.json -o ./reports
+```
View the analysis results.
-Print the detailed results in the command line::
+Print the detailed results in the command line:
- CodeChecker parse --print-steps ./reports
+```
+CodeChecker parse --print-steps ./reports
+```
-Or view the detailed results in a browser::
+Or view the detailed results in a browser:
- CodeChecker parse ./reports -e html -o ./reports_html
- firefox ./reports_html/index.html
+```
+CodeChecker parse ./reports -e html -o ./reports_html
+firefox ./reports_html/index.html
+```
-Optional: store the analysis results in a DB::
+Optional: store the analysis results in a DB:
- mkdir ./ws
- CodeChecker server -w ./ws -v 8555 &
- CodeChecker store ./reports --name my-project --url http://localhost:8555/Default
+```
+mkdir ./ws
+CodeChecker server -w ./ws -v 8555 &
+CodeChecker store ./reports --name my-project --url http://localhost:8555/Default
+```
-Optional: manage (categorize, suppress) the results in your web browser::
+Optional: manage (categorize, suppress) the results in your web browser:
- firefox http://localhost:8555/Default
+```
+firefox http://localhost:8555/Default
+```
-Detailed Usage
-~~~~~~~~~~~~~~
+### Detailed Usage
-For extended documentation please refer to the `official site of CodeChecker <https://github.com/Ericsson/codechecker/blob/master/docs/usage.md>`_!
+For extended documentation please refer to the [official site of CodeChecker](https://github.com/Ericsson/codechecker/blob/master/docs/usage.md)!
diff --git a/clang/docs/analyzer/user-docs/CrossTranslationUnit.md b/clang/docs/analyzer/user-docs/CrossTranslationUnit.md
index a0576bf9254ec..9396d7e4fca8d 100644
--- a/clang/docs/analyzer/user-docs/CrossTranslationUnit.md
+++ b/clang/docs/analyzer/user-docs/CrossTranslationUnit.md
@@ -1,198 +1,196 @@
-=====================================
-Cross Translation Unit (CTU) Analysis
-=====================================
+# Cross Translation Unit (CTU) Analysis
Normally, static analysis works in the boundary of one translation unit (TU).
However, with additional steps and configuration we can enable the analysis to inline the definition of a function from
another TU.
-.. contents::
- :local:
+```{contents}
+:local: true
+```
+
+## Overview
-Overview
-________
CTU analysis can be used in a variety of ways. The importing of external TU definitions can work with pre-dumped PCH
files or generating the necessary AST structure on-demand, during the analysis of the main TU. Driving the static
analysis can also be implemented in multiple ways. The most direct way is to specify the necessary commandline options
of the Clang frontend manually (and generate the prerequisite dependencies of the specific import method by hand). This
-process can be automated by other tools, like `CodeChecker <https://github.com/Ericsson/codechecker>`_ and scan-build-py
+process can be automated by other tools, like [CodeChecker](https://github.com/Ericsson/codechecker) and scan-build-py
(preference for the former).
-PCH-based analysis
-__________________
+## PCH-based analysis
+
The analysis needs the PCH dumps of all the translations units used in the project.
These can be generated by the Clang Frontend itself, and must be arranged in a specific way in the filesystem.
The index, which maps symbols' USR names to PCH dumps containing them must also be generated by the
`clang-extdef-mapping`. Entries in the index *must* have an `.ast` suffix if the goal
is to use PCH-based analysis, as the lack of that extension signals that the entry is to be used as a source-file, and parsed on-demand.
-This tool uses a :doc:`compilation database <../../JSONCompilationDatabase>` to
+This tool uses a {doc}`compilation database <../../JSONCompilationDatabase>` to
determine the compilation flags used.
The analysis invocation must be provided with the directory which contains the dumps and the mapping files.
+### Manual CTU Analysis
-Manual CTU Analysis
-###################
Let's consider these source files in our minimal example:
-.. code-block:: cpp
+```cpp
+// main.cpp
+int foo();
- // main.cpp
- int foo();
+int main() {
+ return 3 / foo();
+}
+```
- int main() {
- return 3 / foo();
- }
-
-.. code-block:: cpp
-
- // foo.cpp
- int foo() {
- return 0;
- }
+```cpp
+// foo.cpp
+int foo() {
+ return 0;
+}
+```
And a compilation database:
-.. code-block:: bash
-
- [
- {
- "directory": "/path/to/your/project",
- "command": "clang++ -c foo.cpp -o foo.o",
- "file": "foo.cpp"
- },
- {
- "directory": "/path/to/your/project",
- "command": "clang++ -c main.cpp -o main.o",
- "file": "main.cpp"
- }
- ]
+```bash
+[
+ {
+ "directory": "/path/to/your/project",
+ "command": "clang++ -c foo.cpp -o foo.o",
+ "file": "foo.cpp"
+ },
+ {
+ "directory": "/path/to/your/project",
+ "command": "clang++ -c main.cpp -o main.o",
+ "file": "main.cpp"
+ }
+]
+```
We'd like to analyze `main.cpp` and discover the division by zero bug.
In order to be able to inline the definition of `foo` from `foo.cpp` first we have to generate the `AST` (or `PCH`) file
of `foo.cpp`:
-.. code-block:: bash
-
- $ pwd $ /path/to/your/project
- $ clang++ -emit-ast -o foo.cpp.ast foo.cpp
- $ # Check that the .ast file is generated:
- $ ls
- compile_commands.json foo.cpp.ast foo.cpp main.cpp
- $
+```bash
+$ pwd $ /path/to/your/project
+$ clang++ -emit-ast -o foo.cpp.ast foo.cpp
+$ # Check that the .ast file is generated:
+$ ls
+compile_commands.json foo.cpp.ast foo.cpp main.cpp
+$
+```
The next step is to create a CTU index file which holds the `USR` name and location of external definitions in the
source files in format `<USR-Length>:<USR> <File-Path>`:
-.. code-block:: bash
-
- $ clang-extdef-mapping -p . foo.cpp.ast
- 9:c:@F at foo# /path/to/your/project/foo.cpp.ast
- $ clang-extdef-mapping -p . foo.cpp.ast > externalDefMap.txt
+```bash
+$ clang-extdef-mapping -p . foo.cpp.ast
+9:c:@F at foo# /path/to/your/project/foo.cpp.ast
+$ clang-extdef-mapping -p . foo.cpp.ast > externalDefMap.txt
+```
Now everything is available for the CTU analysis.
We have to feed Clang with CTU specific extra arguments:
-.. code-block:: bash
-
- $ pwd
- /path/to/your/project
- $ clang++ --analyze \
- -Xclang -analyzer-config -Xclang experimental-enable-naive-ctu-analysis=true \
- -Xclang -analyzer-config -Xclang ctu-dir=. \
- -Xclang -analyzer-output=plist-multi-file \
- main.cpp
- main.cpp:5:12: warning: Division by zero
- return 3 / foo();
- ~~^~~~~~~
- 1 warning generated.
- $ # The plist file with the result is generated.
- $ ls -F
- compile_commands.json externalDefMap.txt foo.ast foo.cpp foo.cpp.ast main.cpp main.plist
- $
+```bash
+$ pwd
+/path/to/your/project
+$ clang++ --analyze \
+ -Xclang -analyzer-config -Xclang experimental-enable-naive-ctu-analysis=true \
+ -Xclang -analyzer-config -Xclang ctu-dir=. \
+ -Xclang -analyzer-output=plist-multi-file \
+ main.cpp
+main.cpp:5:12: warning: Division by zero
+ return 3 / foo();
+ ~~^~~~~~~
+1 warning generated.
+$ # The plist file with the result is generated.
+$ ls -F
+compile_commands.json externalDefMap.txt foo.ast foo.cpp foo.cpp.ast main.cpp main.plist
+$
+```
This manual procedure is error-prone and not scalable, therefore to analyze real projects it is recommended to use
`CodeChecker` or `scan-build-py`.
-Automated CTU Analysis with CodeChecker
-#######################################
-The `CodeChecker <https://github.com/Ericsson/codechecker>`_ project fully supports automated CTU analysis with Clang.
-Once we have set up the `PATH` environment variable and we activated the python `venv` then it is all it takes:
-
-.. code-block:: bash
+### Automated CTU Analysis with CodeChecker
- $ CodeChecker analyze --ctu --ctu-ast-mode load-from-pch compile_commands.json -o reports
- $ ls -F
- compile_commands.json foo.cpp foo.cpp.ast main.cpp reports/
- $ tree reports
- reports
- ├── compile_cmd.json
- ├── compiler_info.json
- ├── foo.cpp_53f6fbf7ab7ec9931301524b551959e2.plist
- ├── main.cpp_23db3d8df52ff0812e6e5a03071c8337.plist
- ├── metadata.json
- └── unique_compile_commands.json
+The [CodeChecker](https://github.com/Ericsson/codechecker) project fully supports automated CTU analysis with Clang.
+Once we have set up the `PATH` environment variable and we activated the python `venv` then it is all it takes:
- 0 directories, 6 files
- $
+```bash
+$ CodeChecker analyze --ctu --ctu-ast-mode load-from-pch compile_commands.json -o reports
+$ ls -F
+compile_commands.json foo.cpp foo.cpp.ast main.cpp reports/
+$ tree reports
+reports
+├── compile_cmd.json
+├── compiler_info.json
+├── foo.cpp_53f6fbf7ab7ec9931301524b551959e2.plist
+├── main.cpp_23db3d8df52ff0812e6e5a03071c8337.plist
+├── metadata.json
+└── unique_compile_commands.json
+
+0 directories, 6 files
+$
+```
The `plist` files contain the results of the analysis, which may be viewed with the regular analysis tools.
E.g. one may use `CodeChecker parse` to view the results in command line:
-.. code-block:: bash
-
- $ CodeChecker parse reports
- [HIGH] /home/egbomrt/ctu_mini_raw_project/main.cpp:5:12: Division by zero [core.DivideZero]
- return 3 / foo();
- ^
-
- Found 1 defect(s) in main.cpp
-
-
- ----==== Summary ====----
- -----------------------
- Filename | Report count
- -----------------------
- main.cpp | 1
- -----------------------
- -----------------------
- Severity | Report count
- -----------------------
- HIGH | 1
- -----------------------
- ----=================----
- Total number of reports: 1
- ----=================----
+```bash
+$ CodeChecker parse reports
+[HIGH] /home/egbomrt/ctu_mini_raw_project/main.cpp:5:12: Division by zero [core.DivideZero]
+ return 3 / foo();
+ ^
+
+Found 1 defect(s) in main.cpp
+
+
+----==== Summary ====----
+-----------------------
+Filename | Report count
+-----------------------
+main.cpp | 1
+-----------------------
+-----------------------
+Severity | Report count
+-----------------------
+HIGH | 1
+-----------------------
+----=================----
+Total number of reports: 1
+----=================----
+```
Or we can use `CodeChecker parse -e html` to export the results into HTML format:
-.. code-block:: bash
+```bash
+$ CodeChecker parse -e html -o html_out reports
+$ firefox html_out/index.html
+```
- $ CodeChecker parse -e html -o html_out reports
- $ firefox html_out/index.html
+### Automated CTU Analysis with scan-build-py (don't do it)
-Automated CTU Analysis with scan-build-py (don't do it)
-#############################################################
We actively develop CTU with CodeChecker as the driver for this feature, `scan-build-py` is not actively developed for CTU.
`scan-build-py` has various errors and issues, expect it to work only with the very basic projects only.
Example usage of scan-build-py:
-.. code-block:: bash
+```bash
+$ /your/path/to/llvm-project/clang/tools/scan-build-py/bin/analyze-build --ctu
+analyze-build: Run 'scan-view /tmp/scan-build-2019-07-17-17-53-33-810365-7fqgWk' to examine bug reports.
+$ /your/path/to/llvm-project/clang/tools/scan-view/bin/scan-view /tmp/scan-build-2019-07-17-17-53-33-810365-7fqgWk
+Starting scan-view at: http://127.0.0.1:8181
+ Use Ctrl-C to exit.
+[6336:6431:0717/175357.633914:ERROR:browser_process_sub_thread.cc(209)] Waited 5 ms for network service
+Opening in existing browser session.
+^C
+$
+```
- $ /your/path/to/llvm-project/clang/tools/scan-build-py/bin/analyze-build --ctu
- analyze-build: Run 'scan-view /tmp/scan-build-2019-07-17-17-53-33-810365-7fqgWk' to examine bug reports.
- $ /your/path/to/llvm-project/clang/tools/scan-view/bin/scan-view /tmp/scan-build-2019-07-17-17-53-33-810365-7fqgWk
- Starting scan-view at: http://127.0.0.1:8181
- Use Ctrl-C to exit.
- [6336:6431:0717/175357.633914:ERROR:browser_process_sub_thread.cc(209)] Waited 5 ms for network service
- Opening in existing browser session.
- ^C
- $
+(ctu-on-demand)=
-.. _ctu-on-demand:
+## On-demand analysis
-On-demand analysis
-__________________
The analysis produces the necessary AST structure of external TUs during analysis. This requires the
exact compiler invocations for each TU, which can be generated by hand, or by tools driving the analyzer.
The compiler invocation is a shell command that could be used to compile the TU-s main source file.
@@ -203,162 +201,161 @@ The index, which maps function USR names to source files containing them must al
`clang-extdef-mapping`. Entries in the index must *not* have an `.ast` suffix if the goal
is to use On-demand analysis, as that extension signals that the entry is to be used as an PCH-dump.
The mapping of external definitions implicitly uses a
-:doc:`compilation database <../../JSONCompilationDatabase>` to determine the compilation flags used.
+{doc}`compilation database <../../JSONCompilationDatabase>` to determine the compilation flags used.
The analysis invocation must be provided with the directory which contains the mapping
files, and the `invocation list` which is used to determine compiler flags.
-
-Manual CTU Analysis
-###################
+### Manual CTU Analysis
Let's consider these source files in our minimal example:
-.. code-block:: cpp
+```cpp
+// main.cpp
+int foo();
- // main.cpp
- int foo();
+int main() {
+ return 3 / foo();
+}
+```
- int main() {
- return 3 / foo();
- }
-
-.. code-block:: cpp
-
- // foo.cpp
- int foo() {
- return 0;
- }
+```cpp
+// foo.cpp
+int foo() {
+ return 0;
+}
+```
The compilation database:
-.. code-block:: bash
-
- [
- {
- "directory": "/path/to/your/project",
- "command": "clang++ -c foo.cpp -o foo.o",
- "file": "foo.cpp"
- },
- {
- "directory": "/path/to/your/project",
- "command": "clang++ -c main.cpp -o main.o",
- "file": "main.cpp"
- }
- ]
+```bash
+[
+ {
+ "directory": "/path/to/your/project",
+ "command": "clang++ -c foo.cpp -o foo.o",
+ "file": "foo.cpp"
+ },
+ {
+ "directory": "/path/to/your/project",
+ "command": "clang++ -c main.cpp -o main.o",
+ "file": "main.cpp"
+ }
+]
+```
The `invocation list`:
-.. code-block:: bash
-
- "/path/to/your/project/foo.cpp":
- - "clang++"
- - "-c"
- - "/path/to/your/project/foo.cpp"
- - "-o"
- - "/path/to/your/project/foo.o"
-
- "/path/to/your/project/main.cpp":
- - "clang++"
- - "-c"
- - "/path/to/your/project/main.cpp"
- - "-o"
- - "/path/to/your/project/main.o"
+```bash
+"/path/to/your/project/foo.cpp":
+ - "clang++"
+ - "-c"
+ - "/path/to/your/project/foo.cpp"
+ - "-o"
+ - "/path/to/your/project/foo.o"
+
+"/path/to/your/project/main.cpp":
+ - "clang++"
+ - "-c"
+ - "/path/to/your/project/main.cpp"
+ - "-o"
+ - "/path/to/your/project/main.o"
+```
We'd like to analyze `main.cpp` and discover the division by zero bug.
As we are using On-demand mode, we only need to create a CTU index file which holds the `USR` name and location of
external definitions in the source files in format `<USR-Length>:<USR> <File-Path>`:
-.. code-block:: bash
-
- $ clang-extdef-mapping -p . foo.cpp
- 9:c:@F at foo# /path/to/your/project/foo.cpp
- $ clang-extdef-mapping -p . foo.cpp > externalDefMap.txt
+```bash
+$ clang-extdef-mapping -p . foo.cpp
+9:c:@F at foo# /path/to/your/project/foo.cpp
+$ clang-extdef-mapping -p . foo.cpp > externalDefMap.txt
+```
Now everything is available for the CTU analysis.
We have to feed Clang with CTU specific extra arguments:
-.. code-block:: bash
-
- $ pwd
- /path/to/your/project
- $ clang++ --analyze \
- -Xclang -analyzer-config -Xclang experimental-enable-naive-ctu-analysis=true \
- -Xclang -analyzer-config -Xclang ctu-dir=. \
- -Xclang -analyzer-config -Xclang ctu-invocation-list=invocations.yaml \
- -Xclang -analyzer-output=plist-multi-file \
- main.cpp
- main.cpp:5:12: warning: Division by zero
- return 3 / foo();
- ~~^~~~~~~
- 1 warning generated.
- $ # The plist file with the result is generated.
- $ ls -F
- compile_commands.json externalDefMap.txt foo.cpp main.cpp main.plist
- $
+```bash
+$ pwd
+/path/to/your/project
+$ clang++ --analyze \
+ -Xclang -analyzer-config -Xclang experimental-enable-naive-ctu-analysis=true \
+ -Xclang -analyzer-config -Xclang ctu-dir=. \
+ -Xclang -analyzer-config -Xclang ctu-invocation-list=invocations.yaml \
+ -Xclang -analyzer-output=plist-multi-file \
+ main.cpp
+main.cpp:5:12: warning: Division by zero
+ return 3 / foo();
+ ~~^~~~~~~
+1 warning generated.
+$ # The plist file with the result is generated.
+$ ls -F
+compile_commands.json externalDefMap.txt foo.cpp main.cpp main.plist
+$
+```
This manual procedure is error-prone and not scalable, therefore to analyze real projects it is recommended to use
`CodeChecker` or `scan-build-py`.
-Automated CTU Analysis with CodeChecker
-#######################################
-The `CodeChecker <https://github.com/Ericsson/codechecker>`_ project fully supports automated CTU analysis with Clang.
-Once we have set up the `PATH` environment variable and we activated the python `venv` then it is all it takes:
-
-.. code-block:: bash
+### Automated CTU Analysis with CodeChecker
- $ CodeChecker analyze --ctu compile_commands.json -o reports
- $ ls -F
- compile_commands.json foo.cpp main.cpp reports/
- $ tree reports
- reports
- ├── compile_cmd.json
- ├── compiler_info.json
- ├── foo.cpp_53f6fbf7ab7ec9931301524b551959e2.plist
- ├── main.cpp_23db3d8df52ff0812e6e5a03071c8337.plist
- ├── metadata.json
- └── unique_compile_commands.json
+The [CodeChecker](https://github.com/Ericsson/codechecker) project fully supports automated CTU analysis with Clang.
+Once we have set up the `PATH` environment variable and we activated the python `venv` then it is all it takes:
- 0 directories, 6 files
- $
+```bash
+$ CodeChecker analyze --ctu compile_commands.json -o reports
+$ ls -F
+compile_commands.json foo.cpp main.cpp reports/
+$ tree reports
+reports
+├── compile_cmd.json
+├── compiler_info.json
+├── foo.cpp_53f6fbf7ab7ec9931301524b551959e2.plist
+├── main.cpp_23db3d8df52ff0812e6e5a03071c8337.plist
+├── metadata.json
+└── unique_compile_commands.json
+
+0 directories, 6 files
+$
+```
The `plist` files contain the results of the analysis, which may be viewed with the regular analysis tools.
E.g. one may use `CodeChecker parse` to view the results in command line:
-.. code-block:: bash
-
- $ CodeChecker parse reports
- [HIGH] /home/egbomrt/ctu_mini_raw_project/main.cpp:5:12: Division by zero [core.DivideZero]
- return 3 / foo();
- ^
-
- Found 1 defect(s) in main.cpp
-
-
- ----==== Summary ====----
- -----------------------
- Filename | Report count
- -----------------------
- main.cpp | 1
- -----------------------
- -----------------------
- Severity | Report count
- -----------------------
- HIGH | 1
- -----------------------
- ----=================----
- Total number of reports: 1
- ----=================----
+```bash
+$ CodeChecker parse reports
+[HIGH] /home/egbomrt/ctu_mini_raw_project/main.cpp:5:12: Division by zero [core.DivideZero]
+ return 3 / foo();
+ ^
+
+Found 1 defect(s) in main.cpp
+
+
+----==== Summary ====----
+-----------------------
+Filename | Report count
+-----------------------
+main.cpp | 1
+-----------------------
+-----------------------
+Severity | Report count
+-----------------------
+HIGH | 1
+-----------------------
+----=================----
+Total number of reports: 1
+----=================----
+```
Or we can use `CodeChecker parse -e html` to export the results into HTML format:
-.. code-block:: bash
+```bash
+$ CodeChecker parse -e html -o html_out reports
+$ firefox html_out/index.html
+```
- $ CodeChecker parse -e html -o html_out reports
- $ firefox html_out/index.html
+### Automated CTU Analysis with scan-build-py (don't do it)
-Automated CTU Analysis with scan-build-py (don't do it)
-#######################################################
We actively develop CTU with CodeChecker as the driver for feature, `scan-build-py` is not actively developed for CTU.
`scan-build-py` has various errors and issues, expect it to work only with the very basic projects only.
Currently On-demand analysis is not supported with `scan-build-py`.
+
diff --git a/clang/docs/analyzer/user-docs/FAQ.md b/clang/docs/analyzer/user-docs/FAQ.md
index 58eac783efccd..7003fc9c145da 100644
--- a/clang/docs/analyzer/user-docs/FAQ.md
+++ b/clang/docs/analyzer/user-docs/FAQ.md
@@ -1,115 +1,110 @@
-FAQ and How to Deal with Common False Positives
-===============================================
+# FAQ and How to Deal with Common False Positives
-.. contents::
- :local:
+```{contents}
+:local: true
+```
-Custom Assertions
------------------
+## Custom Assertions
Q: How do I tell the analyzer that I do not want the bug being reported here since my custom error handler will safely end the execution before the bug is reached?
-.. image:: ../images/example_custom_assert.png
+```{image} ../images/example_custom_assert.png
+```
-You can tell the analyzer that this path is unreachable by teaching it about your `custom assertion handlers <Annotations.html#custom-assertion-handlers>`__. For example, you can modify the code segment as following:
+You can tell the analyzer that this path is unreachable by teaching it about your [custom assertion handlers](Annotations.html#custom-assertion-handlers). For example, you can modify the code segment as following:
-.. code-block:: c
+```c
+void customAssert() __attribute__((analyzer_noreturn));
+int foo(int *b) {
+ if (!b)
+ customAssert();
+ return *b;
+}
+```
- void customAssert() __attribute__((analyzer_noreturn));
- int foo(int *b) {
- if (!b)
- customAssert();
- return *b;
- }
-
-Null Pointer Dereference
-------------------------
+## Null Pointer Dereference
Q: The analyzer reports a null dereference, but I know that the pointer is never null. How can I tell the analyzer that a pointer can never be null?
-.. image:: ../images/example_null_pointer.png
+```{image} ../images/example_null_pointer.png
+```
The reason the analyzer often thinks that a pointer can be null is because the preceding code checked compared it against null. If you are absolutely sure that it cannot be null, remove the preceding check and, preferably, add an assertion as well. For example:
-.. code-block:: c
-
- void usePointer(int *b);
- int foo(int *b) {
- usePointer(b);
- return *b;
- }
+```c
+void usePointer(int *b);
+int foo(int *b) {
+ usePointer(b);
+ return *b;
+}
+```
-Dead Store
-----------
+## Dead Store
Q: How do I tell the static analyzer that I don't care about a specific dead store?
When the analyzer sees that a value stored into a variable is never used, it's going to produce a message similar to this one:
-.. code-block:: none
+```none
+Value stored to 'x' is never read
+```
- Value stored to 'x' is never read
+You can use the `(void)x;` idiom to acknowledge that there is a dead store in your code but you do not want it to be reported in the future.
-You can use the ``(void)x;`` idiom to acknowledge that there is a dead store in your code but you do not want it to be reported in the future.
-
-Unused Instance Variable
-------------------------
+## Unused Instance Variable
Q: How do I tell the static analyzer that I don't care about a specific unused instance variable in Objective-C?
When the analyzer sees that a value stored into a variable is never used, it is going to produce a message similar to this one:
-.. code-block:: none
-
- Instance variable 'commonName' in class 'HappyBird' is never used by the methods in its @implementation
+```none
+Instance variable 'commonName' in class 'HappyBird' is never used by the methods in its @implementation
+```
-You can add ``__attribute__((unused))`` to the instance variable declaration to suppress the warning.
+You can add `__attribute__((unused))` to the instance variable declaration to suppress the warning.
-Unlocalized String
-------------------
+## Unlocalized String
Q: How do I tell the static analyzer that I don't care about a specific unlocalized string?
When the analyzer sees that an unlocalized string is passed to a method that will present that string to the user, it is going to produce a message similar to this one:
-.. code-block:: none
-
- User-facing text should use localized string macro
+```none
+User-facing text should use localized string macro
+```
If your project deliberately uses unlocalized user-facing strings (for example, in a debugging UI that is never shown to users), you can suppress the analyzer warnings (and document your intent) with a function that just returns its input but is annotated to return a localized string:
-.. code-block:: objc
-
- __attribute__((annotate("returns_localized_nsstring")))
- static inline NSString *LocalizationNotNeeded(NSString *s) {
- return s;
- }
+```objc
+__attribute__((annotate("returns_localized_nsstring")))
+static inline NSString *LocalizationNotNeeded(NSString *s) {
+ return s;
+}
+```
You can then call this function when creating your debugging UI:
-.. code-block:: objc
-
- [field setStringValue:LocalizationNotNeeded(@"Debug")];
+```objc
+[field setStringValue:LocalizationNotNeeded(@"Debug")];
+```
Some projects may also find it useful to use NSLocalizedString but add "DNL" or "Do Not Localize" to the string contents as a convention:
-.. code-block:: objc
+```objc
+UILabel *testLabel = [[UILabel alloc] init];
+NSString *s = NSLocalizedString(@"Hello <Do Not Localize>", @"For debug purposes");
+[testLabel setText:s];
+```
- UILabel *testLabel = [[UILabel alloc] init];
- NSString *s = NSLocalizedString(@"Hello <Do Not Localize>", @"For debug purposes");
- [testLabel setText:s];
-
-Dealloc in Manual Retain/Release
---------------------------------
+## Dealloc in Manual Retain/Release
Q: How do I tell the analyzer that my instance variable does not need to be released in -dealloc under Manual Retain/Release?
-If your class only uses an instance variable for part of its lifetime, it may maintain an invariant guaranteeing that the instance variable is always released before -dealloc. In this case, you can silence a warning about a missing release by either adding ``assert(_ivar == nil)`` or an explicit release ``[_ivar release]`` (which will be a no-op when the variable is nil) in -dealloc.
+If your class only uses an instance variable for part of its lifetime, it may maintain an invariant guaranteeing that the instance variable is always released before -dealloc. In this case, you can silence a warning about a missing release by either adding `assert(_ivar == nil)` or an explicit release `[_ivar release]` (which will be a no-op when the variable is nil) in -dealloc.
-Deciding Nullability
---------------------
+## Deciding Nullability
-Q: How do I decide whether a method's return type should be _Nullable or _Nonnull?
+Q: How do I decide whether a method's return type should be \_Nullable or \_Nonnull?
Depending on the implementation of the method, this puts you in one of five situations:
@@ -119,98 +114,96 @@ Depending on the implementation of the method, this puts you in one of five situ
4. You return nil only when the caller passes input documented to be invalid. That means it's the client's fault.
5. You return nil in some totally undocumented case.
-In (1) you should annotate the method as returning a ``_Nonnull`` object.
+In (1) you should annotate the method as returning a `_Nonnull` object.
-In (2) the method should be marked ``_Nullable``.
+In (2) the method should be marked `_Nullable`.
-In (3) you should probably annotate the method ``_Nonnull``. Why? Because no callers will actually check for nil, given that they can't do anything about the situation and don't know what went wrong. At this point things have gone so poorly that there's basically no way to recover.
+In (3) you should probably annotate the method `_Nonnull`. Why? Because no callers will actually check for nil, given that they can't do anything about the situation and don't know what went wrong. At this point things have gone so poorly that there's basically no way to recover.
-The least happy case is (4) because the resulting program will almost certainly either crash or just silently do the wrong thing. If this is a new method or you control the callers, you can use ``NSParameterAssert()`` (or the equivalent) to check the precondition and remove the nil return. But if you don't control the callers and they rely on this behavior, you should return mark the method ``_Nonnull`` and return nil cast to _Nonnull anyway.
+The least happy case is (4) because the resulting program will almost certainly either crash or just silently do the wrong thing. If this is a new method or you control the callers, you can use `NSParameterAssert()` (or the equivalent) to check the precondition and remove the nil return. But if you don't control the callers and they rely on this behavior, you should return mark the method `_Nonnull` and return nil cast to \_Nonnull anyway.
If you're in (5), document it, then figure out if you're now in (2), (3), or (4).
-Intentional Nullability Violation
----------------------------------
+## Intentional Nullability Violation
Q: How do I tell the analyzer that I am intentionally violating nullability?
-In some cases, it may make sense for methods to intentionally violate nullability. For example, your method may — for reasons of backward compatibility — chose to return nil and log an error message in a method with a non-null return type when the client violated a documented precondition rather than check the precondition with ``NSAssert()``. In these cases, you can suppress the analyzer warning with a cast:
-
-.. code-block:: objc
+In some cases, it may make sense for methods to intentionally violate nullability. For example, your method may — for reasons of backward compatibility — chose to return nil and log an error message in a method with a non-null return type when the client violated a documented precondition rather than check the precondition with `NSAssert()`. In these cases, you can suppress the analyzer warning with a cast:
- return (id _Nonnull)nil;
+```objc
+return (id _Nonnull)nil;
+```
Note that this cast does not affect code generation.
-Ensuring Loop Body Execution
-----------------------------
+## Ensuring Loop Body Execution
Q: The analyzer assumes that a loop body is never entered. How can I tell it that the loop body will be entered at least once?
-.. image:: ../images/example_use_assert.png
+```{image} ../images/example_use_assert.png
+```
In cases where you know that a loop will always be entered at least once, you can use assertions to inform the analyzer. For example:
-.. code-block:: c
-
- int foo(int length) {
- int x = 0;
- assert(length > 0);
- for (int i = 0; i < length; i++)
- x += 1;
- return length/x;
- }
+```c
+int foo(int length) {
+ int x = 0;
+ assert(length > 0);
+ for (int i = 0; i < length; i++)
+ x += 1;
+ return length/x;
+}
+```
-By adding ``assert(length > 0)`` in the beginning of the function, you tell the analyzer that your code is never expecting a zero or a negative value, so it won't need to test the correctness of those paths.
+By adding `assert(length > 0)` in the beginning of the function, you tell the analyzer that your code is never expecting a zero or a negative value, so it won't need to test the correctness of those paths.
-Suppressing Specific Warnings
------------------------------
+## Suppressing Specific Warnings
Q: How can I suppress a specific analyzer warning?
-When you encounter an analyzer bug/false positive, check if it's one of the issues discussed above or if the analyzer `annotations <Annotations.html#custom-assertion-handlers>`__ can resolve the issue by helping the static analyzer understand the code better. Second, please `report it <FilingBugs.html>`_ to help us improve user experience.
+When you encounter an analyzer bug/false positive, check if it's one of the issues discussed above or if the analyzer [annotations](Annotations.html#custom-assertion-handlers) can resolve the issue by helping the static analyzer understand the code better. Second, please [report it](FilingBugs.html) to help us improve user experience.
Sometimes there's really no "good" way to eliminate the issue. In such cases you can "silence" it directly by annotating the problematic line of code with the help of Clang attribute 'suppress':
-.. code-block:: c
+```c
+int foo() {
+ int *x = nullptr;
+ ...
+ [[clang::suppress]] {
+ // all warnings in this scope are suppressed
+ int y = *x;
+ }
- int foo() {
- int *x = nullptr;
- ...
- [[clang::suppress]] {
- // all warnings in this scope are suppressed
- int y = *x;
- }
+ // null pointer dereference warning suppressed on the next line
+ [[clang::suppress]]
+ return *x
+}
- // null pointer dereference warning suppressed on the next line
- [[clang::suppress]]
- return *x
- }
+int bar(bool coin_flip) {
+ // suppress all memory leak warnings about this allocation
+ [[clang::suppress]]
+ int *result = (int *)malloc(sizeof(int));
- int bar(bool coin_flip) {
- // suppress all memory leak warnings about this allocation
- [[clang::suppress]]
- int *result = (int *)malloc(sizeof(int));
+ if (coin_flip)
+ return 0; // including this leak path
- if (coin_flip)
- return 0; // including this leak path
+ return *result; // as well as this leak path
+}
+```
- return *result; // as well as this leak path
- }
+(exclude-code)=
-.. _exclude_code:
-
-Excluding Code from Analysis
-----------------------------
+## Excluding Code from Analysis
Q: How can I selectively exclude code the analyzer examines?
-When the static analyzer is using clang to parse source files, it implicitly defines the preprocessor macro ``__clang_analyzer__``. One can use this macro to selectively exclude code the analyzer examines. Here is an example:
-
-.. code-block:: c
+When the static analyzer is using clang to parse source files, it implicitly defines the preprocessor macro `__clang_analyzer__`. One can use this macro to selectively exclude code the analyzer examines. Here is an example:
- #ifndef __clang_analyzer__
- // Code not to be analyzed
- #endif
+```c
+#ifndef __clang_analyzer__
+// Code not to be analyzed
+#endif
+```
This usage is discouraged because it makes the code dead to the analyzer from now on. Instead, we prefer that users file bugs against the analyzer when it flags false positives.
+
diff --git a/clang/docs/analyzer/user-docs/FilingBugs.md b/clang/docs/analyzer/user-docs/FilingBugs.md
index 4fd7100b38d42..ab3fedbe2a155 100644
--- a/clang/docs/analyzer/user-docs/FilingBugs.md
+++ b/clang/docs/analyzer/user-docs/FilingBugs.md
@@ -1,18 +1,16 @@
-Filing Bugs and Feature Requests
-================================
+# Filing Bugs and Feature Requests
We encourage users to file bug reports for any problems that they encounter.
We also welcome feature requests. When filing a bug report, please do the
following:
- Include the checker build (for prebuilt Mac OS X binaries) or the git hash.
-
- Provide a self-contained, reduced test case that exhibits the issue you are
experiencing.
-
- Test cases don't tell us everything. Please briefly describe the problem you
are seeing, including what you thought should have been the expected behavior
and why.
-Please `file bugs and feature requests <https://llvm.org/docs/HowToSubmitABug.html>`_
-in `LLVM's issue tracker <https://github.com/llvm/llvm-project/issues>`_ and label the report with the ``clang:static analyzer`` label.
+Please [file bugs and feature requests](https://llvm.org/docs/HowToSubmitABug.html)
+in [LLVM's issue tracker](https://github.com/llvm/llvm-project/issues) and label the report with the `clang:static analyzer` label.
+
diff --git a/clang/docs/analyzer/user-docs/Installation.md b/clang/docs/analyzer/user-docs/Installation.md
index 8d2b3aca6e474..7b723c411fe9b 100644
--- a/clang/docs/analyzer/user-docs/Installation.md
+++ b/clang/docs/analyzer/user-docs/Installation.md
@@ -1,6 +1,8 @@
-:orphan:
+---
+orphan: true
+---
-Obtaining the Static Analyzer
-=============================
+# Obtaining the Static Analyzer
+
+The Static Analyzer can be obtained as a part of Clang; for downloading and installing Clang visit the [LLVM releases page](https://releases.llvm.org/). Once the analyzer is installed, follow the {doc}`CommandLineUsage` on using the command line to get started analyzing your code.
-The Static Analyzer can be obtained as a part of Clang; for downloading and installing Clang visit the `LLVM releases page <https://releases.llvm.org/>`_. Once the analyzer is installed, follow the :doc:`CommandLineUsage` on using the command line to get started analyzing your code.
diff --git a/clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.md b/clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.md
index 4849a553cb2ce..b631ef2712c13 100644
--- a/clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.md
+++ b/clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.md
@@ -1,173 +1,166 @@
-============================
-Taint Analysis Configuration
-============================
+# Taint Analysis Configuration
The Clang Static Analyzer uses taint analysis to detect injection vulnerability related issues in code.
-The backbone of taint analysis in the Clang SA is the ``TaintPropagation`` modeling checker.
-The reports are emitted via the :ref:`optin-taint-GenericTaint` checker.
-The ``TaintPropagation`` checker has a default taint-related configuration.
+The backbone of taint analysis in the Clang SA is the `TaintPropagation` modeling checker.
+The reports are emitted via the {ref}`optin-taint-GenericTaint` checker.
+The `TaintPropagation` checker has a default taint-related configuration.
The built-in default settings are defined in code, and they are always in effect.
-The checker also provides a configuration interface for extending the default settings via the ``optin.taint.TaintPropagation:Config`` checker config parameter
-by providing a configuration file to the in `YAML <http://llvm.org/docs/YamlIO.html#introduction-to-yaml>`_ format.
+The checker also provides a configuration interface for extending the default settings via the `optin.taint.TaintPropagation:Config` checker config parameter
+by providing a configuration file to the in [YAML](http://llvm.org/docs/YamlIO.html#introduction-to-yaml) format.
This documentation describes the syntax of the configuration file and gives the informal semantics of the configuration options.
-.. contents::
- :local:
+```{contents}
+:local: true
+```
-.. _clangsa-taint-configuration-overview:
+(clangsa-taint-configuration-overview)=
-Overview
-________
+## Overview
Taint analysis works by checking for the occurrence of special operations during the symbolic execution of the program.
Taint analysis defines sources, sinks, and propagation rules. It identifies errors by detecting a flow of information that originates from a taint source, reaches a taint sink, and propagates through the program paths via propagation rules.
-A source, sink, or an operation that propagates taint is mainly domain-specific knowledge, but there are some built-in defaults provided by the ``TaintPropagation`` checker.
-It is possible to express that a statement sanitizes tainted values by providing a ``Filters`` section in the external configuration (see :ref:`clangsa-taint-configuration-example` and :ref:`clangsa-taint-filter-details`).
+A source, sink, or an operation that propagates taint is mainly domain-specific knowledge, but there are some built-in defaults provided by the `TaintPropagation` checker.
+It is possible to express that a statement sanitizes tainted values by providing a `Filters` section in the external configuration (see {ref}`clangsa-taint-configuration-example` and {ref}`clangsa-taint-filter-details`).
There are no default filters defined in the built-in settings.
The checker's documentation also specifies how to provide a custom taint configuration with command-line options.
-.. _clangsa-taint-configuration-example:
-
-Example configuration file
-__________________________
-
-.. code-block:: yaml
-
- # The entries that specify arguments use 0-based indexing when specifying
- # input arguments, and -1 is used to denote the return value.
-
- Filters:
- # Filter functions
- # Taint is sanitized when tainted variables are pass arguments to filters.
-
- # Filter function
- # void cleanse_first_arg(int* arg)
- #
- # Result example:
- # int x; // x is tainted
- # cleanse_first_arg(&x); // x is not tainted after the call
- - Name: cleanse_first_arg
- Args: [0]
-
- Propagations:
- # Source functions
- # The omission of SrcArgs key indicates unconditional taint propagation,
- # which is conceptually what a source does.
-
- # Source function
- # size_t fread(void *ptr, size_t size, size_t nmemb, FILE * stream)
- #
- # Result example:
- # FILE* f = fopen("file.txt");
- # char buf[1024];
- # size_t read = fread(buf, sizeof(buf[0]), sizeof(buf)/sizeof(buf[0]), f);
- # // both read and buf are tainted
- - Name: fread
- DstArgs: [0, -1]
-
- # Propagation functions
- # The presence of SrcArgs key indicates conditional taint propagation,
- # which is conceptually what a propagator does.
-
- # Propagation function
- # char *dirname(char *path)
- #
- # Result example:
- # char* path = read_path();
- # char* dir = dirname(path);
- # // dir is tainted if path was tainted
- - Name: dirname
- SrcArgs: [0]
- DstArgs: [-1]
-
- Sinks:
- # Sink functions
- # If taint reaches any of the arguments specified, a warning is emitted.
-
- # Sink function
- # int system(const char* command)
- #
- # Result example:
- # const char* command = read_command();
- # system(command); // emit diagnostic if command is tainted
- - Name: system
- Args: [0]
+(clangsa-taint-configuration-example)=
+
+## Example configuration file
+
+```yaml
+# The entries that specify arguments use 0-based indexing when specifying
+# input arguments, and -1 is used to denote the return value.
+
+Filters:
+ # Filter functions
+ # Taint is sanitized when tainted variables are pass arguments to filters.
+
+ # Filter function
+ # void cleanse_first_arg(int* arg)
+ #
+ # Result example:
+ # int x; // x is tainted
+ # cleanse_first_arg(&x); // x is not tainted after the call
+ - Name: cleanse_first_arg
+ Args: [0]
+
+Propagations:
+ # Source functions
+ # The omission of SrcArgs key indicates unconditional taint propagation,
+ # which is conceptually what a source does.
+
+ # Source function
+ # size_t fread(void *ptr, size_t size, size_t nmemb, FILE * stream)
+ #
+ # Result example:
+ # FILE* f = fopen("file.txt");
+ # char buf[1024];
+ # size_t read = fread(buf, sizeof(buf[0]), sizeof(buf)/sizeof(buf[0]), f);
+ # // both read and buf are tainted
+ - Name: fread
+ DstArgs: [0, -1]
+
+ # Propagation functions
+ # The presence of SrcArgs key indicates conditional taint propagation,
+ # which is conceptually what a propagator does.
+
+ # Propagation function
+ # char *dirname(char *path)
+ #
+ # Result example:
+ # char* path = read_path();
+ # char* dir = dirname(path);
+ # // dir is tainted if path was tainted
+ - Name: dirname
+ SrcArgs: [0]
+ DstArgs: [-1]
+
+Sinks:
+ # Sink functions
+ # If taint reaches any of the arguments specified, a warning is emitted.
+
+ # Sink function
+ # int system(const char* command)
+ #
+ # Result example:
+ # const char* command = read_command();
+ # system(command); // emit diagnostic if command is tainted
+ - Name: system
+ Args: [0]
+```
In the example file above, the entries under the `Propagation` key implement the conceptual sources and propagations, and sinks have their dedicated `Sinks` key.
The user can define operations (function calls) where the tainted values should be cleansed by listing entries under the `Filters` key.
Filters model the sanitization of values done by the programmer, and providing these is key to avoiding false-positive findings.
-Configuration file syntax and semantics
-_______________________________________
+## Configuration file syntax and semantics
-The configuration file should have valid `YAML <http://llvm.org/docs/YamlIO.html#introduction-to-yaml>`_ syntax.
+The configuration file should have valid [YAML](http://llvm.org/docs/YamlIO.html#introduction-to-yaml) syntax.
The configuration file can have the following top-level keys:
- - Filters
- - Propagations
- - Sinks
+: - Filters
+ - Propagations
+ - Sinks
-Under the `Filters` key, the user can specify a list of operations that remove taint (see :ref:`clangsa-taint-filter-details` for details).
+Under the `Filters` key, the user can specify a list of operations that remove taint (see {ref}`clangsa-taint-filter-details` for details).
-Under the `Propagations` key, the user can specify a list of operations that introduce and propagate taint (see :ref:`clangsa-taint-propagation-details` for details).
+Under the `Propagations` key, the user can specify a list of operations that introduce and propagate taint (see {ref}`clangsa-taint-propagation-details` for details).
The user can mark taint sources with a `SrcArgs` key in the `Propagation` key, while propagations have none.
The lack of the `SrcArgs` key means unconditional propagation, which is how sources are modeled.
The semantics of propagations are such, that if any of the source arguments are tainted (specified by indexes in `SrcArgs`) then all of the destination arguments (specified by indexes in `DstArgs`) also become tainted.
-Under the `Sinks` key, the user can specify a list of operations where the checker should emit a bug report if tainted data reaches it (see :ref:`clangsa-taint-sink-details` for details).
+Under the `Sinks` key, the user can specify a list of operations where the checker should emit a bug report if tainted data reaches it (see {ref}`clangsa-taint-sink-details` for details).
-.. _clangsa-taint-filter-details:
+(clangsa-taint-filter-details)=
-Filter syntax and semantics
-###########################
+### Filter syntax and semantics
-An entry under `Filters` is a `YAML <http://llvm.org/docs/YamlIO.html#introduction-to-yaml>`_ object with the following mandatory keys:
- - `Name` is a string that specifies the name of a function.
- Encountering this function during symbolic execution the checker will sanitize taint from the memory region referred to by the given arguments or return a sanitized value.
- - `Args` is a list of numbers in the range of ``[-1..int_max]``.
- It indicates the indexes of arguments in the function call.
- The number ``-1`` signifies the return value; other numbers identify call arguments.
- The values of these arguments are considered clean after the function call.
+An entry under `Filters` is a [YAML](http://llvm.org/docs/YamlIO.html#introduction-to-yaml) object with the following mandatory keys:
+: - `Name` is a string that specifies the name of a function.
+ Encountering this function during symbolic execution the checker will sanitize taint from the memory region referred to by the given arguments or return a sanitized value.
+ - `Args` is a list of numbers in the range of `[-1..int_max]`.
+ It indicates the indexes of arguments in the function call.
+ The number `-1` signifies the return value; other numbers identify call arguments.
+ The values of these arguments are considered clean after the function call.
The following keys are optional:
- - `Scope` is a string that specifies the prefix of the function's name in its fully qualified name. This option restricts the set of matching function calls. It can encode not only namespaces but struct/class names as well to match member functions.
+: - `Scope` is a string that specifies the prefix of the function's name in its fully qualified name. This option restricts the set of matching function calls. It can encode not only namespaces but struct/class names as well to match member functions.
- .. _clangsa-taint-propagation-details:
+ (clangsa-taint-propagation-details)=
-Propagation syntax and semantics
-################################
+### Propagation syntax and semantics
-An entry under `Propagation` is a `YAML <http://llvm.org/docs/YamlIO.html#introduction-to-yaml>`_ object with the following mandatory keys:
- - `Name` is a string that specifies the name of a function.
- Encountering this function during symbolic execution propagate taint from one or more arguments to other arguments and possibly the return value.
- It helps model the taint-related behavior of functions that are not analyzable otherwise.
+An entry under `Propagation` is a [YAML](http://llvm.org/docs/YamlIO.html#introduction-to-yaml) object with the following mandatory keys:
+: - `Name` is a string that specifies the name of a function.
+ Encountering this function during symbolic execution propagate taint from one or more arguments to other arguments and possibly the return value.
+ It helps model the taint-related behavior of functions that are not analyzable otherwise.
The following keys are optional:
- - `Scope` is a string that specifies the prefix of the function's name in its fully qualified name. This option restricts the set of matching function calls.
- - `SrcArgs` is a list of numbers in the range of ``[0..int_max]`` that indicates the indexes of arguments in the function call.
- Taint-propagation considers the values of these arguments during the evaluation of the function call.
- If any `SrcArgs` arguments are tainted, the checker will consider all `DstArgs` arguments tainted after the call.
- - `DstArgs` is a list of numbers in the range of ``[-1..int_max]`` that indicates the indexes of arguments in the function call.
- The number ``-1`` specifies the return value of the function.
- If any `SrcArgs` arguments are tainted, the checker will consider all `DstArgs` arguments tainted after the call.
- - `VariadicType` is a string that can be one of ``None``, ``Dst``, ``Src``.
- It is used in conjunction with `VariadicIndex` to specify arguments inside a variadic argument.
- The value of ``Src`` will treat every call site argument that is part of a variadic argument list as a source concerning propagation rules (as if specified by `SrcArg`).
- The value of ``Dst`` will treat every call site argument that is part of a variadic argument list a destination concerning propagation rules.
- The value of ``None`` will not consider the arguments that are part of a variadic argument list (this option is redundant but can be used to temporarily switch off handling of a particular variadic argument option without removing the VariadicIndex key).
- - `VariadicIndex` is a number in the range of ``[0..int_max]``. It indicates the starting index of the variadic argument in the signature of the function.
-
-
-.. _clangsa-taint-sink-details:
-
-Sink syntax and semantics
-#########################
-
-An entry under `Sinks` is a `YAML <http://llvm.org/docs/YamlIO.html#introduction-to-yaml>`_ object with the following mandatory keys:
- - `Name` is a string that specifies the name of a function.
- Encountering this function during symbolic execution will emit a taint-related diagnostic if any of the arguments specified with `Args` are tainted at the call site.
- - `Args` is a list of numbers in the range of ``[0..int_max]`` that indicates the indexes of arguments in the function call.
- The checker reports an error if any of the specified arguments are tainted.
+: - `Scope` is a string that specifies the prefix of the function's name in its fully qualified name. This option restricts the set of matching function calls.
+ - `SrcArgs` is a list of numbers in the range of `[0..int_max]` that indicates the indexes of arguments in the function call.
+ Taint-propagation considers the values of these arguments during the evaluation of the function call.
+ If any `SrcArgs` arguments are tainted, the checker will consider all `DstArgs` arguments tainted after the call.
+ - `DstArgs` is a list of numbers in the range of `[-1..int_max]` that indicates the indexes of arguments in the function call.
+ The number `-1` specifies the return value of the function.
+ If any `SrcArgs` arguments are tainted, the checker will consider all `DstArgs` arguments tainted after the call.
+ - `VariadicType` is a string that can be one of `None`, `Dst`, `Src`.
+ It is used in conjunction with `VariadicIndex` to specify arguments inside a variadic argument.
+ The value of `Src` will treat every call site argument that is part of a variadic argument list as a source concerning propagation rules (as if specified by `SrcArg`).
+ The value of `Dst` will treat every call site argument that is part of a variadic argument list a destination concerning propagation rules.
+ The value of `None` will not consider the arguments that are part of a variadic argument list (this option is redundant but can be used to temporarily switch off handling of a particular variadic argument option without removing the VariadicIndex key).
+ - `VariadicIndex` is a number in the range of `[0..int_max]`. It indicates the starting index of the variadic argument in the signature of the function.
+
+(clangsa-taint-sink-details)=
+
+### Sink syntax and semantics
+
+An entry under `Sinks` is a [YAML](http://llvm.org/docs/YamlIO.html#introduction-to-yaml) object with the following mandatory keys:
+: - `Name` is a string that specifies the name of a function.
+ Encountering this function during symbolic execution will emit a taint-related diagnostic if any of the arguments specified with `Args` are tainted at the call site.
+ - `Args` is a list of numbers in the range of `[0..int_max]` that indicates the indexes of arguments in the function call.
+ The checker reports an error if any of the specified arguments are tainted.
The following keys are optional:
- - `Scope` is a string that specifies the prefix of the function's name in its fully qualified name. This option restricts the set of matching function calls.
+: - `Scope` is a string that specifies the prefix of the function's name in its fully qualified name. This option restricts the set of matching function calls.
+
diff --git a/clang/docs/analyzer/user-docs/UsingWithXCode.md b/clang/docs/analyzer/user-docs/UsingWithXCode.md
index d4f76afa9fb9a..781dae215159d 100644
--- a/clang/docs/analyzer/user-docs/UsingWithXCode.md
+++ b/clang/docs/analyzer/user-docs/UsingWithXCode.md
@@ -1,88 +1,90 @@
-Running the analyzer within Xcode
-=================================
+# Running the analyzer within Xcode
-.. contents::
- :local:
+```{contents}
+:local: true
+```
-Since Xcode 3.2, users have been able to run the static analyzer `directly within Xcode <https://developer.apple.com/library/ios/recipes/xcode_help-source_editor/chapters/Analyze.html#//apple_ref/doc/uid/TP40009975-CH4-SW1>`_.
+Since Xcode 3.2, users have been able to run the static analyzer [directly within Xcode](https://developer.apple.com/library/ios/recipes/xcode_help-source_editor/chapters/Analyze.html#//apple_ref/doc/uid/TP40009975-CH4-SW1).
It integrates directly with the Xcode build system and presents analysis results directly within Xcode's editor.
-Can I use the open source analyzer builds with Xcode?
------------------------------------------------------
+## Can I use the open source analyzer builds with Xcode?
**Yes**. Instructions are included below.
-.. image:: ../images/analyzer_xcode.png
+```{image} ../images/analyzer_xcode.png
+```
**Viewing static analyzer results in Xcode**
-Key features:
--------------
+## Key features:
- **Integrated workflow:** Results are integrated within Xcode. There is no experience of using a separate tool, and activating the analyzer requires a single keystroke or mouse click.
- **Transparency:** Works effortlessly with Xcode projects (including iPhone projects).
-- **Cons:** Doesn't work well with non-Xcode projects. For those, consider :doc:`CommandLineUsage`.
+- **Cons:** Doesn't work well with non-Xcode projects. For those, consider {doc}`CommandLineUsage`.
-Getting Started
----------------
+## Getting Started
-Xcode is available as a free download from Apple on the `Mac App Store <https://itunes.apple.com/us/app/xcode/id497799835?mt=12>`_, with `instructions available <https://developer.apple.com/library/ios/recipes/xcode_help-source_editor/chapters/Analyze.html#//apple_ref/doc/uid/TP40009975-CH4-SW1>`_ for using the analyzer.
+Xcode is available as a free download from Apple on the [Mac App Store](https://itunes.apple.com/us/app/xcode/id497799835?mt=12), with [instructions available](https://developer.apple.com/library/ios/recipes/xcode_help-source_editor/chapters/Analyze.html#//apple_ref/doc/uid/TP40009975-CH4-SW1) for using the analyzer.
-Using open source analyzer builds with Xcode
---------------------------------------------
+## Using open source analyzer builds with Xcode
-By default, Xcode uses the version of ``clang`` that came bundled with it to analyze your code. It is possible to change Xcode's behavior to use an alternate version of ``clang`` for this purpose while continuing to use the ``clang`` that came with Xcode for compiling projects.
+By default, Xcode uses the version of `clang` that came bundled with it to analyze your code. It is possible to change Xcode's behavior to use an alternate version of `clang` for this purpose while continuing to use the `clang` that came with Xcode for compiling projects.
-Why try open source builds?
-----------------------------
+## Why try open source builds?
The advantage of using open source analyzer builds (provided on this website) is that they are often newer than the analyzer provided with Xcode, and thus can contain bug fixes, new checks, or simply better analysis.
-On the other hand, new checks can be experimental, with results of variable quality. Users are encouraged to file bug reports (for any version of the analyzer) where they encounter false positives or other issues here: :doc:`FilingBugs`.
+On the other hand, new checks can be experimental, with results of variable quality. Users are encouraged to file bug reports (for any version of the analyzer) where they encounter false positives or other issues here: {doc}`FilingBugs`.
-set-xcode-analyzer
-------------------
+## set-xcode-analyzer
-Starting with analyzer build checker-234, analyzer builds contain a command line utility called ``set-xcode-analyzer`` that allows users to change what copy of ``clang`` that Xcode uses for analysis::
+Starting with analyzer build checker-234, analyzer builds contain a command line utility called `set-xcode-analyzer` that allows users to change what copy of `clang` that Xcode uses for analysis:
- $ set-xcode-analyzer -h
- Usage: set-xcode-analyzer [options]
+```
+$ set-xcode-analyzer -h
+Usage: set-xcode-analyzer [options]
- Options:
- -h, --help show this help message and exit
- --use-checker-build=PATH
- Use the Clang located at the provided absolute path,
- e.g. /Users/foo/checker-1
- --use-xcode-clang Use the Clang bundled with Xcode
+Options:
+ -h, --help show this help message and exit
+ --use-checker-build=PATH
+ Use the Clang located at the provided absolute path,
+ e.g. /Users/foo/checker-1
+ --use-xcode-clang Use the Clang bundled with Xcode
+```
-Operationally, **set-xcode-analyzer** edits Xcode's configuration files to point it to use the version of ``clang`` you specify for static analysis. Within this model it provides you two basic modes:
+Operationally, **set-xcode-analyzer** edits Xcode's configuration files to point it to use the version of `clang` you specify for static analysis. Within this model it provides you two basic modes:
-- **--use-xcode-clang:** Switch Xcode (back) to using the ``clang`` that came bundled with it for static analysis.
-- **--use-checker-build:** Switch Xcode to using the ``clang`` provided by the specified analyzer build.
+- **--use-xcode-clang:** Switch Xcode (back) to using the `clang` that came bundled with it for static analysis.
+- **--use-checker-build:** Switch Xcode to using the `clang` provided by the specified analyzer build.
-Things to keep in mind
-----------------------
+## Things to keep in mind
-- You should quit Xcode prior to running ``set-xcode-analyzer``.
-- You will need to run ``set-xcode-analyzer`` under **``sudo``** in order to have write privileges to modify the Xcode configuration files.
+- You should quit Xcode prior to running `set-xcode-analyzer`.
+- You will need to run `set-xcode-analyzer` under **\`\`sudo\`\`** in order to have write privileges to modify the Xcode configuration files.
-Examples
---------
+## Examples
-**Example 1**: Telling Xcode to use checker-235::
+**Example 1**: Telling Xcode to use checker-235:
- $ pwd
- /tmp
- $ tar xjf checker-235.tar.bz2
- $ sudo checker-235/set-xcode-analyzer --use-checker-build=/tmp/checker-235
+```
+$ pwd
+/tmp
+$ tar xjf checker-235.tar.bz2
+$ sudo checker-235/set-xcode-analyzer --use-checker-build=/tmp/checker-235
+```
-Note that you typically won't install an analyzer build in ``/tmp``, but the point of this example is that ``set-xcode-analyzer`` just wants a full path to an untarred analyzer build.
+Note that you typically won't install an analyzer build in `/tmp`, but the point of this example is that `set-xcode-analyzer` just wants a full path to an untarred analyzer build.
-**Example 2**: Telling Xcode to use a very specific version of ``clang``::
+**Example 2**: Telling Xcode to use a very specific version of `clang`:
- $ sudo set-xcode-analyzer --use-checker-build=~/mycrazyclangbuild/bin/clang
+```
+$ sudo set-xcode-analyzer --use-checker-build=~/mycrazyclangbuild/bin/clang
+```
-**Example 3**: Resetting Xcode to its default behavior::
+**Example 3**: Resetting Xcode to its default behavior:
+
+```
+$ sudo set-xcode-analyzer --use-xcode-clang
+```
- $ sudo set-xcode-analyzer --use-xcode-clang
>From 405412255307986bfcbbc3dd5ae2851707bae2b4 Mon Sep 17 00:00:00 2001
From: Reid Kleckner <rkleckner at nvidia.com>
Date: Thu, 13 Aug 2026 22:45:46 +0000
Subject: [PATCH 2/2] [docs][clang] Finish MyST migration for analyzer docs
---
.../developer-docs/ForceLinkerHeaders.md | 3 +-
.../developer-docs/HowToExtend.md | 3 +-
.../SummaryExtractionInternals.md | 3 +-
clang/docs/analyzer/checkers.md | 25 +-
.../analyzer/developer-docs/DebugChecks.md | 5 +-
clang/docs/analyzer/developer-docs/IPA.md | 7 +-
.../developer-docs/InitializerLists.md | 65 ++-
.../analyzer/developer-docs/RegionStore.md | 3 +-
.../analyzer/developer-docs/nullability.md | 3 +-
clang/docs/analyzer/user-docs/Annotations.md | 414 +++++++++---------
.../analyzer/user-docs/CommandLineUsage.md | 43 +-
.../user-docs/CrossTranslationUnit.md | 31 +-
clang/docs/analyzer/user-docs/FAQ.md | 11 +-
.../user-docs/TaintAnalysisConfiguration.md | 3 +-
.../docs/analyzer/user-docs/UsingWithXCode.md | 11 +-
15 files changed, 314 insertions(+), 316 deletions(-)
diff --git a/clang/docs/ScalableStaticAnalysis/developer-docs/ForceLinkerHeaders.md b/clang/docs/ScalableStaticAnalysis/developer-docs/ForceLinkerHeaders.md
index daf57291477f7..701a0f6aabf84 100644
--- a/clang/docs/ScalableStaticAnalysis/developer-docs/ForceLinkerHeaders.md
+++ b/clang/docs/ScalableStaticAnalysis/developer-docs/ForceLinkerHeaders.md
@@ -8,7 +8,7 @@ The purpose of this documentation is to give context for upcoming reviews.
## The problem
-SSAF uses [llvm::Registry\<>](https://llvm.org/doxygen/classllvm_1_1Registry.html)
+SSAF uses [llvm::Registry<>](https://llvm.org/doxygen/classllvm_1_1Registry.html)
for decentralized registration of summary extractors and serialization formats.
Each registration is a file-scope static object whose constructor adds an entry
to the global registry:
@@ -149,4 +149,3 @@ void initializeSSAFRegistrations() {
the decoupled-registration benefit of `llvm::Registry`.
- Adding a new extractor or format requires modifying a central file, which
increases merge-conflict risk for downstream users.
-
diff --git a/clang/docs/ScalableStaticAnalysis/developer-docs/HowToExtend.md b/clang/docs/ScalableStaticAnalysis/developer-docs/HowToExtend.md
index 8bd88bd8c796e..e216486290862 100644
--- a/clang/docs/ScalableStaticAnalysis/developer-docs/HowToExtend.md
+++ b/clang/docs/ScalableStaticAnalysis/developer-docs/HowToExtend.md
@@ -154,7 +154,7 @@ static llvm::Registry<FormatInfo>::Add<MyAnalysisFormatInfo>
### Step 4: Add the force-linker anchor
Same pattern as for extractors — add the anchor to `BuiltinAnchorSources.def`
-(in alphabetical order). See [Adding a summary extractor] Step 3,
+(in alphabetical order). See [Adding a summary extractor](#adding-a-summary-extractor) Step 3,
and {doc}`ForceLinkerHeaders`.
## Static extensibility
@@ -205,4 +205,3 @@ To use a plugin:
No changes to any force-linker header are required.
The `llvm::Registry` infrastructure handles everything once the shared object is loaded.
-
diff --git a/clang/docs/ScalableStaticAnalysis/developer-docs/SummaryExtractionInternals.md b/clang/docs/ScalableStaticAnalysis/developer-docs/SummaryExtractionInternals.md
index 8df055ad0ce69..3f0d305cd9fa8 100644
--- a/clang/docs/ScalableStaticAnalysis/developer-docs/SummaryExtractionInternals.md
+++ b/clang/docs/ScalableStaticAnalysis/developer-docs/SummaryExtractionInternals.md
@@ -19,11 +19,10 @@ When it succeeds, it will multiplex the handlers of the ASTConsumer to every sum
### Global Registries
-The framework uses [llvm::Registry\<>](https://llvm.org/doxygen/classllvm_1_1Registry.html)
+The framework uses [llvm::Registry<>](https://llvm.org/doxygen/classllvm_1_1Registry.html)
as an extension point for adding new summary analyses or serialization formats.
Each entry in the *registry* holds a name, a description and a pointer to a constructor.
Because static linking can discard unreferenced registration objects, the framework
uses {doc}`ForceLinkerHeaders` to ensure they are retained.
For details on how to add new extractors and formats, see {doc}`HowToExtend`.
-
diff --git a/clang/docs/analyzer/checkers.md b/clang/docs/analyzer/checkers.md
index 93a494c5a3fd5..3b54c3a359c3f 100644
--- a/clang/docs/analyzer/checkers.md
+++ b/clang/docs/analyzer/checkers.md
@@ -39,7 +39,7 @@ these are logically unsound.
Moreover, if the pedantic mode is activated by
`-analyzer-config core.BitwiseShift:Pedantic=true`, then this checker also
-reports situations where the \_left\_ operand of a shift operator is negative or
+reports situations where the *left* operand of a shift operator is negative or
overflow occurs during the right shift of a signed value. (Most compilers
handle these predictably, but the C standard and the C++ standards before C++20
say that they're undefined behavior. In the C++20 standard these constructs are
@@ -690,7 +690,7 @@ Checkers (mostly Objective C) that warn for null pointer passing and dereferenci
#### nullability.NullPassedToNonnull (ObjC)
-Warns when a null pointer is passed to a pointer which has a \_Nonnull type.
+Warns when a null pointer is passed to a pointer which has a `_Nonnull` type.
```objc
if (name != nil)
@@ -703,7 +703,7 @@ NSString *greeting = [@"Hello " stringByAppendingString:name];
#### nullability.NullReturnedFromNonnull (C, C++, ObjC)
-Warns when a null pointer is returned from a function that has \_Nonnull return type.
+Warns when a null pointer is returned from a function that has `_Nonnull` return type.
```objc
- (nonnull id)firstChild {
@@ -758,7 +758,7 @@ void updateNextData(struct LinkedList *list, int newData) {
#### nullability.NullablePassedToNonnull (ObjC)
-Warns when a nullable pointer is passed to a pointer which has a \_Nonnull type.
+Warns when a nullable pointer is passed to a pointer which has a `_Nonnull` type.
```objc
typedef struct Dummy { int val; } Dummy;
@@ -775,7 +775,7 @@ void test() {
#### nullability.NullableReturnedFromNonnull (ObjC)
-Warns when a nullable pointer is returned from a function that has \_Nonnull return type.
+Warns when a nullable pointer is returned from a function that has `_Nonnull` return type.
(optin-checkers)=
@@ -1318,7 +1318,7 @@ One can get rid of this superfluous warning by telling by specifying the
sanitation functions in the taint configuration file (see
{doc}`user-docs/TaintAnalysisConfiguration`).
-```YAML
+```yaml
Filters:
- Name: sanitizeFileName
Args: [0]
@@ -1368,7 +1368,7 @@ Similarly to the previous example, you need to
define a `Filter` function in a `YAML` configuration file
and add the `csa_mark_sanitized` function.
-```YAML
+```yaml
Filters:
- Name: csa_mark_sanitized
Args: [0]
@@ -2044,7 +2044,7 @@ These are common options that affect multiple checkers in the `unix` group.
and deallocations (like `malloc` or `free`) are marked with
`ownership_holds`, `ownership_takes` and `ownership_returns`
attributes. For more information see
- [Attributes in Clang](../AttributeReference.html#ownership-holds-ownership-returns-ownership-takes-clang-static-analyzer).
+ [Attributes in Clang](../AttributeReference.md#ownership-holds-ownership-returns-ownership-takes-clang-static-analyzer).
Default value is `false`.
- `unix.DynamicMemoryModeling:ModelAllocationFailure`
@@ -2251,7 +2251,7 @@ Custom allocation/deallocation functions can be defined using
{ref}`ownership attributes<analyzer-ownership-attrs>`.
```{literalinclude} checkers/mismatched_deallocator_example.cpp
-:language: c
+:language: cpp
```
(unix-vfork)=
@@ -2462,7 +2462,7 @@ The `ModelPOSIX` option controls if functions from the POSIX standard are
recognized by the checker.
With `ModelPOSIX=true`, many POSIX functions are modeled according to the
-[POSIX standard]. This includes ranges of parameters and possible return
+[POSIX standard](https://pubs.opengroup.org/onlinepubs/9699919799/). This includes ranges of parameters and possible return
values. Furthermore the behavior related to `errno` in the POSIX case is
often that `errno` is set only if a function call fails, and it becomes
undefined after a successful function call.
@@ -2924,7 +2924,7 @@ void test() {
#### osx.coreFoundation.CFError (C)
-Check usage of CFErrorRef\* parameters
+Check usage of `CFErrorRef *` parameters
```c
void test(CFErrorRef *error) {
@@ -4090,7 +4090,7 @@ Here are some examples of cases that we consider incorrect use of RetainPtr cons
## Debug Checkers
-(debug-checkers-1)=
+(debug-checkers)=
### debug
@@ -4180,4 +4180,3 @@ View Call Graph using GraphViz.
#### debug.ViewExplodedGraph
View Exploded Graphs using GraphViz.
-
diff --git a/clang/docs/analyzer/developer-docs/DebugChecks.md b/clang/docs/analyzer/developer-docs/DebugChecks.md
index 831afed6fc4a6..b89cb91626157 100644
--- a/clang/docs/analyzer/developer-docs/DebugChecks.md
+++ b/clang/docs/analyzer/developer-docs/DebugChecks.md
@@ -89,7 +89,7 @@ inspects expressions.)
inlined function could provide different information, making it difficult to
write proper -verify directives.
- In C, the argument can be typed as 'int' or as '\_Bool'.
+ In C, the argument can be typed as 'int' or as `_Bool`.
Example usage:
@@ -115,7 +115,7 @@ inspects expressions.)
also be analyzed as a top-level function (in which case both TRUE and FALSE
would be printed), depending on the value of the -analyzer-inlining option.
- In C, the argument can be typed as 'int' or as '\_Bool'.
+ In C, the argument can be typed as 'int' or as `_Bool`.
Example usage:
@@ -376,4 +376,3 @@ least one bug report per function) may actually change the values reported by
- debug.ReportStmts reports a warning at **every** statement, making it a very
useful tool for testing thoroughly bug report construction and output
emission.
-
diff --git a/clang/docs/analyzer/developer-docs/IPA.md b/clang/docs/analyzer/developer-docs/IPA.md
index 37bf1eb6a8623..a5d1c1bfaa32c 100644
--- a/clang/docs/analyzer/developer-docs/IPA.md
+++ b/clang/docs/analyzer/developer-docs/IPA.md
@@ -168,7 +168,7 @@ some cases, however, where the analyzer chooses not to inline:
- If the function is variadic. This is not a hard limitation, but an engineering
limitation.
- Tracked by: \<<rdar://problem/12147064>> Support inlining of variadic functions
+ Tracked by: `<rdar://problem/12147064>` Support inlining of variadic functions
- In C++, constructors are not inlined unless the destructor call will be
processed by the ExprEngine. Thus, if the CFG was built without nodes for
@@ -252,7 +252,7 @@ The -analyzer-config ipa option has five different modes: none, basic-inlining,
inlining, dynamic, and dynamic-bifurcate. Under -analyzer-config ipa=dynamic,
all dynamic calls are inlined, whether we are certain or not that this will
actually be the definition used at runtime. Under -analyzer-config ipa=inlining,
-only "near-perfect" devirtualized calls are inlined\*, and other dynamic calls
+only "near-perfect" devirtualized calls are inlined*, and other dynamic calls
are evaluated conservatively (as if no definition were available).
- Currently, no Objective-C messages are not inlined under
@@ -355,10 +355,9 @@ CallEvent should be used whenever there is logic dealing with function calls
that does not care how the call occurred.
Examples include checking that arguments satisfy preconditions (such as
-\_\_attribute\_\_((nonnull))), and attempting to inline a call.
+`__attribute__((nonnull))`), and attempting to inline a call.
CallEvents are reference-counted objects managed by a CallEventManager. While
there is no inherent issue with persisting them (say, in a ProgramState's GDM),
they are intended for short-lived use, and can be recreated from CFGElements or
non-top-level StackFrames fairly easily.
-
diff --git a/clang/docs/analyzer/developer-docs/InitializerLists.md b/clang/docs/analyzer/developer-docs/InitializerLists.md
index 06e0e08ca4b6e..1c8620d7bbf59 100644
--- a/clang/docs/analyzer/developer-docs/InitializerLists.md
+++ b/clang/docs/analyzer/developer-docs/InitializerLists.md
@@ -39,7 +39,7 @@ The obvious approach to modeling `std::initializer_list` in a checker would be t
construct a SymbolMetadata for the memory region of the initializer list object,
which would be of type `T*` and represent `begin()`, so we'd trivially model `begin()`
as a function that returns this symbol. The array pointed to by that symbol
-would be ``` bindLoc()``ed to contain the list's contents (probably as a ``CompoundVal ```
+would be `bindLoc()`ed to contain the list's contents (probably as a `CompoundVal`
to produce less bindings in the store). Extent of this array would represent
`size()` and would be equal to the length of the list as written.
@@ -131,10 +131,10 @@ them more openly. As a quick dump of my current mood:
**Artem:**
-\> Approach (2): We could teach the Store to scan itself for bindings to
-\> metadata-symbolic-based regions during scanReachableSymbols() whenever
-\> a region turns out to be reachable. This requires no work on checker side,
-\> but it sounds performance-heavy.
+> Approach (2): We could teach the Store to scan itself for bindings to
+> metadata-symbolic-based regions during scanReachableSymbols() whenever
+> a region turns out to be reachable. This requires no work on checker side,
+> but it sounds performance-heavy.
Nope, this approach is wrong. Metadata symbols may become out-of-date: when the
object changes, metadata symbols attached to it aren't changing (because symbols
@@ -183,12 +183,12 @@ invalidation for free.
**Artem:**
-\> In this case, I would be fine with some sort of `AbstractStorageMemoryRegion`
-\> that meant "here is a memory region and somewhere reachable from here exists
-\> another region of type T". Or even multiple regions with different
-\> identifiers. This wouldn't specify how the memory is reachable, but it would
-\> allow for transfer functions to get at those regions and it would allow for
-\> invalidation.
+> In this case, I would be fine with some sort of `AbstractStorageMemoryRegion`
+> that meant "here is a memory region and somewhere reachable from here exists
+> another region of type T". Or even multiple regions with different
+> identifiers. This wouldn't specify how the memory is reachable, but it would
+> allow for transfer functions to get at those regions and it would allow for
+> invalidation.
Yeah, this is what we can easily implement now as a
symbolic-region-based-on-a-metadata-symbol (though we can make a new region
@@ -202,9 +202,9 @@ abstract storage is most of the time at best a "nice to know" thing - we cannot
rely on it to do any actual work. We'd anyway need to rely on the checker to do
the job.
-\> For std::initializer_list this reachable region would the region for the
-\> backing array and the transfer functions for begin() and end() yield the
-\> beginning and end element regions for it.
+> For std::initializer_list this reachable region would the region for the
+> backing array and the transfer functions for begin() and end() yield the
+> beginning and end element regions for it.
So maybe in fact for std::initializer_list it may work fine because you cannot
change the data after the object is constructed - so this region's contents are
@@ -254,18 +254,18 @@ would be their superregion) is actually useful, the mutability of their contents
is expressed naturally, and the store automagically sees reachable symbols, live
symbols, escapes, invalidations, whatever.
-\> In my view this differs from ghost variables in that (1) this storage does
-\> actually exist (it is just a library implementation detail where that storage
-\> lives) and (2) it is perfectly valid for a pointer into that storage to be
-\> returned and for another part of the program to read or write from that
-\> storage. (Well, in this case just read since it is allowed to be read-only
-\> memory).
+> In my view this differs from ghost variables in that (1) this storage does
+> actually exist (it is just a library implementation detail where that storage
+> lives) and (2) it is perfectly valid for a pointer into that storage to be
+> returned and for another part of the program to read or write from that
+> storage. (Well, in this case just read since it is allowed to be read-only
+> memory).
-\> What I'm not OK with is modeling abstract analysis state (for example, the
-\> count of a NSMutableArray or the typestate of a file handle) as a value stored
-\> in some ginned up region in the store.This takes an easy problem that the
-\> analyzer does well at (modeling typestate) and turns it into a hard one that
-\> the analyzer is bad at (reasoning about the contents of the heap).
+> What I'm not OK with is modeling abstract analysis state (for example, the
+> count of a NSMutableArray or the typestate of a file handle) as a value stored
+> in some ginned up region in the store.This takes an easy problem that the
+> analyzer does well at (modeling typestate) and turns it into a hard one that
+> the analyzer is bad at (reasoning about the contents of the heap).
Yeah, i tend to agree on that. For simple typestates, this is probably an
overkill, so let's definitely put aside the idea of "ghost symbolic regions"
@@ -278,13 +278,13 @@ have a choice between re-doing this modeling in every such checker (which is
something analyzer is indeed good at, but at a price of making checkers heavy)
or instead relying on the Store to do exactly what it's designed to do.
-\> I think the key criterion here is: "is the region accessible from outside
-\> the library". That is, does the library expose the region as a pointer that
-\> can be read to or written from in the client program? If so, then it makes
-\> sense for this to be in the store: we are modeling reachable storage as
-\> storage. But if we're just modeling arbitrary analysis facts that need to be
-\> invalidated when a pointer escapes then we shouldn't try to gin up storage
-\> for them just to get invalidation for free.
+> I think the key criterion here is: "is the region accessible from outside
+> the library". That is, does the library expose the region as a pointer that
+> can be read to or written from in the client program? If so, then it makes
+> sense for this to be in the store: we are modeling reachable storage as
+> storage. But if we're just modeling arbitrary analysis facts that need to be
+> invalidated when a pointer escapes then we shouldn't try to gin up storage
+> for them just to get invalidation for free.
As a metaphor, i'd probably compare it to body farms - the difference between
ghost member variables and metadata symbols seems to me like the difference
@@ -319,4 +319,3 @@ about:
So, because this needs further digging into overall C++ support and rises too
many questions, i'm delaying a better approach to this problem and will fall
back to the original trivial patch.
-
diff --git a/clang/docs/analyzer/developer-docs/RegionStore.md b/clang/docs/analyzer/developer-docs/RegionStore.md
index 5c5a5eaa8ab60..b52cac197edac 100644
--- a/clang/docs/analyzer/developer-docs/RegionStore.md
+++ b/clang/docs/analyzer/developer-docs/RegionStore.md
@@ -47,7 +47,7 @@ foo[0] = 0;
After this latest assignment, nothing can be said about the value of `foo[i]`,
because `foo[0]` may have overwritten it! *Binding to a region R with a
concrete offset invalidates any symbolic offset bindings whose concrete offset
-region is a super-region \*\*or\** sub-region of R.\* All we know about `foo[i]`
+region is a super-region **or** sub-region of R.* All we know about `foo[i]`
is that it is somewhere within `foo`, so changing *anything* within `foo`
might change `foo[i]`, and changing *all* of `foo` (or its base region) will
*definitely* change `foo[i]`.
@@ -170,4 +170,3 @@ return p2.x; // The binding for FieldRegion 'p2.x' is requested.
// and see that it's the '.x' field. We ask for the value
// of 'p.x' within the snapshot, and get back 42.
```
-
diff --git a/clang/docs/analyzer/developer-docs/nullability.md b/clang/docs/analyzer/developer-docs/nullability.md
index a51b90ef7a34d..b9dcf01d29054 100644
--- a/clang/docs/analyzer/developer-docs/nullability.md
+++ b/clang/docs/analyzer/developer-docs/nullability.md
@@ -25,7 +25,7 @@ takesNonNull((_nonnull) bar); // should not warn here (backward compatibility ha
anotherTakesNonNull(bar); // would be great to warn here, but not necessary(*)
```
-Because bar corresponds to the same symbol all the time it is not easy to implement the checker that way the cast only suppress the first call but not the second. For this reason in the first implementation after a contradictory cast happens, I will treat bar as nullable unspecified, this way all of the warnings will be suppressed. Treating the symbol as nullable unspecified also has an advantage that in case the takesNonNull function body is being inlined, the will be no warning, when the symbol is dereferenced. In case I have time after the initial version I might spend additional time to try to find a more sophisticated solution, in which we would produce the second warning (\*).
+Because bar corresponds to the same symbol all the time it is not easy to implement the checker that way the cast only suppress the first call but not the second. For this reason in the first implementation after a contradictory cast happens, I will treat bar as nullable unspecified, this way all of the warnings will be suppressed. Treating the symbol as nullable unspecified also has an advantage that in case the takesNonNull function body is being inlined, the will be no warning, when the symbol is dereferenced. In case I have time after the initial version I might spend additional time to try to find a more sophisticated solution, in which we would produce the second warning (*).
**2) nonnull**
@@ -101,4 +101,3 @@ What to track?
- When there is an explicit cast from a null unspecified to either nonnull or nullable I will trust the cast.
- Unannotated pointers are treated the same way as pointers annotated with nullability unspecified qualifier, unless the region is wrapped in ASSUME_NONNULL macros.
- We might want to implement a callback for entry points to top level functions, where the pointer nullability assumptions would be made.
-
diff --git a/clang/docs/analyzer/user-docs/Annotations.md b/clang/docs/analyzer/user-docs/Annotations.md
index dd67dc28a598e..383eeb6caba1b 100644
--- a/clang/docs/analyzer/user-docs/Annotations.md
+++ b/clang/docs/analyzer/user-docs/Annotations.md
@@ -56,7 +56,7 @@ Running `scan-build` over this source produces the following output:
```{image} ../images/example_attribute_nonnull.png
```
-(custom-assertion-handlers)=
+(custom_assertion_handlers)=
### Custom Assertion Handlers
@@ -159,10 +159,10 @@ void my_assert_rtn(const char *, const char *, int, const char *) CLANG_ANALYZER
### Dynamic Memory Modeling Annotations
-If a project uses custom functions for dynamic memory management (that e.g. act as wrappers around `malloc`/`free` or `new`/`delete` in C++) and the analyzer cannot "see" the \_definitions\_ of these functions, it's possible to annotate their declarations to let the analyzer model their behavior. (Otherwise the analyzer cannot know that the opaque `my_free()` is basically equivalent to a standard `free()` call.)
+If a project uses custom functions for dynamic memory management (that e.g. act as wrappers around `malloc`/`free` or `new`/`delete` in C++) and the analyzer cannot "see" the `_definitions_` of these functions, it's possible to annotate their declarations to let the analyzer model their behavior. (Otherwise the analyzer cannot know that the opaque `my_free()` is basically equivalent to a standard `free()` call.)
:::{note}
-**This page only provides a brief list of these annotations.** For a full documentation, see the main [Attributes in Clang](../../AttributeReference.html#ownership-holds-ownership-returns-ownership-takes-clang-static-analyzer) page.
+**This page only provides a brief list of these annotations.** For a full documentation, see the main [Attributes in Clang](../../AttributeReference.md#ownership-holds-ownership-returns-ownership-takes-clang-static-analyzer) page.
:::
#### Attribute 'ownership_returns' (Clang-specific)
@@ -202,7 +202,7 @@ The annotations `ownership_takes` and `ownership_holds` both prevent memory leak
## Mac OS X API Annotations
-(cocoa-mem)=
+(cocoa_mem)=
### Cocoa & Core Foundation Memory Management Annotations
@@ -218,7 +218,7 @@ attributes described here. However, you should consider using proper naming
conventions or the [objc_method_family](https://clang.llvm.org/docs/LanguageExtensions.html#the-objc-method-family-attribute)
attribute, if applicable.
-(ns-returns-retained)=
+(ns_returns_retained)=
#### Attribute 'ns_returns_retained' (Clang-specific)
@@ -276,37 +276,38 @@ Running `scan-build` on this source file produces the following output:
```{image} ../images/example_ns_returns_retained.png
```
-(ns-returns-not-retained)=
+(ns_returns_not_retained)=
#### Attribute 'ns_returns_not_retained' (Clang-specific)
The 'ns_returns_not_retained' attribute is the complement of
-'[ns_returns_retained]'. Where a function or method may appear to obey the
+'[ns_returns_retained](#attribute-ns-returns-retained-clang-specific)'. Where a function or method may appear to obey the
Cocoa conventions and return a retained Cocoa object, this attribute can be
used to indicate that the object reference returned should not be considered as
an "owning" reference being returned to the caller. The Foundation
framework defines a macro `NS_RETURNS_NOT_RETAINED` that is functionally
equivalent to the one shown below.
-Usage is identical to [ns_returns_retained]. When using the
+Usage is identical to [ns_returns_retained](#attribute-ns-returns-retained-clang-specific). When using the
attribute, be sure to declare it within the proper macro that checks for
its availability, as it is not available in earlier versions of the analyzer:
-% code-block:objc
-%
-% #ifndef __has_feature // Optional.
-% #define __has_feature(x) 0 // Compatibility with non-clang compilers.
-% #endif
-%
-% #ifndef NS_RETURNS_NOT_RETAINED
-% #if __has_feature(attribute_ns_returns_not_retained)
-% #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
-% #else
-% #define NS_RETURNS_NOT_RETAINED
-% #endif
-% #endif
-
-(cf-returns-retained)=
+```objc
+
+#ifndef __has_feature // Optional.
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#endif
+
+#ifndef NS_RETURNS_NOT_RETAINED
+#if __has_feature(attribute_ns_returns_not_retained)
+#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
+#else
+#define NS_RETURNS_NOT_RETAINED
+#endif
+#endif
+```
+
+(cf_returns_retained)=
#### Attribute 'cf_returns_retained' (Clang-specific)
@@ -340,46 +341,47 @@ interprets the function as:
**Example**
-% code-block:objc
-%
-% #import <Cocoa/Cocoa.h>
-%
-% #ifndef __has_feature // Optional.
-% #define __has_feature(x) 0 // Compatibility with non-clang compilers.
-% #endif
-%
-% #ifndef CF_RETURNS_RETAINED
-% #if __has_feature(attribute_cf_returns_retained)
-% #define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
-% #else
-% #define CF_RETURNS_RETAINED
-% #endif
-% #endif
-%
-% @interface MyClass : NSObject {}
-% - (NSDate*) returnsCFRetained CF_RETURNS_RETAINED;
-% - (NSDate*) alsoReturnsRetained;
-% - (NSDate*) returnsNSRetained NS_RETURNS_RETAINED;
-% @end
-%
-% CF_RETURNS_RETAINED
-% CFDateRef returnsRetainedCFDate() {
-% return CFDateCreate(0, CFAbsoluteTimeGetCurrent());
-% }
-%
-% @implementation MyClass
-% - (NSDate*) returnsCFRetained {
-% return (NSDate*) returnsRetainedCFDate(); // No leak.
-% }
-%
-% - (NSDate*) alsoReturnsRetained {
-% return (NSDate*) returnsRetainedCFDate(); // Always report a leak.
-% }
-%
-% - (NSDate*) returnsNSRetained {
-% return (NSDate*) returnsRetainedCFDate(); // Report a leak when using GC.
-% }
-% @end
+```objc
+
+#import <Cocoa/Cocoa.h>
+
+#ifndef __has_feature // Optional.
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#endif
+
+#ifndef CF_RETURNS_RETAINED
+#if __has_feature(attribute_cf_returns_retained)
+#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+#else
+#define CF_RETURNS_RETAINED
+#endif
+#endif
+
+ at interface MyClass : NSObject {}
+- (NSDate*) returnsCFRetained CF_RETURNS_RETAINED;
+- (NSDate*) alsoReturnsRetained;
+- (NSDate*) returnsNSRetained NS_RETURNS_RETAINED;
+ at end
+
+CF_RETURNS_RETAINED
+CFDateRef returnsRetainedCFDate() {
+ return CFDateCreate(0, CFAbsoluteTimeGetCurrent());
+}
+
+ at implementation MyClass
+- (NSDate*) returnsCFRetained {
+ return (NSDate*) returnsRetainedCFDate(); // No leak.
+}
+
+- (NSDate*) alsoReturnsRetained {
+ return (NSDate*) returnsRetainedCFDate(); // Always report a leak.
+}
+
+- (NSDate*) returnsNSRetained {
+ return (NSDate*) returnsRetainedCFDate(); // Report a leak when using GC.
+}
+ at end
+```
Running `scan-build` on this example produces the following output:
@@ -389,33 +391,34 @@ Running `scan-build` on this example produces the following output:
#### Attribute 'cf_returns_not_retained' (Clang-specific)
The 'cf_returns_not_retained' attribute is the complement of
-'[cf_returns_retained]'. Where a function or method may appear to obey the
+'[cf_returns_retained](#attribute-cf-returns-retained-clang-specific)'. Where a function or method may appear to obey the
Core Foundation or Cocoa conventions and return a retained Core Foundation
object, this attribute can be used to indicate that the object reference
returned should not be considered as an "owning" reference being
returned to the caller. The CoreFoundation framework defines a macro
-**\`\`CF_RETURNS_NOT_RETAINED\`\`** that is functionally equivalent to the one
+**`CF_RETURNS_NOT_RETAINED`** that is functionally equivalent to the one
shown below.
-Usage is identical to [cf_returns_retained]. When using the attribute, be sure
+Usage is identical to [cf_returns_retained](#attribute-cf-returns-retained-clang-specific). When using the attribute, be sure
to declare it within the proper macro that checks for its availability, as it
is not available in earlier versions of the analyzer:
-% code-block:objc
-%
-% #ifndef __has_feature // Optional.
-% #define __has_feature(x) 0 // Compatibility with non-clang compilers.
-% #endif
-%
-% #ifndef CF_RETURNS_NOT_RETAINED
-% #if __has_feature(attribute_cf_returns_not_retained)
-% #define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
-% #else
-% #define CF_RETURNS_NOT_RETAINED
-% #endif
-% #endif
-
-(ns-consumed)=
+```objc
+
+#ifndef __has_feature // Optional.
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#endif
+
+#ifndef CF_RETURNS_NOT_RETAINED
+#if __has_feature(attribute_cf_returns_not_retained)
+#define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained))
+#else
+#define CF_RETURNS_NOT_RETAINED
+#endif
+#endif
+```
+
+(ns_consumed)=
#### Attribute 'ns_consumed' (Clang-specific)
@@ -428,46 +431,47 @@ is functionally equivalent to the `NS_CONSUMED` macro shown below.
**Example**
-% code-block:objc
-%
-% #ifndef __has_feature // Optional.
-% #define __has_feature(x) 0 // Compatibility with non-clang compilers.
-% #endif
-%
-% #ifndef NS_CONSUMED
-% #if __has_feature(attribute_ns_consumed)
-% #define NS_CONSUMED __attribute__((ns_consumed))
-% #else
-% #define NS_CONSUMED
-% #endif
-% #endif
-%
-% void consume_ns(id NS_CONSUMED x);
-%
-% void test() {
-% id x = [[NSObject alloc] init];
-% consume_ns(x); // No leak!
-% }
-%
-% @interface Foo : NSObject
-% + (void) releaseArg:(id) NS_CONSUMED x;
-% + (void) releaseSecondArg:(id)x second:(id) NS_CONSUMED y;
-% @end
-%
-% void test_method() {
-% id x = [[NSObject alloc] init];
-% [Foo releaseArg:x]; // No leak!
-% }
-%
-% void test_method2() {
-% id a = [[NSObject alloc] init];
-% id b = [[NSObject alloc] init];
-% [Foo releaseSecondArg:a second:b]; // 'a' is leaked, but 'b' is released.
-% }
+```objc
+
+#ifndef __has_feature // Optional.
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#endif
+
+#ifndef NS_CONSUMED
+#if __has_feature(attribute_ns_consumed)
+#define NS_CONSUMED __attribute__((ns_consumed))
+#else
+#define NS_CONSUMED
+#endif
+#endif
+
+void consume_ns(id NS_CONSUMED x);
+
+void test() {
+ id x = [[NSObject alloc] init];
+ consume_ns(x); // No leak!
+}
+
+ at interface Foo : NSObject
++ (void) releaseArg:(id) NS_CONSUMED x;
++ (void) releaseSecondArg:(id)x second:(id) NS_CONSUMED y;
+ at end
+
+void test_method() {
+ id x = [[NSObject alloc] init];
+ [Foo releaseArg:x]; // No leak!
+}
+
+void test_method2() {
+ id a = [[NSObject alloc] init];
+ id b = [[NSObject alloc] init];
+ [Foo releaseSecondArg:a second:b]; // 'a' is leaked, but 'b' is released.
+}
+```
#### Attribute 'cf_consumed' (Clang-specific)
-The 'cf_consumed' attribute is practically identical to [ns_consumed]. The
+The 'cf_consumed' attribute is practically identical to [ns_consumed](#attribute-ns-consumed-clang-specific). The
attribute can be placed on a specific parameter in either the declaration of a
function or an Objective-C method. It indicates to the static analyzer that the
object reference is implicitly passed to a call to `CFRelease` upon
@@ -479,44 +483,45 @@ Operationally this attribute is nearly identical to 'ns_consumed'.
**Example**
-% code-block:objc
-%
-% #ifndef __has_feature // Optional.
-% #define __has_feature(x) 0 // Compatibility with non-clang compilers.
-% #endif
-%
-% #ifndef CF_CONSUMED
-% #if __has_feature(attribute_cf_consumed)
-% #define CF_CONSUMED __attribute__((cf_consumed))
-% #else
-% #define CF_CONSUMED
-% #endif
-% #endif
-%
-% void consume_cf(id CF_CONSUMED x);
-% void consume_CFDate(CFDateRef CF_CONSUMED x);
-%
-% void test() {
-% id x = [[NSObject alloc] init];
-% consume_cf(x); // No leak!
-% }
-%
-% void test2() {
-% CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
-% consume_CFDate(date); // No leak, including under GC!
-%
-% }
-%
-% @interface Foo : NSObject
-% + (void) releaseArg:(CFDateRef) CF_CONSUMED x;
-% @end
-%
-% void test_method() {
-% CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
-% [Foo releaseArg:date]; // No leak!
-% }
-
-(ns-consumes-self)=
+```objc
+
+#ifndef __has_feature // Optional.
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#endif
+
+#ifndef CF_CONSUMED
+#if __has_feature(attribute_cf_consumed)
+#define CF_CONSUMED __attribute__((cf_consumed))
+#else
+#define CF_CONSUMED
+#endif
+#endif
+
+void consume_cf(id CF_CONSUMED x);
+void consume_CFDate(CFDateRef CF_CONSUMED x);
+
+void test() {
+ id x = [[NSObject alloc] init];
+ consume_cf(x); // No leak!
+}
+
+void test2() {
+ CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
+ consume_CFDate(date); // No leak, including under GC!
+
+}
+
+ at interface Foo : NSObject
++ (void) releaseArg:(CFDateRef) CF_CONSUMED x;
+ at end
+
+void test_method() {
+ CFDateRef date = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
+ [Foo releaseArg:date]; // No leak!
+}
+```
+
+(ns_consumes_self)=
#### Attribute 'ns_consumes_self' (Clang-specific)
@@ -530,23 +535,24 @@ follow the standard Cocoa naming conventions.
**Example**
-% code-block:objc
-% #ifndef __has_feature
-% #define __has_feature(x) 0 // Compatibility with non-clang compilers.
-% #endif
-%
-% #ifndef NS_CONSUMES_SELF
-% #if __has_feature((attribute_ns_consumes_self))
-% #define NS_CONSUMES_SELF __attribute__((ns_consumes_self))
-% #else
-% #define NS_CONSUMES_SELF
-% #endif
-% #endif
-%
-% @interface MyClass : NSObject
-% - initWith:(MyClass *)x;
-% - nonstandardInitWith:(MyClass *)x NS_CONSUMES_SELF NS_RETURNS_RETAINED;
-% @end
+```objc
+#ifndef __has_feature
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#endif
+
+#ifndef NS_CONSUMES_SELF
+#if __has_feature((attribute_ns_consumes_self))
+#define NS_CONSUMES_SELF __attribute__((ns_consumes_self))
+#else
+#define NS_CONSUMES_SELF
+#endif
+#endif
+
+ at interface MyClass : NSObject
+- initWith:(MyClass *)x;
+- nonstandardInitWith:(MyClass *)x NS_CONSUMES_SELF NS_RETURNS_RETAINED;
+ at end
+```
In this example, `-nonstandardInitWith:` has the same ownership
semantics as the init method `-initWith:`. The static analyzer will
@@ -600,7 +606,7 @@ These summaries can be overriden with the following
#### Attribute 'os_returns_retained'
The `os_returns_retained` attribute (accessed through the macro
-`LIBKERN_RETURNS_RETAINED`) plays a role identical to [ns_returns_retained]
+`LIBKERN_RETURNS_RETAINED`) plays a role identical to [ns_returns_retained](#attribute-ns-returns-retained-clang-specific)
for functions returning `OSObject` subclasses. The attribute indicates that
it is a callers responsibility to release the returned object.
@@ -608,45 +614,48 @@ it is a callers responsibility to release the returned object.
The `os_returns_not_retained` attribute (accessed through the macro
`LIBKERN_RETURNS_NOT_RETAINED`) plays a role identical to
-[ns_returns_not_retained] for functions returning `OSObject` subclasses. The
+[ns_returns_not_retained](#attribute-ns-returns-not-retained-clang-specific) for functions returning `OSObject` subclasses. The
attribute indicates that the caller should not change the retain count of the
returned object.
**Example**
-% code-block:objc
-%
-% class MyClass {
-% OSObject *f;
-% LIBKERN_RETURNS_NOT_RETAINED OSObject *myFieldGetter();
-% }
-%
-% // Note that the annotation only has to be applied to the function declaration.
-% OSObject * MyClass::myFieldGetter() {
-% return f;
-% }
+```objc
+
+class MyClass {
+ OSObject *f;
+ LIBKERN_RETURNS_NOT_RETAINED OSObject *myFieldGetter();
+}
+
+// Note that the annotation only has to be applied to the function declaration.
+OSObject * MyClass::myFieldGetter() {
+ return f;
+}
+```
#### Attribute 'os_consumed'
-Similarly to [ns_consumed] attribute, `os_consumed` (accessed through
+Similarly to [ns_consumed](#attribute-ns-consumed-clang-specific) attribute, `os_consumed` (accessed through
`LIBKERN_CONSUMED`) attribute, applied to a parameter, indicates that the
call to the function *consumes* the parameter: the callee should either release
it or store it and release it in the destructor, while the caller should assume
one is subtracted from the reference count after the call.
-% code-block:objc
-% IOReturn addToList(LIBKERN_CONSUMED IOPMinformee *newInformee);
+```objc
+IOReturn addToList(LIBKERN_CONSUMED IOPMinformee *newInformee);
+```
#### Attribute 'os_consumes_this'
-Similarly to [ns_consumes_self], the `os_consumes_self` attribute indicates
+Similarly to [ns_consumes_self](#attribute-ns-consumes-self-clang-specific), the `os_consumes_self` attribute indicates
that the method call *consumes* the implicit `this` argument: the caller
should assume one was subtracted from the reference count of the object after
the call, and the callee has on obligation to either release the argument, or
store it and eventually release it in the destructor.
-% code-block:objc
-% void addThisToList(OSArray *givenList) LIBKERN_CONSUMES_THIS;
+```objc
+void addThisToList(OSArray *givenList) LIBKERN_CONSUMES_THIS;
+```
#### Out Parameters
@@ -658,16 +667,18 @@ parameters by default, but with annotations we distinguish four separate cases:
**1. Non-retained out parameters**, identified using
`LIBKERN_RETURNS_NOT_RETAINED` applied to parameters, e.g.:
-% code-block:objc
-% void getterViaOutParam(LIBKERN_RETURNS_NOT_RETAINED OSObject **obj)
+```objc
+void getterViaOutParam(LIBKERN_RETURNS_NOT_RETAINED OSObject **obj)
+```
Such functions write a non-retained object into an out parameter, and the
caller has no further obligations.
**2. Retained out parameters**, identified using `LIBKERN_RETURNS_RETAINED`:
-% code-block:objc
-% void getterViaOutParam(LIBKERN_RETURNS_NOT_RETAINED OSObject **obj)
+```objc
+void getterViaOutParam(LIBKERN_RETURNS_NOT_RETAINED OSObject **obj)
+```
In such cases a retained object is written into an out parameter, which the caller has then to release in order to avoid a leak.
@@ -675,8 +686,9 @@ These two cases are simple - but in practice a functions returning an
out-parameter usually also return a return code, and then an out parameter may
or may not be written, which conditionally depends on the exit code, e.g.:
-% code-block:objc
-% bool maybeCreateObject(LIBKERN_RETURNS_RETAINED OSObject **obj);
+```objc
+bool maybeCreateObject(LIBKERN_RETURNS_RETAINED OSObject **obj);
+```
For such functions, the usual semantics is that an object is written into on "success", and not written into on "failure".
@@ -692,8 +704,9 @@ success:
`LIBKERN_RETURNS_RETAINED_ON_ZERO` states that a retained object is written
into if and only if the function returns a zero value:
-% code-block:objc
-% bool OSUnserializeXML(void *data, LIBKERN_RETURNS_RETAINED_ON_ZERO OSString **errString);
+```objc
+bool OSUnserializeXML(void *data, LIBKERN_RETURNS_RETAINED_ON_ZERO OSString **errString);
+```
Then the caller has to release an object if the function has returned zero.
@@ -705,4 +718,3 @@ value.
Note that for non-retained out parameters conditionals do not matter, as the
caller has no obligations regardless of whether an object is written into or
not.
-
diff --git a/clang/docs/analyzer/user-docs/CommandLineUsage.md b/clang/docs/analyzer/user-docs/CommandLineUsage.md
index 4db8498ab062e..49b556fce336c 100644
--- a/clang/docs/analyzer/user-docs/CommandLineUsage.md
+++ b/clang/docs/analyzer/user-docs/CommandLineUsage.md
@@ -10,7 +10,7 @@ Therefore CodeChecker is recommended in case you need any of the above features
For a direct analysis of a source file, the `clang` driver can write a SARIF report:
-```
+```console
$ clang --analyze --analyzer-output sarif -o report.sarif source.c
```
@@ -23,7 +23,7 @@ This direct form analyzes a translation unit.
For project-wide analysis, use a tool such as scan-build or CodeChecker to drive the individual compiler invocations.
`scan-build` can emit a SARIF report for each analyzed translation unit with its `-sarif` option:
-```
+```console
$ scan-build -sarif -o reports make
```
@@ -35,12 +35,12 @@ It is possible, however, to invoke the static analyzer from the command line in
The following tools are used commonly to run the analyzer from the command line.
Both tools are wrapper scripts to drive the analysis and the underlying invocations of the Clang compiler:
-1. [scan-build] is an old and simple command line tool that emits static analyzer warnings as HTML files while compiling your project. You can view the analysis results in your web browser; the utility script `scan-view` can provide a trivial HTTP server that servers these result files.
+1. [scan-build](#scan-build) is an old and simple command line tool that emits static analyzer warnings as HTML files while compiling your project. You can view the analysis results in your web browser; the utility script `scan-view` can provide a trivial HTTP server that servers these result files.
: - Is available as a part of the LLVM project (together with `scan-view`).
- Useful for individual developers who simply want to view static analysis results at their desk, or in a very simple collaborative environment.
- Works on all major platforms (Windows, Linux, macOS) and is available as a package in many Linux distributions.
- Does not include support for cross-translation-unit analysis.
-2. [CodeChecker] is a driver and web server that runs the static analyzer on your projects on demand and maintains a database of issues.
+2. [CodeChecker](#codechecker) is a driver and web server that runs the static analyzer on your projects on demand and maintains a database of issues.
: - Open source, but out-of-tree, i.e. not part of the LLVM project.
- Perfect for managing large amounts of thee static analyzer warnings in a collaborative environment.
- Generally much more feature-rich than scan-build.
@@ -76,7 +76,7 @@ This "poor man's interposition" works amazingly well in many cases and falls dow
Basic usage of `scan-build` is designed to be simple: just place the word "scan-build" in front of your build command:
-```
+```console
$ scan-build make
$ scan-build xcodebuild
```
@@ -85,13 +85,13 @@ In the first case `scan-build` analyzes the code of a project built with `make`
Here is the general format for invoking `scan-build`:
-```
+```console
$ scan-build [scan-build options] <command> [command options]
```
-Operationally, `scan-build` literally runs \<command> with all of the subsequent options passed to it. For example, one can pass `-j4` to `make` get a parallel build over 4 cores:
+Operationally, `scan-build` literally runs `<command>` with all of the subsequent options passed to it. For example, one can pass `-j4` to `make` get a parallel build over 4 cores:
-```
+```console
$ scan-build make -j4
```
@@ -99,7 +99,7 @@ In almost all cases, `scan-build` makes no effort to interpret the options after
It is also possible to use `scan-build` to analyze specific files:
-```
+```console
$ scan-build gcc -c t1.c t2.c
```
@@ -117,7 +117,7 @@ If you have unexpected compilation/make problems when running scan-build with Mi
\- Use MinGW `mingw32-make` instead of MSYS `make` and exclude the path to MSYS from PATH to prevent `mingw32-make` from using MSYS utils. MSYS utils are dependent on the MSYS runtime and they are not intended for being run from the Windows cmd. Specifically, makefile commands with backslashed quotes may be heavily corrupted when passed for execution.
\- Run `make` from the sh shell:
- ```
+ ```console
$ scan-build [scan-build options] sh -c "make [make options]"
```
@@ -127,7 +127,7 @@ If you have unexpected compilation/make problems when running scan-build with Mi
As mentioned above, extra options can be passed to `scan-build`. These options prefix the build command. For example:
-```
+```console
$ scan-build -k -V make
$ scan-build -k -V xcodebuild
```
@@ -169,7 +169,7 @@ If an analyzed project uses an autoconf generated `configure` script, you will p
**Example**:
-```
+```console
$ scan-build ./configure
$ scan-build --keep-cc make
```
@@ -186,7 +186,7 @@ Conceptually Xcode projects for iPhone applications are nearly the same as their
The absolute easiest way to analyze iPhone projects is to use the [Analyze feature in Xcode](https://developer.apple.com/library/ios/recipes/xcode_help-source_editor/chapters/Analyze.html#//apple_ref/doc/uid/TP40009975-CH4-SW1) (which is based on the static analyzer). There a user can analyze their project right from a menu without most of the setup described later.
-[Instructions are available](../xcode.html) on this website on how to use open source builds of the analyzer as a replacement for the one bundled with Xcode.
+[Instructions are available](UsingWithXCode.md) on this website on how to use open source builds of the analyzer as a replacement for the one bundled with Xcode.
### Using scan-build directly
@@ -198,13 +198,13 @@ If you wish to use **scan-build** with your iPhone project, keep the following t
Note that you can most of this without actually modifying your project. For example, if your application targets iPhoneOS 2.2, you could run **scan-build** in the following manner from the command line:
-```
+```console
$ scan-build xcodebuild -configuration Debug -sdk iphonesimulator2.2
```
Alternatively, if your application targets iPhoneOS 3.0:
-```
+```console
$ scan-build xcodebuild -configuration Debug -sdk iphonesimulator3.0
```
@@ -229,34 +229,34 @@ Install CodeChecker as described here: [CodeChecker Install Guide](https://githu
Create a compilation database. If you use cmake then pass the `-DCMAKE_EXPORT_COMPILE_COMMANDS=1` parameter to cmake. Cmake will create a `compile_commands.json` file.
If you have a Makefile based or similar build system then you can log the build commands with the help of CodeChecker:
-```
+```bash
make clean
CodeChecker log -b "make" -o compile_commands.json
```
Analyze your project:
-```
+```bash
CodeChecker analyze compile_commands.json -o ./reports
```
View the analysis results.
Print the detailed results in the command line:
-```
+```bash
CodeChecker parse --print-steps ./reports
```
Or view the detailed results in a browser:
-```
+```bash
CodeChecker parse ./reports -e html -o ./reports_html
firefox ./reports_html/index.html
```
Optional: store the analysis results in a DB:
-```
+```bash
mkdir ./ws
CodeChecker server -w ./ws -v 8555 &
CodeChecker store ./reports --name my-project --url http://localhost:8555/Default
@@ -264,11 +264,10 @@ CodeChecker store ./reports --name my-project --url http://localhost:8555/Defaul
Optional: manage (categorize, suppress) the results in your web browser:
-```
+```bash
firefox http://localhost:8555/Default
```
### Detailed Usage
For extended documentation please refer to the [official site of CodeChecker](https://github.com/Ericsson/codechecker/blob/master/docs/usage.md)!
-
diff --git a/clang/docs/analyzer/user-docs/CrossTranslationUnit.md b/clang/docs/analyzer/user-docs/CrossTranslationUnit.md
index 9396d7e4fca8d..a8ac851547c0f 100644
--- a/clang/docs/analyzer/user-docs/CrossTranslationUnit.md
+++ b/clang/docs/analyzer/user-docs/CrossTranslationUnit.md
@@ -50,7 +50,7 @@ int foo() {
And a compilation database:
-```bash
+```json
[
{
"directory": "/path/to/your/project",
@@ -69,7 +69,7 @@ We'd like to analyze `main.cpp` and discover the division by zero bug.
In order to be able to inline the definition of `foo` from `foo.cpp` first we have to generate the `AST` (or `PCH`) file
of `foo.cpp`:
-```bash
+```console
$ pwd $ /path/to/your/project
$ clang++ -emit-ast -o foo.cpp.ast foo.cpp
$ # Check that the .ast file is generated:
@@ -81,7 +81,7 @@ $
The next step is to create a CTU index file which holds the `USR` name and location of external definitions in the
source files in format `<USR-Length>:<USR> <File-Path>`:
-```bash
+```console
$ clang-extdef-mapping -p . foo.cpp.ast
9:c:@F at foo# /path/to/your/project/foo.cpp.ast
$ clang-extdef-mapping -p . foo.cpp.ast > externalDefMap.txt
@@ -90,7 +90,7 @@ $ clang-extdef-mapping -p . foo.cpp.ast > externalDefMap.txt
Now everything is available for the CTU analysis.
We have to feed Clang with CTU specific extra arguments:
-```bash
+```console
$ pwd
/path/to/your/project
$ clang++ --analyze \
@@ -116,7 +116,7 @@ This manual procedure is error-prone and not scalable, therefore to analyze real
The [CodeChecker](https://github.com/Ericsson/codechecker) project fully supports automated CTU analysis with Clang.
Once we have set up the `PATH` environment variable and we activated the python `venv` then it is all it takes:
-```bash
+```console
$ CodeChecker analyze --ctu --ctu-ast-mode load-from-pch compile_commands.json -o reports
$ ls -F
compile_commands.json foo.cpp foo.cpp.ast main.cpp reports/
@@ -136,7 +136,7 @@ $
The `plist` files contain the results of the analysis, which may be viewed with the regular analysis tools.
E.g. one may use `CodeChecker parse` to view the results in command line:
-```bash
+```console
$ CodeChecker parse reports
[HIGH] /home/egbomrt/ctu_mini_raw_project/main.cpp:5:12: Division by zero [core.DivideZero]
return 3 / foo();
@@ -163,7 +163,7 @@ Total number of reports: 1
Or we can use `CodeChecker parse -e html` to export the results into HTML format:
-```bash
+```console
$ CodeChecker parse -e html -o html_out reports
$ firefox html_out/index.html
```
@@ -175,7 +175,7 @@ We actively develop CTU with CodeChecker as the driver for this feature, `scan-b
Example usage of scan-build-py:
-```bash
+```console
$ /your/path/to/llvm-project/clang/tools/scan-build-py/bin/analyze-build --ctu
analyze-build: Run 'scan-view /tmp/scan-build-2019-07-17-17-53-33-810365-7fqgWk' to examine bug reports.
$ /your/path/to/llvm-project/clang/tools/scan-view/bin/scan-view /tmp/scan-build-2019-07-17-17-53-33-810365-7fqgWk
@@ -227,7 +227,7 @@ int foo() {
The compilation database:
-```bash
+```json
[
{
"directory": "/path/to/your/project",
@@ -244,7 +244,7 @@ The compilation database:
The `invocation list`:
-```bash
+```yaml
"/path/to/your/project/foo.cpp":
- "clang++"
- "-c"
@@ -264,7 +264,7 @@ We'd like to analyze `main.cpp` and discover the division by zero bug.
As we are using On-demand mode, we only need to create a CTU index file which holds the `USR` name and location of
external definitions in the source files in format `<USR-Length>:<USR> <File-Path>`:
-```bash
+```console
$ clang-extdef-mapping -p . foo.cpp
9:c:@F at foo# /path/to/your/project/foo.cpp
$ clang-extdef-mapping -p . foo.cpp > externalDefMap.txt
@@ -273,7 +273,7 @@ $ clang-extdef-mapping -p . foo.cpp > externalDefMap.txt
Now everything is available for the CTU analysis.
We have to feed Clang with CTU specific extra arguments:
-```bash
+```console
$ pwd
/path/to/your/project
$ clang++ --analyze \
@@ -300,7 +300,7 @@ This manual procedure is error-prone and not scalable, therefore to analyze real
The [CodeChecker](https://github.com/Ericsson/codechecker) project fully supports automated CTU analysis with Clang.
Once we have set up the `PATH` environment variable and we activated the python `venv` then it is all it takes:
-```bash
+```console
$ CodeChecker analyze --ctu compile_commands.json -o reports
$ ls -F
compile_commands.json foo.cpp main.cpp reports/
@@ -320,7 +320,7 @@ $
The `plist` files contain the results of the analysis, which may be viewed with the regular analysis tools.
E.g. one may use `CodeChecker parse` to view the results in command line:
-```bash
+```console
$ CodeChecker parse reports
[HIGH] /home/egbomrt/ctu_mini_raw_project/main.cpp:5:12: Division by zero [core.DivideZero]
return 3 / foo();
@@ -347,7 +347,7 @@ Total number of reports: 1
Or we can use `CodeChecker parse -e html` to export the results into HTML format:
-```bash
+```console
$ CodeChecker parse -e html -o html_out reports
$ firefox html_out/index.html
```
@@ -358,4 +358,3 @@ We actively develop CTU with CodeChecker as the driver for feature, `scan-build-
`scan-build-py` has various errors and issues, expect it to work only with the very basic projects only.
Currently On-demand analysis is not supported with `scan-build-py`.
-
diff --git a/clang/docs/analyzer/user-docs/FAQ.md b/clang/docs/analyzer/user-docs/FAQ.md
index 7003fc9c145da..8412d8a834442 100644
--- a/clang/docs/analyzer/user-docs/FAQ.md
+++ b/clang/docs/analyzer/user-docs/FAQ.md
@@ -11,7 +11,7 @@ Q: How do I tell the analyzer that I do not want the bug being reported here sin
```{image} ../images/example_custom_assert.png
```
-You can tell the analyzer that this path is unreachable by teaching it about your [custom assertion handlers](Annotations.html#custom-assertion-handlers). For example, you can modify the code segment as following:
+You can tell the analyzer that this path is unreachable by teaching it about your [custom assertion handlers](Annotations.md#custom-assertion-handlers). For example, you can modify the code segment as following:
```c
void customAssert() __attribute__((analyzer_noreturn));
@@ -104,7 +104,7 @@ If your class only uses an instance variable for part of its lifetime, it may ma
## Deciding Nullability
-Q: How do I decide whether a method's return type should be \_Nullable or \_Nonnull?
+Q: How do I decide whether a method's return type should be `_Nullable` or `_Nonnull`?
Depending on the implementation of the method, this puts you in one of five situations:
@@ -120,7 +120,7 @@ In (2) the method should be marked `_Nullable`.
In (3) you should probably annotate the method `_Nonnull`. Why? Because no callers will actually check for nil, given that they can't do anything about the situation and don't know what went wrong. At this point things have gone so poorly that there's basically no way to recover.
-The least happy case is (4) because the resulting program will almost certainly either crash or just silently do the wrong thing. If this is a new method or you control the callers, you can use `NSParameterAssert()` (or the equivalent) to check the precondition and remove the nil return. But if you don't control the callers and they rely on this behavior, you should return mark the method `_Nonnull` and return nil cast to \_Nonnull anyway.
+The least happy case is (4) because the resulting program will almost certainly either crash or just silently do the wrong thing. If this is a new method or you control the callers, you can use `NSParameterAssert()` (or the equivalent) to check the precondition and remove the nil return. But if you don't control the callers and they rely on this behavior, you should return mark the method `_Nonnull` and return nil cast to `_Nonnull` anyway.
If you're in (5), document it, then figure out if you're now in (2), (3), or (4).
@@ -161,7 +161,7 @@ By adding `assert(length > 0)` in the beginning of the function, you tell the an
Q: How can I suppress a specific analyzer warning?
-When you encounter an analyzer bug/false positive, check if it's one of the issues discussed above or if the analyzer [annotations](Annotations.html#custom-assertion-handlers) can resolve the issue by helping the static analyzer understand the code better. Second, please [report it](FilingBugs.html) to help us improve user experience.
+When you encounter an analyzer bug/false positive, check if it's one of the issues discussed above or if the analyzer [annotations](Annotations.md#custom-assertion-handlers) can resolve the issue by helping the static analyzer understand the code better. Second, please [report it](FilingBugs.md) to help us improve user experience.
Sometimes there's really no "good" way to eliminate the issue. In such cases you can "silence" it directly by annotating the problematic line of code with the help of Clang attribute 'suppress':
@@ -191,7 +191,7 @@ int bar(bool coin_flip) {
}
```
-(exclude-code)=
+(exclude_code)=
## Excluding Code from Analysis
@@ -206,4 +206,3 @@ When the static analyzer is using clang to parse source files, it implicitly def
```
This usage is discouraged because it makes the code dead to the analyzer from now on. Instead, we prefer that users file bugs against the analyzer when it flags false positives.
-
diff --git a/clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.md b/clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.md
index b631ef2712c13..552ba87f996b4 100644
--- a/clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.md
+++ b/clang/docs/analyzer/user-docs/TaintAnalysisConfiguration.md
@@ -127,7 +127,7 @@ An entry under `Filters` is a [YAML](http://llvm.org/docs/YamlIO.html#introducti
The following keys are optional:
: - `Scope` is a string that specifies the prefix of the function's name in its fully qualified name. This option restricts the set of matching function calls. It can encode not only namespaces but struct/class names as well to match member functions.
- (clangsa-taint-propagation-details)=
+(clangsa-taint-propagation-details)=
### Propagation syntax and semantics
@@ -163,4 +163,3 @@ An entry under `Sinks` is a [YAML](http://llvm.org/docs/YamlIO.html#introduction
The following keys are optional:
: - `Scope` is a string that specifies the prefix of the function's name in its fully qualified name. This option restricts the set of matching function calls.
-
diff --git a/clang/docs/analyzer/user-docs/UsingWithXCode.md b/clang/docs/analyzer/user-docs/UsingWithXCode.md
index 781dae215159d..77461e922212f 100644
--- a/clang/docs/analyzer/user-docs/UsingWithXCode.md
+++ b/clang/docs/analyzer/user-docs/UsingWithXCode.md
@@ -41,7 +41,7 @@ On the other hand, new checks can be experimental, with results of variable qual
Starting with analyzer build checker-234, analyzer builds contain a command line utility called `set-xcode-analyzer` that allows users to change what copy of `clang` that Xcode uses for analysis:
-```
+```console
$ set-xcode-analyzer -h
Usage: set-xcode-analyzer [options]
@@ -61,13 +61,13 @@ Operationally, **set-xcode-analyzer** edits Xcode's configuration files to point
## Things to keep in mind
- You should quit Xcode prior to running `set-xcode-analyzer`.
-- You will need to run `set-xcode-analyzer` under **\`\`sudo\`\`** in order to have write privileges to modify the Xcode configuration files.
+- You will need to run `set-xcode-analyzer` under **`sudo`** in order to have write privileges to modify the Xcode configuration files.
## Examples
**Example 1**: Telling Xcode to use checker-235:
-```
+```console
$ pwd
/tmp
$ tar xjf checker-235.tar.bz2
@@ -78,13 +78,12 @@ Note that you typically won't install an analyzer build in `/tmp`, but the point
**Example 2**: Telling Xcode to use a very specific version of `clang`:
-```
+```console
$ sudo set-xcode-analyzer --use-checker-build=~/mycrazyclangbuild/bin/clang
```
**Example 3**: Resetting Xcode to its default behavior:
-```
+```console
$ sudo set-xcode-analyzer --use-xcode-clang
```
-
More information about the llvm-branch-commits
mailing list