diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 64d87a5339..47da64c8ab 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -58,3 +58,204 @@ When reviewing tests, it is critical to: - Check that the locations do not refer to files in the standard library, as these have issues in GitHub's Code Scanning UI and complicate our compiler compatibility tests. - Consider the "test coverage" of the query, are each of its logical statements effectively exercised individually, collectively? The test should neither be overly bloated nor under specified. - Consider the edge cases of the language itself, will the analysis work in non-trivial cases, are all relevant language concepts tested here? This doesn't need to be exhaustive, but it should be thoughfully thorough. + +## Validating Query Style + +The following list describes the required style guides for a query that **must** be validated during the code-review process. + +A query **must** include: + +- A use of the `isExcluded` predicate on the element reported as the primary location. This predicate ensures that we have a central mechanism for excluding results. This predicate may also be used on other elements relevant to the alert, but only if a suppression on that element should also cause alerts on the current element to be suppressed. +- A well formatted alert message: + - The message should be a complete standalone sentence, with punctuation and a period. + - The message should refer to this particular instance of the problem, rather than repeating the generic rule. e.g. "Call to banned function x." instead of "Do not use function x." + - Code elements should be placed in 'single quotes', unless they are formatted as links. + - Avoid value judgments such as "dubious" and "suspicious", and focus on factual statements about the problem. + - If possible, avoid constant alert messages. Either add placeholders and links (using $@), or concatenate element names to the alert message. Non-constant messages make it easier to find particular results, and links to other program elements can help provide additional context to help a developer understand the results. Examples: + - Instead of `Call to banned function.` prefer `Call to banned function foobar.`. + - Instead of `Return value from call is unused.` prefer `Return value from call to function [x] is unused.`, where `[x]` is a link to the function itself. + - Do not try to explain the solution in the message; instead that should be provided in the help for the query. + +All lines in CodeQL source files and test files should be kept to a maximum of 100 characters. + +All public predicates, classes, modules and files should be documented with QLDoc. All QLDoc should follow the following QLDoc style guide: + +### General QLDoc requirements + +1. Documentation must adhere to the [QLDoc specification](https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#qldoc). +1. Documentation comments should be appropriate for users of the code. +1. Documentation for maintainers of the code must use normal comments. +1. Use `/** ... */` for documentation, even for single line comments. + - For single-line documentation, the `/**` and `*/` are written on the same line as the comment. + - For multi-line documentation, the `/**` and `*/` are written on separate lines. There is a `*` preceding each comment line, aligned on the first `*`. +1. Use code formatting (backticks) within comments for code from the source language, and also for QL code (for example, names of classes, predicates, and variables). +1. Give explanatory examples of code in the target language, enclosed in ```` ``` ```` or `` ` ``. + + +### Language requirements + +1. Use American English. +1. Use full sentences, with capital letters and periods, except for the initial sentence of the comment, which may be fragmentary as described below. +1. Use simple sentence structures and avoid complex or academic language. +1. Avoid colloquialisms and contractions. +1. Use words that are in common usage. + + +### Requirements for specific items + +1. Public declarations must be documented. +1. Non-public declarations should be documented. +1. Declarations in query files should be documented. +1. Library files (`.qll` files) should have a documentation comment at the top of the file. +1. Query files, except for tests, must have a QLDoc query documentation comment at the top of the file. + +### QLDoc for predicates + +1. Refer to all predicate parameters in the predicate documentation. +1. Reference names, such as types and parameters, using backticks `` ` ``. +1. Give examples of code in the target language, enclosed in ```` ``` ```` or `` ` ``. +1. Predicates that override a single predicate don't need QLDoc, as they will inherit it. + +#### Predicates without result + +1. Use a third-person verb phrase of the form ``Holds if `arg` has .`` +1. Avoid: + - `/** Whether ... */` + - `/** Relates ... */` + - Question forms: + - ``/** Is `x` a foo? */`` + - ``/** Does `x` have a bar? */`` + +##### Example + +```ql +/** + * Holds if the qualifier of this call has type `qualifierType`. + * `isExactType` indicates whether the type is exact, that is, whether + * the qualifier is guaranteed not to be a subtype of `qualifierType`. + */ +``` + +#### Predicates with result + +1. Use a third-person verb phrase of the form `Gets (a|the) .` +1. Use "if any" if the item is usually unique but might be missing. For example + `Gets the body of this method, if any.` +1. If the predicate has more complex behaviour, for example multiple arguments are conceptually "outputs", it can be described like a predicate without a result. For example + ``Holds if `result` is a child of this expression.`` +1. Avoid: + - `Get a ...` + - `The ...` + - `Results in ...` + - Any use of `return` + +##### Example +```ql +/** + * Gets the expression denoting the super class of this class, + * or nothing if this is an interface or a class without an `extends` clause. + */ +``` + +#### Deprecated predicates + +The documentation for deprecated predicates should be updated to emphasize the deprecation and specify what predicate to use as an alternative. +Insert a sentence of the form `DEPRECATED: Use instead.` at the start of the QLDoc comment. + +##### Example + +```ql +/** DEPRECATED: Use `getAnExpr()` instead. */ +deprecated Expr getInitializer() +``` + +#### Internal predicates + +Some predicates are internal-only declarations that cannot be made private. The documentation for internal predicates should begin with `INTERNAL: Do not use.` + +##### Example + +```ql +/** + * INTERNAL: Do not use. + */ +``` + +#### Special predicates + +Certain special predicates should be documented consistently. + +- Always document `toString` as + + ```ql + /** Gets a textual representation of this element. */ + string toString() { ... } + ``` + +- Always document `hasLocationInfo` as + + ```ql + /** + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). + */ + + predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) { ... } + ``` + +### QLDoc for classes + +1. Document classes using a noun phrase of the form `A that .` +1. Use "that", not "which". +1. Refer to member elements in the singular. +1. Where a class denotes a generic concept with subclasses, list those subclasses. + +##### Example + +```ql +/** + * A delegate declaration, for example + * ``` + * delegate void Logger(string text); + * ``` + */ +class Delegate extends ... +``` + +```ql +/** + * An element that can be called. + * + * Either a method (`Method`), a constructor (`Constructor`), a destructor + * (`Destructor`), an operator (`Operator`), an accessor (`Accessor`), + * an anonymous function (`AnonymousFunctionExpr`), or a local function + * (`LocalFunction`). + */ +class Callable extends ... +``` + +### QLDoc for modules + +Modules should be documented using a third-person verb phrase of the form `Provides .` + +##### Example + +```ql +/** Provides logic for determining constant expressions. */ +``` +```ql +/** Provides classes representing the control flow graph within functions. */ +``` + +### Special variables + +When referring to `this`, you may either refer to it as `` `this` `` or `this `. For example: +- ``Holds if `this` is static.`` +- `Holds if this method is static.` + +When referring to `result`, you may either refer to it as `` `result` `` or as `the result`. For example: +- ``Holds if `result` is a child of this expression.`` +- `Holds if the result is a child of this expression.` diff --git a/.github/workflows/code-scanning-pack-gen.yml b/.github/workflows/code-scanning-pack-gen.yml index d5890e4542..295ef36f4c 100644 --- a/.github/workflows/code-scanning-pack-gen.yml +++ b/.github/workflows/code-scanning-pack-gen.yml @@ -28,7 +28,7 @@ jobs: matrix: ${{ steps.export-code-scanning-pack-matrix.outputs.matrix }} steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Export Code Scanning pack matrix id: export-code-scanning-pack-matrix run: | @@ -44,7 +44,7 @@ jobs: fail-fast: false matrix: ${{ fromJSON(needs.prepare-code-scanning-pack-matrix.outputs.matrix) }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Cache CodeQL id: cache-codeql @@ -84,7 +84,7 @@ jobs: id: checkout-external-help-files # PRs from forks and dependabot do not have access to an appropriate token for cloning the help files repos if: ${{ !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' }} - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ssh-key: ${{ secrets.CODEQL_CODING_STANDARDS_HELP_KEY }} repository: "github/codeql-coding-standards-help" diff --git a/.github/workflows/codeql_unit_tests.yml b/.github/workflows/codeql_unit_tests.yml index ece7f378bc..7ec7e53a79 100644 --- a/.github/workflows/codeql_unit_tests.yml +++ b/.github/workflows/codeql_unit_tests.yml @@ -15,7 +15,6 @@ on: - main - next - "rc/**" - - michaelrfairhurst/package-undefined-behavior jobs: @@ -26,7 +25,7 @@ jobs: matrix: ${{ steps.export-unit-test-matrix.outputs.matrix }} steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Export unit test matrix id: export-unit-test-matrix @@ -48,7 +47,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install Python uses: actions/setup-python@v6 diff --git a/.github/workflows/dispatch-matrix-test-on-comment.yml b/.github/workflows/dispatch-matrix-test-on-comment.yml index 513536df99..222a1b79e2 100644 --- a/.github/workflows/dispatch-matrix-test-on-comment.yml +++ b/.github/workflows/dispatch-matrix-test-on-comment.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check permission id: check-write-permission @@ -23,7 +23,7 @@ jobs: - name: Generate token id: generate-token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@v3 with: app-id: ${{ vars.AUTOMATION_APP_ID }} private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} diff --git a/.github/workflows/dispatch-release-performance-check.yml b/.github/workflows/dispatch-release-performance-check.yml index a596fac9b7..71f372d961 100644 --- a/.github/workflows/dispatch-release-performance-check.yml +++ b/.github/workflows/dispatch-release-performance-check.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check permission id: check-write-permission @@ -23,7 +23,7 @@ jobs: - name: Generate token id: generate-token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@v3 with: app-id: ${{ vars.AUTOMATION_APP_ID }} private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} diff --git a/.github/workflows/extra-rule-validation.yml b/.github/workflows/extra-rule-validation.yml index bb6faf2f4e..9f74ae6574 100644 --- a/.github/workflows/extra-rule-validation.yml +++ b/.github/workflows/extra-rule-validation.yml @@ -15,7 +15,6 @@ on: - main - "rc/**" - next - - michaelrfairhurst/package-undefined-behavior jobs: @@ -24,7 +23,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check Rules shell: pwsh @@ -36,7 +35,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Ensure CPP Shared Rules Have Valid Structure shell: pwsh diff --git a/.github/workflows/finalize-release.yml b/.github/workflows/finalize-release.yml index 392f967542..ede0c1e7c5 100644 --- a/.github/workflows/finalize-release.yml +++ b/.github/workflows/finalize-release.yml @@ -44,14 +44,14 @@ jobs: fi - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ env.REF }} fetch-depth: 0 path: release - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ env.TOOL_REF }} path: tooling @@ -108,7 +108,7 @@ jobs: - name: Generate token if: env.HOTFIX_RELEASE == 'false' id: generate-token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@v3 with: app-id: ${{ vars.AUTOMATION_APP_ID }} private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} diff --git a/.github/workflows/generate-html-docs.yml b/.github/workflows/generate-html-docs.yml index b0bea855c5..c593d94085 100644 --- a/.github/workflows/generate-html-docs.yml +++ b/.github/workflows/generate-html-docs.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install Python uses: actions/setup-python@v6 diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index 87551e47ad..8a3a0d9036 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -34,7 +34,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ inputs.ref }} @@ -143,7 +143,7 @@ jobs: - name: Generate token id: generate-token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@v3 with: app-id: ${{ vars.AUTOMATION_APP_ID }} private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} diff --git a/.github/workflows/standard_library_upgrade_tests.yml b/.github/workflows/standard_library_upgrade_tests.yml index de9478bf54..22c3dd9e05 100644 --- a/.github/workflows/standard_library_upgrade_tests.yml +++ b/.github/workflows/standard_library_upgrade_tests.yml @@ -21,7 +21,7 @@ jobs: matrix: ${{ steps.export-unit-test-matrix.outputs.matrix }} steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Export unit test matrix id: export-unit-test-matrix @@ -43,7 +43,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup Python 3 uses: actions/setup-python@v6 diff --git a/.github/workflows/tooling-unit-tests.yml b/.github/workflows/tooling-unit-tests.yml index c49ba8eb15..aec9f5dd78 100644 --- a/.github/workflows/tooling-unit-tests.yml +++ b/.github/workflows/tooling-unit-tests.yml @@ -15,7 +15,6 @@ on: - main - "rc/**" - next - - michaelrfairhurst/package-undefined-behavior jobs: prepare-supported-codeql-env-matrix: @@ -25,7 +24,7 @@ jobs: matrix: ${{ steps.export-supported-codeql-env-matrix.outputs.matrix }} steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Export supported CodeQL environment matrix id: export-supported-codeql-env-matrix @@ -43,7 +42,7 @@ jobs: matrix: ${{ fromJSON(needs.prepare-supported-codeql-env-matrix.outputs.matrix) }} steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install Python uses: actions/setup-python@v6 @@ -86,7 +85,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install Python uses: actions/setup-python@v6 @@ -105,7 +104,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Install Python uses: actions/setup-python@v6 diff --git a/.github/workflows/update-release.yml b/.github/workflows/update-release.yml index 282d2a104d..72bf49fc9d 100644 --- a/.github/workflows/update-release.yml +++ b/.github/workflows/update-release.yml @@ -49,7 +49,7 @@ jobs: - name: Generate token id: generate-token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@v3 with: app-id: ${{ vars.AUTOMATION_APP_ID }} private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} diff --git a/.github/workflows/upgrade_codeql_dependencies.yml b/.github/workflows/upgrade_codeql_dependencies.yml index 199cc04733..4ca973474a 100644 --- a/.github/workflows/upgrade_codeql_dependencies.yml +++ b/.github/workflows/upgrade_codeql_dependencies.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Fetch CodeQL env: diff --git a/.github/workflows/validate-package-files.yml b/.github/workflows/validate-package-files.yml index be8f0b1396..3e53fc9650 100644 --- a/.github/workflows/validate-package-files.yml +++ b/.github/workflows/validate-package-files.yml @@ -9,7 +9,6 @@ on: - main - next - "rc/**" - - michaelrfairhurst/package-undefined-behavior jobs: validate-package-files: @@ -19,7 +18,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ inputs.ref }} diff --git a/.github/workflows/validate-query-formatting.yml b/.github/workflows/validate-query-formatting.yml index 6f2bb96703..e059caeca7 100644 --- a/.github/workflows/validate-query-formatting.yml +++ b/.github/workflows/validate-query-formatting.yml @@ -9,7 +9,6 @@ on: - main - next - "rc/**" - - michaelrfairhurst/package-undefined-behavior env: XARGS_MAX_PROCS: 4 @@ -22,7 +21,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ inputs.ref }} diff --git a/.github/workflows/validate-query-help.yml b/.github/workflows/validate-query-help.yml index 9c80e4fcde..8ac04f1ba9 100644 --- a/.github/workflows/validate-query-help.yml +++ b/.github/workflows/validate-query-help.yml @@ -9,7 +9,6 @@ on: - main - next - "rc/**" - - michaelrfairhurst/package-undefined-behavior jobs: validate-query-help-files: @@ -19,7 +18,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ inputs.ref }} diff --git a/.github/workflows/validate-query-test-case-formatting.yml b/.github/workflows/validate-query-test-case-formatting.yml index cc51473a8a..70151fbf48 100644 --- a/.github/workflows/validate-query-test-case-formatting.yml +++ b/.github/workflows/validate-query-test-case-formatting.yml @@ -9,7 +9,6 @@ on: - main - next - "rc/**" - - michaelrfairhurst/package-undefined-behavior env: XARGS_MAX_PROCS: 4 @@ -23,7 +22,7 @@ jobs: fail-fast: false steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: ref: ${{ inputs.ref }} diff --git a/.github/workflows/validate-release.yml b/.github/workflows/validate-release.yml index cd7d27f6fa..1f25aee4c7 100644 --- a/.github/workflows/validate-release.yml +++ b/.github/workflows/validate-release.yml @@ -40,7 +40,7 @@ jobs: steps: - name: Generate token id: generate-token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@v3 with: app-id: ${{ vars.AUTOMATION_APP_ID }} private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} @@ -108,7 +108,7 @@ jobs: steps: - name: Generate token id: generate-token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@v3 with: app-id: ${{ vars.AUTOMATION_APP_ID }} private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} diff --git a/.github/workflows/verify-standard-library-dependencies.yml b/.github/workflows/verify-standard-library-dependencies.yml index 1dfc9e5829..581dd12183 100644 --- a/.github/workflows/verify-standard-library-dependencies.yml +++ b/.github/workflows/verify-standard-library-dependencies.yml @@ -24,7 +24,7 @@ jobs: matrix: ${{ steps.export-matrix.outputs.matrix }} steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Export unit test matrix id: export-matrix @@ -46,7 +46,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup Python 3 uses: actions/setup-python@v6 diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 82cad087ae..32839c8ce8 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -259,6 +259,7 @@ "Language1", "Language2", "Language3", + "Lifetime", "Linkage1", "Linkage2", "Literals", diff --git a/c/cert/src/codeql-pack.lock.yml b/c/cert/src/codeql-pack.lock.yml index 0ff25f8606..86c985eb17 100644 --- a/c/cert/src/codeql-pack.lock.yml +++ b/c/cert/src/codeql-pack.lock.yml @@ -1,6 +1,8 @@ --- lockVersion: 1.0.0 dependencies: + advanced-security/qtil: + version: 0.0.3 codeql/cpp-all: version: 5.0.0 codeql/dataflow: diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index 885052ed16..b3b0ac7096 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards -version: 2.55.0-dev +version: 2.56.0-dev description: CERT C 2016 suites: codeql-suites license: MIT diff --git a/c/cert/test/codeql-pack.lock.yml b/c/cert/test/codeql-pack.lock.yml index 0ff25f8606..86c985eb17 100644 --- a/c/cert/test/codeql-pack.lock.yml +++ b/c/cert/test/codeql-pack.lock.yml @@ -1,6 +1,8 @@ --- lockVersion: 1.0.0 dependencies: + advanced-security/qtil: + version: 0.0.3 codeql/cpp-all: version: 5.0.0 codeql/dataflow: diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index adc5aec939..a51647efd7 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards-tests -version: 2.55.0-dev +version: 2.56.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/common/src/codeql-pack.lock.yml b/c/common/src/codeql-pack.lock.yml index 0ff25f8606..86c985eb17 100644 --- a/c/common/src/codeql-pack.lock.yml +++ b/c/common/src/codeql-pack.lock.yml @@ -1,6 +1,8 @@ --- lockVersion: 1.0.0 dependencies: + advanced-security/qtil: + version: 0.0.3 codeql/cpp-all: version: 5.0.0 codeql/dataflow: diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index 0da3469f8b..45122b9132 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards -version: 2.55.0-dev +version: 2.56.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' diff --git a/c/common/test/codeql-pack.lock.yml b/c/common/test/codeql-pack.lock.yml index 0ff25f8606..86c985eb17 100644 --- a/c/common/test/codeql-pack.lock.yml +++ b/c/common/test/codeql-pack.lock.yml @@ -1,6 +1,8 @@ --- lockVersion: 1.0.0 dependencies: + advanced-security/qtil: + version: 0.0.3 codeql/cpp-all: version: 5.0.0 codeql/dataflow: diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index d6d2253051..0bd91b3b9e 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards-tests -version: 2.55.0-dev +version: 2.56.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/common/test/rules/possibledataracebetweenthreadsshared/PossibleDataRaceBetweenThreadsShared.expected b/c/common/test/rules/possibledataracebetweenthreadsshared/PossibleDataRaceBetweenThreadsShared.expected index e1c0e9389d..ca6c50128e 100644 --- a/c/common/test/rules/possibledataracebetweenthreadsshared/PossibleDataRaceBetweenThreadsShared.expected +++ b/c/common/test/rules/possibledataracebetweenthreadsshared/PossibleDataRaceBetweenThreadsShared.expected @@ -8,6 +8,7 @@ | test.c:82:3:82:7 | call to srand | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:82:3:82:7 | call to srand | srand | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:82:3:82:7 | call to srand | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | | test.c:83:3:83:8 | call to getenv | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:83:3:83:8 | call to getenv | getenv | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:83:3:83:8 | call to getenv | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | | test.c:84:3:84:10 | call to getenv_s | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:84:3:84:10 | call to getenv_s | getenv_s | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:84:3:84:10 | call to getenv_s | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:85:3:85:8 | call to strtok | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:85:3:85:8 | call to strtok | strtok | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:85:3:85:8 | call to strtok | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | | test.c:86:3:86:10 | call to strerror | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:86:3:86:10 | call to strerror | strerror | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:86:3:86:10 | call to strerror | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | | test.c:87:3:87:9 | call to asctime | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:87:3:87:9 | call to asctime | asctime | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:87:3:87:9 | call to asctime | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | | test.c:88:3:88:7 | call to ctime | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:88:3:88:7 | call to ctime | ctime | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:88:3:88:7 | call to ctime | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | diff --git a/c/misra/src/codeql-pack.lock.yml b/c/misra/src/codeql-pack.lock.yml index 0ff25f8606..86c985eb17 100644 --- a/c/misra/src/codeql-pack.lock.yml +++ b/c/misra/src/codeql-pack.lock.yml @@ -1,6 +1,8 @@ --- lockVersion: 1.0.0 dependencies: + advanced-security/qtil: + version: 0.0.3 codeql/cpp-all: version: 5.0.0 codeql/dataflow: diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index 23057987a5..bbfe4d0feb 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards -version: 2.55.0-dev +version: 2.56.0-dev description: MISRA C 2012 suites: codeql-suites license: MIT diff --git a/c/misra/test/codeql-pack.lock.yml b/c/misra/test/codeql-pack.lock.yml index 0ff25f8606..86c985eb17 100644 --- a/c/misra/test/codeql-pack.lock.yml +++ b/c/misra/test/codeql-pack.lock.yml @@ -1,6 +1,8 @@ --- lockVersion: 1.0.0 dependencies: + advanced-security/qtil: + version: 0.0.3 codeql/cpp-all: version: 5.0.0 codeql/dataflow: diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index 314be1e54c..03dc4d254a 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards-tests -version: 2.55.0-dev +version: 2.56.0-dev extractor: cpp license: MIT dependencies: diff --git a/change_notes/2026-02-03-uninitialized-mem-improve.md b/change_notes/2026-02-03-uninitialized-mem-improve.md new file mode 100644 index 0000000000..c3db99391b --- /dev/null +++ b/change_notes/2026-02-03-uninitialized-mem-improve.md @@ -0,0 +1,2 @@ +- `A8-5-0`, `EXP53-CPP`, `EXP33-C`, `RULE-9-1` - `MemoryNotInitializedBeforeItIsRead.ql`, `DoNotReadUninitializedMemory.ql`, `DoNotReadUninitializedMemory.ql`, `ObjectWithAutoStorageDurationReadBeforeInit.ql`: + - The queries listed now find uses of the operator 'new' where there is no value initialization provided. The queries listed now also uses an out of the box library to consider initialization within another function as valid initialization (`InitializationFunctions.qll`). We do not yet track finely track the initialization/use of `p` vs `*p`. \ No newline at end of file diff --git a/change_notes/2026-03-13-share-array-delete-type-mismatch-query.md b/change_notes/2026-03-13-share-array-delete-type-mismatch-query.md new file mode 100644 index 0000000000..38b11f3517 --- /dev/null +++ b/change_notes/2026-03-13-share-array-delete-type-mismatch-query.md @@ -0,0 +1,3 @@ + - `EXP51-CPP` - `DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql`: + - Refactored query logic into a shared library (`DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.qll`) to enable reuse by MISRA C++ `RULE-4-1-3`. The query logic is unchanged and no visible changes to results or performance are expected. + - The query now uses a `query predicate problems` instead of a `from/where/select`. In path-problem BQRS output, the results section header changes from `#select` to `problems`. Alert results and their content are otherwise identical. diff --git a/cpp/autosar/src/codeql-pack.lock.yml b/cpp/autosar/src/codeql-pack.lock.yml index 0ff25f8606..86c985eb17 100644 --- a/cpp/autosar/src/codeql-pack.lock.yml +++ b/cpp/autosar/src/codeql-pack.lock.yml @@ -1,6 +1,8 @@ --- lockVersion: 1.0.0 dependencies: + advanced-security/qtil: + version: 0.0.3 codeql/cpp-all: version: 5.0.0 codeql/dataflow: diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index b467f866b5..36d39bd50f 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards -version: 2.55.0-dev +version: 2.56.0-dev description: AUTOSAR C++14 Guidelines R22-11, R21-11, R20-11, R19-11 and R19-03 suites: codeql-suites license: MIT diff --git a/cpp/autosar/test/codeql-pack.lock.yml b/cpp/autosar/test/codeql-pack.lock.yml index 0ff25f8606..86c985eb17 100644 --- a/cpp/autosar/test/codeql-pack.lock.yml +++ b/cpp/autosar/test/codeql-pack.lock.yml @@ -1,6 +1,8 @@ --- lockVersion: 1.0.0 dependencies: + advanced-security/qtil: + version: 0.0.3 codeql/cpp-all: version: 5.0.0 codeql/dataflow: diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index cee3a37971..32216fe714 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards-tests -version: 2.55.0-dev +version: 2.56.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/cert/src/codeql-pack.lock.yml b/cpp/cert/src/codeql-pack.lock.yml index 0ff25f8606..86c985eb17 100644 --- a/cpp/cert/src/codeql-pack.lock.yml +++ b/cpp/cert/src/codeql-pack.lock.yml @@ -1,6 +1,8 @@ --- lockVersion: 1.0.0 dependencies: + advanced-security/qtil: + version: 0.0.3 codeql/cpp-all: version: 5.0.0 codeql/dataflow: diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index 3960b52cdd..0a938c862a 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards -version: 2.55.0-dev +version: 2.56.0-dev description: CERT C++ 2016 suites: codeql-suites license: MIT diff --git a/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql b/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql index d0935cc798..ae1a767f66 100644 --- a/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql +++ b/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql @@ -18,29 +18,18 @@ import cpp import codingstandards.cpp.cert -import semmle.code.cpp.dataflow.DataFlow -import AllocationToDeleteFlow::PathGraph +import codingstandards.cpp.rules.donotdeleteanarraythroughapointeroftheincorrecttypeshared.DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared -module AllocationToDeleteConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { source.asExpr() instanceof NewArrayExpr } - - predicate isSink(DataFlow::Node sink) { - exists(DeleteArrayExpr dae | dae.getExpr() = sink.asExpr()) +module DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeConfig implements + DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeSharedConfigSig +{ + Query getQuery() { + result = FreedPackage::doNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeQuery() } } -module AllocationToDeleteFlow = DataFlow::Global; +module Shared = + DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared; -from - AllocationToDeleteFlow::PathNode source, AllocationToDeleteFlow::PathNode sink, - NewArrayExpr newArray, DeleteArrayExpr deleteArray -where - not isExcluded(deleteArray.getExpr(), - FreedPackage::doNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeQuery()) and - AllocationToDeleteFlow::flowPath(source, sink) and - newArray = source.getNode().asExpr() and - deleteArray.getExpr() = sink.getNode().asExpr() and - not newArray.getType().getUnspecifiedType() = deleteArray.getExpr().getType().getUnspecifiedType() -select sink, source, sink, - "Array of type " + newArray.getType() + " is deleted through a pointer of type " + - deleteArray.getExpr().getType() + "." +import Shared::PathGraph +import Shared diff --git a/cpp/cert/test/codeql-pack.lock.yml b/cpp/cert/test/codeql-pack.lock.yml index 0ff25f8606..86c985eb17 100644 --- a/cpp/cert/test/codeql-pack.lock.yml +++ b/cpp/cert/test/codeql-pack.lock.yml @@ -1,6 +1,8 @@ --- lockVersion: 1.0.0 dependencies: + advanced-security/qtil: + version: 0.0.3 codeql/cpp-all: version: 5.0.0 codeql/dataflow: diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index e2b6ba0b75..d6c003da26 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards-tests -version: 2.55.0-dev +version: 2.56.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected b/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected deleted file mode 100644 index 8b7a4902cc..0000000000 --- a/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected +++ /dev/null @@ -1,15 +0,0 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:24,44-52) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:25,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:27,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:32,33-41) -edges -| test.cpp:6:19:6:37 | new[] | test.cpp:9:12:9:13 | l1 | provenance | | -| test.cpp:7:22:7:40 | new[] | test.cpp:10:12:10:13 | l2 | provenance | | -nodes -| test.cpp:6:19:6:37 | new[] | semmle.label | new[] | -| test.cpp:7:22:7:40 | new[] | semmle.label | new[] | -| test.cpp:9:12:9:13 | l1 | semmle.label | l1 | -| test.cpp:10:12:10:13 | l2 | semmle.label | l2 | -subpaths -#select -| test.cpp:9:12:9:13 | l1 | test.cpp:6:19:6:37 | new[] | test.cpp:9:12:9:13 | l1 | Array of type DerivedClass * is deleted through a pointer of type BaseClass *. | diff --git a/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.qlref b/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.qlref deleted file mode 100644 index fbeac87143..0000000000 --- a/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql \ No newline at end of file diff --git a/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.testref b/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.testref new file mode 100644 index 0000000000..069f5724f8 --- /dev/null +++ b/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.testref @@ -0,0 +1 @@ +cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.ql diff --git a/cpp/common/src/codeql-pack.lock.yml b/cpp/common/src/codeql-pack.lock.yml index 0ff25f8606..86c985eb17 100644 --- a/cpp/common/src/codeql-pack.lock.yml +++ b/cpp/common/src/codeql-pack.lock.yml @@ -1,6 +1,8 @@ --- lockVersion: 1.0.0 dependencies: + advanced-security/qtil: + version: 0.0.3 codeql/cpp-all: version: 5.0.0 codeql/dataflow: diff --git a/cpp/common/src/codingstandards/cpp/ast/Conditions.qll b/cpp/common/src/codingstandards/cpp/ast/Conditions.qll new file mode 100644 index 0000000000..1a5c84c347 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/ast/Conditions.qll @@ -0,0 +1,29 @@ +import cpp +import codeql.util.Boolean + +/** + * Any type of conditional evaluation, such as if statements, and conditional expressions. + * + * A condition may be: + * - An if statement condition + * - A conditional expression (ternary) condition + * - A short-circuiting logical expression (&& or ||) + */ +class Conditional extends Element { + Expr condition; + + Conditional() { + condition = this.(ConditionalExpr).getCondition() + or + condition = this.(IfStmt).getCondition() + or + condition = this.(LogicalOrExpr).getLeftOperand() + or + condition = this.(LogicalAndExpr).getLeftOperand() + } + + /** + * Get the expression that controls the flow of this conditional. + */ + Expr getCondition() { result = condition } +} diff --git a/cpp/common/src/codingstandards/cpp/ast/Search.qll b/cpp/common/src/codingstandards/cpp/ast/Search.qll new file mode 100644 index 0000000000..6385938894 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/ast/Search.qll @@ -0,0 +1,21 @@ +import cpp +import qtil.Qtil + +module OutermostSearch::Type Find> { + Find find(Element e) { + // Do not return a result if there are multiple siblings to different `Find`s. + result = unique(Find found | found = outermostSearchImpl(e)) + } + + private Find outermostSearchImpl(Element e) { + if e instanceof Find + then result = e + else ( + result = outermostSearchImpl(e.(ExprStmt).getExpr()) + or + result = outermostSearchImpl(e.(Stmt).getAChild()) + or + result = outermostSearchImpl(e.(Expr).getAChild()) + ) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations1.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations1.qll new file mode 100644 index 0000000000..51d68035bc --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Declarations1.qll @@ -0,0 +1,26 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Declarations1Query = TDeclarationsOfAFunctionSameParameterNameQuery() + +predicate isDeclarations1QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `declarationsOfAFunctionSameParameterName` query + Declarations1Package::declarationsOfAFunctionSameParameterNameQuery() and + queryId = + // `@id` for the `declarationsOfAFunctionSameParameterName` query + "cpp/misra/declarations-of-a-function-same-parameter-name" and + ruleId = "RULE-13-3-3" and + category = "required" +} + +module Declarations1Package { + Query declarationsOfAFunctionSameParameterNameQuery() { + //autogenerate `Query` type + result = + // `Query` type for `declarationsOfAFunctionSameParameterName` query + TQueryCPP(TDeclarations1PackageQuery(TDeclarationsOfAFunctionSameParameterNameQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Lifetime.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Lifetime.qll new file mode 100644 index 0000000000..bb06eaaf8f --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Lifetime.qll @@ -0,0 +1,44 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype LifetimeQuery = + TValueOfAnObjectMustNotBeReadBeforeItHasBeenSetQuery() or + TAutomaticStorageAssignedToObjectGreaterLifetimeQuery() + +predicate isLifetimeQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `valueOfAnObjectMustNotBeReadBeforeItHasBeenSet` query + LifetimePackage::valueOfAnObjectMustNotBeReadBeforeItHasBeenSetQuery() and + queryId = + // `@id` for the `valueOfAnObjectMustNotBeReadBeforeItHasBeenSet` query + "cpp/misra/value-of-an-object-must-not-be-read-before-it-has-been-set" and + ruleId = "RULE-11-6-2" and + category = "mandatory" + or + query = + // `Query` instance for the `automaticStorageAssignedToObjectGreaterLifetime` query + LifetimePackage::automaticStorageAssignedToObjectGreaterLifetimeQuery() and + queryId = + // `@id` for the `automaticStorageAssignedToObjectGreaterLifetime` query + "cpp/misra/automatic-storage-assigned-to-object-greater-lifetime" and + ruleId = "RULE-6-8-3" and + category = "required" +} + +module LifetimePackage { + Query valueOfAnObjectMustNotBeReadBeforeItHasBeenSetQuery() { + //autogenerate `Query` type + result = + // `Query` type for `valueOfAnObjectMustNotBeReadBeforeItHasBeenSet` query + TQueryCPP(TLifetimePackageQuery(TValueOfAnObjectMustNotBeReadBeforeItHasBeenSetQuery())) + } + + Query automaticStorageAssignedToObjectGreaterLifetimeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `automaticStorageAssignedToObjectGreaterLifetime` query + TQueryCPP(TLifetimePackageQuery(TAutomaticStorageAssignedToObjectGreaterLifetimeQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Preconditions3.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Preconditions3.qll new file mode 100644 index 0000000000..8bc8afb0e6 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Preconditions3.qll @@ -0,0 +1,26 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Preconditions3Query = TAssertMacroUsedWithAConstantExpressionQuery() + +predicate isPreconditions3QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `assertMacroUsedWithAConstantExpression` query + Preconditions3Package::assertMacroUsedWithAConstantExpressionQuery() and + queryId = + // `@id` for the `assertMacroUsedWithAConstantExpression` query + "cpp/misra/assert-macro-used-with-a-constant-expression" and + ruleId = "RULE-22-3-1" and + category = "required" +} + +module Preconditions3Package { + Query assertMacroUsedWithAConstantExpressionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `assertMacroUsedWithAConstantExpression` query + TQueryCPP(TPreconditions3PackageQuery(TAssertMacroUsedWithAConstantExpressionQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll index efbe78d417..eefa9d6f8a 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll @@ -27,6 +27,7 @@ import DeadCode7 import DeadCode8 import DeadCode9 import Declarations +import Declarations1 import ExceptionSafety import Exceptions1 import Exceptions2 @@ -45,6 +46,7 @@ import IntegerConversion import Invariants import Iterators import Lambdas +import Lifetime import Linkage1 import Linkage2 import Literals @@ -65,6 +67,7 @@ import OrderOfEvaluation import OutOfBounds import Pointers import Preconditions1 +import Preconditions3 import Preconditions4 import Preprocessor import Preprocessor2 @@ -116,6 +119,7 @@ newtype TCPPQuery = TDeadCode8PackageQuery(DeadCode8Query q) or TDeadCode9PackageQuery(DeadCode9Query q) or TDeclarationsPackageQuery(DeclarationsQuery q) or + TDeclarations1PackageQuery(Declarations1Query q) or TExceptionSafetyPackageQuery(ExceptionSafetyQuery q) or TExceptions1PackageQuery(Exceptions1Query q) or TExceptions2PackageQuery(Exceptions2Query q) or @@ -134,6 +138,7 @@ newtype TCPPQuery = TInvariantsPackageQuery(InvariantsQuery q) or TIteratorsPackageQuery(IteratorsQuery q) or TLambdasPackageQuery(LambdasQuery q) or + TLifetimePackageQuery(LifetimeQuery q) or TLinkage1PackageQuery(Linkage1Query q) or TLinkage2PackageQuery(Linkage2Query q) or TLiteralsPackageQuery(LiteralsQuery q) or @@ -154,6 +159,7 @@ newtype TCPPQuery = TOutOfBoundsPackageQuery(OutOfBoundsQuery q) or TPointersPackageQuery(PointersQuery q) or TPreconditions1PackageQuery(Preconditions1Query q) or + TPreconditions3PackageQuery(Preconditions3Query q) or TPreconditions4PackageQuery(Preconditions4Query q) or TPreprocessorPackageQuery(PreprocessorQuery q) or TPreprocessor2PackageQuery(Preprocessor2Query q) or @@ -205,6 +211,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isDeadCode8QueryMetadata(query, queryId, ruleId, category) or isDeadCode9QueryMetadata(query, queryId, ruleId, category) or isDeclarationsQueryMetadata(query, queryId, ruleId, category) or + isDeclarations1QueryMetadata(query, queryId, ruleId, category) or isExceptionSafetyQueryMetadata(query, queryId, ruleId, category) or isExceptions1QueryMetadata(query, queryId, ruleId, category) or isExceptions2QueryMetadata(query, queryId, ruleId, category) or @@ -223,6 +230,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isInvariantsQueryMetadata(query, queryId, ruleId, category) or isIteratorsQueryMetadata(query, queryId, ruleId, category) or isLambdasQueryMetadata(query, queryId, ruleId, category) or + isLifetimeQueryMetadata(query, queryId, ruleId, category) or isLinkage1QueryMetadata(query, queryId, ruleId, category) or isLinkage2QueryMetadata(query, queryId, ruleId, category) or isLiteralsQueryMetadata(query, queryId, ruleId, category) or @@ -243,6 +251,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isOutOfBoundsQueryMetadata(query, queryId, ruleId, category) or isPointersQueryMetadata(query, queryId, ruleId, category) or isPreconditions1QueryMetadata(query, queryId, ruleId, category) or + isPreconditions3QueryMetadata(query, queryId, ruleId, category) or isPreconditions4QueryMetadata(query, queryId, ruleId, category) or isPreprocessorQueryMetadata(query, queryId, ruleId, category) or isPreprocessor2QueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Undefined.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Undefined.qll index a1fcf5afd3..6c865693ff 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Undefined.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Undefined.qll @@ -5,6 +5,7 @@ import codingstandards.cpp.exclusions.RuleMetadata newtype UndefinedQuery = TPossibleDataRaceBetweenThreadsQuery() or + TArrayDeletedThroughPointerOfIncorrectTypeQuery() or TSignedIntegerOverflowQuery() or TDivisionByZeroUndefinedBehaviorQuery() or TDeallocationTypeMismatchQuery() or @@ -24,6 +25,15 @@ predicate isUndefinedQueryMetadata(Query query, string queryId, string ruleId, s ruleId = "RULE-4-1-3" and category = "required" or + query = + // `Query` instance for the `arrayDeletedThroughPointerOfIncorrectType` query + UndefinedPackage::arrayDeletedThroughPointerOfIncorrectTypeQuery() and + queryId = + // `@id` for the `arrayDeletedThroughPointerOfIncorrectType` query + "cpp/misra/array-deleted-through-pointer-of-incorrect-type" and + ruleId = "RULE-4-1-3" and + category = "required" + or query = // `Query` instance for the `signedIntegerOverflow` query UndefinedPackage::signedIntegerOverflowQuery() and @@ -105,6 +115,13 @@ module UndefinedPackage { TQueryCPP(TUndefinedPackageQuery(TPossibleDataRaceBetweenThreadsQuery())) } + Query arrayDeletedThroughPointerOfIncorrectTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `arrayDeletedThroughPointerOfIncorrectType` query + TQueryCPP(TUndefinedPackageQuery(TArrayDeletedThroughPointerOfIncorrectTypeQuery())) + } + Query signedIntegerOverflowQuery() { //autogenerate `Query` type result = diff --git a/cpp/common/src/codingstandards/cpp/lifetimes/CppObjects.qll b/cpp/common/src/codingstandards/cpp/lifetimes/CppObjects.qll index 4ef3122805..1c38859cb8 100644 --- a/cpp/common/src/codingstandards/cpp/lifetimes/CppObjects.qll +++ b/cpp/common/src/codingstandards/cpp/lifetimes/CppObjects.qll @@ -246,7 +246,7 @@ class AggregateLiteralObjectIdentity extends AggregateLiteral, ObjectIdentityBas } /** - * An object identified by a call to `malloc`. + * An object identified by a call to `malloc` or allcoated with a `new` or `new[]` expression. * * Note: the malloc expression returns an address to this object, not the object itself. Therefore, * `getAnAccess()` returns cases where this malloc result is dereferenced, and not the malloc call @@ -262,6 +262,8 @@ class AggregateLiteralObjectIdentity extends AggregateLiteral, ObjectIdentityBas class AllocatedObjectIdentity extends AllocationExpr, ObjectIdentityBase { AllocatedObjectIdentity() { this.(FunctionCall).getTarget().(AllocationFunction).requiresDealloc() + or + this = any(NewOrNewArrayExpr new | not exists(new.getPlacementPointer())) } override StorageDuration getStorageDuration() { result.isAllocated() } diff --git a/cpp/common/src/codingstandards/cpp/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.qll b/cpp/common/src/codingstandards/cpp/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.qll new file mode 100644 index 0000000000..d526632f89 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.qll @@ -0,0 +1,48 @@ +/** + * Provides a configurable module DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared + * with a `problems` predicate for the following issue: + * Deleting an array through a pointer of an incorrect type leads to undefined behavior. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import semmle.code.cpp.dataflow.DataFlow + +signature module DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeSharedConfigSig { + Query getQuery(); +} + +module DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared< + DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeSharedConfigSig Config> +{ + private module AllocationToDeleteConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof NewArrayExpr } + + predicate isSink(DataFlow::Node sink) { + exists(DeleteArrayExpr dae | dae.getExpr() = sink.asExpr()) + } + } + + module AllocationToDeleteFlow = DataFlow::Global; + + module PathGraph = AllocationToDeleteFlow::PathGraph; + + query predicate problems( + Expr deleteExpr, AllocationToDeleteFlow::PathNode source, AllocationToDeleteFlow::PathNode sink, + string message + ) { + exists(NewArrayExpr newArray, DeleteArrayExpr deleteArray | + not isExcluded(deleteArray.getExpr(), Config::getQuery()) and + AllocationToDeleteFlow::flowPath(source, sink) and + newArray = source.getNode().asExpr() and + deleteArray.getExpr() = sink.getNode().asExpr() and + not newArray.getType().getUnspecifiedType() = + deleteArray.getExpr().getType().getUnspecifiedType() and + deleteExpr = sink.getNode().asExpr() and + message = + "Array of type " + newArray.getType() + " is deleted through a pointer of type " + + deleteArray.getExpr().getType() + "." + ) + } +} diff --git a/cpp/common/src/codingstandards/cpp/rules/possibledataracebetweenthreadsshared/PossibleDataRaceBetweenThreadsShared.qll b/cpp/common/src/codingstandards/cpp/rules/possibledataracebetweenthreadsshared/PossibleDataRaceBetweenThreadsShared.qll index 966d6bcba3..b4aa239f65 100644 --- a/cpp/common/src/codingstandards/cpp/rules/possibledataracebetweenthreadsshared/PossibleDataRaceBetweenThreadsShared.qll +++ b/cpp/common/src/codingstandards/cpp/rules/possibledataracebetweenthreadsshared/PossibleDataRaceBetweenThreadsShared.qll @@ -37,7 +37,7 @@ module PossibleDataRaceBetweenThreadsShared 0` in `assert(x > 0);`. + * + * Since the assert macro may expand to various forms of conditional statements, this method + * uses a combination of AST inspection and control flow analysis to determine the actual + * condition being asserted. + * + * For example, `assert(x)` may expand to `{ if (!__unlikely(x)) abort(); }`. In this case: + * - We first identify the "outermost conditional" generated by the macro, which is the `if` + * statement, with the raw condition `!__unlikely(x)`. + * - We then analyze the control flow to see if the abort occurs when this raw condition is true + * or false. In this case, it aborts when the raw condition `!__unlikely(x)` is true. + * - To unwrap the user provided condition `x` from the raw condition, we remove the compiler + * intrinsics such as `__unlikely`. + * - Lastly, we also account for the negation. Since the program aborts on `!x`, we know we are + * asserting `!x` is false, which is equivalent to asserting `x` is true. + * + * Note that the last two bullets are handled in either order, to support `!__unlikely(x)` or + * `__unlikely(!x)`. + */ + Expr getAssertCondition() { + exists(Conditional conditional, Expr condition, Boolean isTrue | + // Get the outermost conditional in the assert body (if, &&, ||, ?:, etc). + conditional = OutermostSearch::find(this.getGeneratedBody()) and + condition = conditional.getCondition() and + // An assertion of form `assert(x)` may expand to a negated form, e.g. `if (!x) abort()`, or + // it may expand to a non-negated form e.g. `x || abort()`. We check whether the condition + // appears to abort when `condition` is true or false to distinguish these cases. + Asserts::appearsToAssert(conditional, isTrue) and + // If we seem to be asserting the condition is both true and false, give no result. + not Asserts::appearsToAssert(conditional, isTrue.booleanNot()) and + // Unwrap compiler inserted calls around the actual asserted condition such as `__unlikely`, + // and unwrap conditions such as `!x` if we found `appearsToAssert(conditional, false)`. + result = Asserts::unwrapAssertRawCondition(condition, isTrue.booleanNot()) + ) + } + + /** + * Helper method to get the body whether it is a statement or an expression. + */ + Element getGeneratedBody() { result = this.getStmt() or result = this.getExpr() } + + /** + * Holds if this is an assertion of the form `assert(false)` or `assert(false && "message")`. + */ + predicate isAssertFalse() { + exists(Expr assertCondition | + assertCondition = this.getAssertCondition() and + ( + // plain `assert(false)` + assertCondition.(Literal).getValue() = "0" + or + // with literal, e.g. `assert(false && "message")` + exists(LogicalAndExpr lAnd | + lAnd = assertCondition and + lAnd.getLeftOperand().(Literal).getValue() = "0" and + lAnd.getRightOperand() instanceof StringLiteral + ) + ) + ) + } +} + +private module Asserts { + /** + * The outermost condition of an assert macro may not be the actual condition passed to assert, as + * the compiler may insert special calls like `__unlikely` or `__builtin_expect` around it. This + * function unwraps those calls to get to the actual condition. + * + * `negated` indicates whether negations were unwrapped. For example, `assert(x)` may expand + * to `if (!x) abort();`, so this predicate would hold for `(x, true)` and `(!x, false)`. + */ + Expr unwrapAssertRawCondition(Expr e, Boolean negated) { + exists(Boolean inner_negated | + result = unwrapAssertRawCondition(e.(NotExpr).getOperand(), inner_negated) and + negated = inner_negated.booleanNot() + ) + or + if e.(FunctionCall).getTarget().getName().matches("__%") + then result = unwrapAssertRawCondition(e.(FunctionCall).getArgument(0), negated) + else ( + result = e and negated = false + ) + } + + /** + * Holds if the given conditional appears to assert its condition to be `isTrue`. + * + * For example, both `x || abort();` and `if (!x) abort();` effectively assert that `x` + * is true (in the second case, by asserting that `!x` is false). + */ + predicate appearsToAssert(Conditional conditional, Boolean isTrue) { + // Check if an aborting side is reachable via the given boolean value of the condition. + sideAborts(conditional, _, isTrue.booleanNot()) + or + // If the condition is a constant value, then we may not be able to reach the side that aborts + // via control flow. Detect such cases here. + not sideAborts(conditional, _, _) and + ( + // If the false side is unreachable, we presume the false side aborts when reachable + not exists(conditional.getCondition().getAFalseSuccessor()) and + // Therefore this asserts the condition is true + isTrue = true + or + // If the true side is unreachable, we presume the true side aborts when reachable + not exists(conditional.getCondition().getATrueSuccessor()) and + // Therefore this asserts the condition is false + isTrue = false + ) + } + + /** + * Holds if a control flow node contained by the `conditional` ast node appears to abort the + * program when the condition evaluates to `isTrue`. + */ + predicate sideAborts(Conditional conditional, Expr abort, Boolean isTrue) { + abort.getEnclosingElement*() = conditional and + appearsToAbort(abort) and + exists(ControlFlowNode branch | + branch.getASuccessor*() = abort and + ( + isTrue = true and + branch = conditional.getCondition().(ControlFlowNode).getATrueSuccessor() + or + isTrue = false and + branch = conditional.getCondition().(ControlFlowNode).getAFalseSuccessor() + ) + ) + } + + /** + * Holds if a control flow node appears to abort the program. + * + * We currently detect: + * - Calls to functions with "fail" or "abort" in their name. + * - Calls to functions beginning with "__" and containing "assert" in their name. + * - Nodes with no successors (e.g. a call to `std::terminate` or a throw statement). + */ + predicate appearsToAbort(ControlFlowNode node) { + node.(FunctionCall).getTarget().getName().matches(["%fail%", "%abort%", "__%assert"]) + or + not exists(node.getASuccessor()) and not node instanceof Conversion + } +} + +import Asserts diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index 12adf36c15..34bcb1cdbf 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,8 +1,9 @@ name: codeql/common-cpp-coding-standards -version: 2.55.0-dev +version: 2.56.0-dev license: MIT dependencies: codeql/cpp-all: 5.0.0 + advanced-security/qtil: "0.0.3" dataExtensions: - ext/*.model.yml - ext/unicode.yml diff --git a/cpp/common/test/codeql-pack.lock.yml b/cpp/common/test/codeql-pack.lock.yml index 0ff25f8606..86c985eb17 100644 --- a/cpp/common/test/codeql-pack.lock.yml +++ b/cpp/common/test/codeql-pack.lock.yml @@ -1,6 +1,8 @@ --- lockVersion: 1.0.0 dependencies: + advanced-security/qtil: + version: 0.0.3 codeql/cpp-all: version: 5.0.0 codeql/dataflow: diff --git a/cpp/common/test/includes/standard-library/assert.h b/cpp/common/test/includes/standard-library/assert.h index e8ba88d635..20d6528e61 100644 --- a/cpp/common/test/includes/standard-library/assert.h +++ b/cpp/common/test/includes/standard-library/assert.h @@ -1,6 +1,13 @@ #ifndef _GHLIBCPP_ASSERT #define _GHLIBCPP_ASSERT -#define assert(x) (void)0 +#include +#include + +#define __assert(e, file, line) \ + ((void)printf ("%s:%d: failed assertion `%s'\n", file, line, e), abort()) + +#define assert(e) \ + { (__builtin_expect(!(e), 0) ? __assert (#e, __FILE__, __LINE__) : (void)0); } #endif // _GHLIBCPP_ASSERT \ No newline at end of file diff --git a/cpp/common/test/library/codingstandards/cpp/standardlibrary/Assert/AssertTest.expected b/cpp/common/test/library/codingstandards/cpp/standardlibrary/Assert/AssertTest.expected new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/common/test/library/codingstandards/cpp/standardlibrary/Assert/AssertTest.ql b/cpp/common/test/library/codingstandards/cpp/standardlibrary/Assert/AssertTest.ql new file mode 100644 index 0000000000..2072f59660 --- /dev/null +++ b/cpp/common/test/library/codingstandards/cpp/standardlibrary/Assert/AssertTest.ql @@ -0,0 +1,25 @@ +import cpp +import codingstandards.cpp.standardlibrary.Assert +import utils.test.InlineExpectationsTest + +module AssertTest implements TestSig { + string getARelevantTag() { result = ["asserts_false", "condition"] } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(AssertInvocation assert, Expr condition | + condition = assert.getAssertCondition() and + location = assert.getLocation() and + element = condition.toString() and + ( + tag = "condition" and + value = condition.toString().replaceAll(" ", "") + or + tag = "asserts_false" and + value = "true" and + assert.isAssertFalse() + ) + ) + } +} + +import MakeTest diff --git a/cpp/common/test/library/codingstandards/cpp/standardlibrary/Assert/test.cpp b/cpp/common/test/library/codingstandards/cpp/standardlibrary/Assert/test.cpp new file mode 100644 index 0000000000..6017847233 --- /dev/null +++ b/cpp/common/test/library/codingstandards/cpp/standardlibrary/Assert/test.cpp @@ -0,0 +1,81 @@ +/** + * C-style assert macros can be implemented in many different structures. + * + * This aims to test that we support as many of these as possible. + */ + +// Disable clang-format for this file to enable inline tests. +// clang-format off + +bool __unlikely(bool condition); +bool __likely(bool condition); +void __assert(const char* expr, const char* file, int line); +bool __custom_abort(const char* expr, const char* file, int line); +void __print(const char* expr, const char* file, int line); +void abort(); +[[noreturn]] void end_control_flow(); + +#define assert(X) \ + { (__builtin_expect(!(X), 0) ? __assert (#X, __FILE__, __LINE__) : (void)0); } + +void g() {} + +void f1(int x) { + assert(x); // $ condition=x + assert(false); // $ condition=0 asserts_false=true + assert(false && "abort here"); // $ condition=...&&... asserts_false=true + assert(0); // $ condition=0 asserts_false=true + assert(1); // $ condition=1 + assert(1 && "always true"); // $ condition=...&&... + assert(x ? 1 : 0); // $ condition=...?...:... +} + +#define assert(X) \ + { __builtin_expect((X), 1) ? (void)0 : __assert (#X, __FILE__, __LINE__); } + +void f2(int x) { + assert(x); // $ condition=x + assert(false); // $ condition=0 asserts_false=true + assert(0); // $ condition=0 asserts_false=true + assert(1); // $ condition=1 +} + +#define assert(X) \ + { if(!(X)) { __print (#X, __FILE__, __LINE__); abort(); } } + +void f3(int x) { + assert(x); // $ condition=x + assert(false); // $ condition=0 asserts_false=true + assert(0); // $ condition=0 asserts_false=true + assert(1); // $ condition=1 +} + +#define assert(X) \ + { __likely(X) || __custom_abort (#X, __FILE__, __LINE__); } + +void f4(int x) { + assert(x); // $ condition=x + assert(false); // $ condition=0 asserts_false=true + assert(0); // $ condition=0 asserts_false=true + assert(1); // $ condition=1 +} + +#define assert(X) \ + { __unlikely(!(X)) && __custom_abort (#X, __FILE__, __LINE__); } + +void f5(int x) { + assert(x); // $ condition=x + assert(false); // $ condition=0 asserts_false=true + assert(0); // $ condition=0 asserts_false=true + assert(1); // $ condition=1 +} + +#define assert(X) \ + { if (__unlikely((X))) { (void) 0; } else { __print( #X, __FILE__, __LINE__); end_control_flow(); } } + +void f6(int x) { + assert(x); // $ condition=x + assert(false); // $ condition=0 asserts_false=true + assert(0); // $ condition=0 asserts_false=true + assert(1); // $ condition=1 +} \ No newline at end of file diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index e518c4a1fe..9099955d68 100644 --- a/cpp/common/test/qlpack.yml +++ b/cpp/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards-tests -version: 2.55.0-dev +version: 2.56.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.expected b/cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.expected index 8699ae2d8a..35d2fd438a 100644 --- a/cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.expected +++ b/cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.expected @@ -62,3 +62,5 @@ | stack_escapes_test.cpp:367:3:367:17 | ... = ... | A stack address ($@) may be assigned to a non-local variable. | stack_escapes_test.cpp:367:17:367:17 | x | source | | stack_escapes_test.cpp:368:3:368:20 | ... = ... | A stack address ($@) may be assigned to a non-local variable. | stack_escapes_test.cpp:368:20:368:20 | x | source | | test.cpp:7:5:7:10 | ... = ... | A stack address ($@) may be assigned to a non-local variable. | test.cpp:7:10:7:10 | c | source | +| test.cpp:15:5:15:11 | ... = ... | A stack address ($@) may be assigned to a non-local variable. | test.cpp:15:9:15:11 | l_a | source | +| test.cpp:26:5:26:10 | ... = ... | A stack address ($@) may be assigned to a non-local variable. | test.cpp:25:11:25:11 | l | source | diff --git a/cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/test.cpp b/cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/test.cpp index 0cd3970c7e..5014ecf9cb 100644 --- a/cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/test.cpp +++ b/cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/test.cpp @@ -6,4 +6,23 @@ void test_simple_aliasing() { int c; a = &c; // NON_COMPLIANT - different scope } +} + +void extra_test_simple_aliasing() { + int *p; + { + int l_a[1]; + p = l_a; // NON_COMPLIANT + } +} + +void extra_test2_simple_aliasing() { + int *p; + { + int *p2 = nullptr; + int l; + + p2 = &l; // COMPLIANT + p = p2; // NON_COMPLIANT + } } \ No newline at end of file diff --git a/cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.expected b/cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.expected new file mode 100644 index 0000000000..7debcf36ab --- /dev/null +++ b/cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.expected @@ -0,0 +1,11 @@ +problems +| test.cpp:9:12:9:13 | l1 | test.cpp:6:19:6:37 | new[] | test.cpp:9:12:9:13 | l1 | Array of type DerivedClass * is deleted through a pointer of type BaseClass *. | +edges +| test.cpp:6:19:6:37 | new[] | test.cpp:9:12:9:13 | l1 | provenance | | +| test.cpp:7:22:7:40 | new[] | test.cpp:10:12:10:13 | l2 | provenance | | +nodes +| test.cpp:6:19:6:37 | new[] | semmle.label | new[] | +| test.cpp:7:22:7:40 | new[] | semmle.label | new[] | +| test.cpp:9:12:9:13 | l1 | semmle.label | l1 | +| test.cpp:10:12:10:13 | l2 | semmle.label | l2 | +subpaths diff --git a/cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.ql b/cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.ql new file mode 100644 index 0000000000..769bb3c1b5 --- /dev/null +++ b/cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.ql @@ -0,0 +1,11 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.donotdeleteanarraythroughapointeroftheincorrecttypeshared.DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared + +module TestFileConfig implements DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeSharedConfigSig { + Query getQuery() { result instanceof TestQuery } +} + +module Shared = DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared; + +import Shared::PathGraph +import Shared diff --git a/cpp/cert/test/rules/EXP51-CPP/test.cpp b/cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/test.cpp similarity index 99% rename from cpp/cert/test/rules/EXP51-CPP/test.cpp rename to cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/test.cpp index a09dd276fa..4efbc87159 100644 --- a/cpp/cert/test/rules/EXP51-CPP/test.cpp +++ b/cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/test.cpp @@ -8,4 +8,4 @@ void test() { delete[] l1; // NON_COMPLIANT - pointer to base class delete[] l2; // COMPLIANT - pointer to derived class -} \ No newline at end of file +} diff --git a/cpp/common/test/rules/possibledataracebetweenthreadsshared/PossibleDataRaceBetweenThreadsShared.expected b/cpp/common/test/rules/possibledataracebetweenthreadsshared/PossibleDataRaceBetweenThreadsShared.expected index f928076b1c..e7b797dc60 100644 --- a/cpp/common/test/rules/possibledataracebetweenthreadsshared/PossibleDataRaceBetweenThreadsShared.expected +++ b/cpp/common/test/rules/possibledataracebetweenthreadsshared/PossibleDataRaceBetweenThreadsShared.expected @@ -8,6 +8,8 @@ | test.cpp:93:3:93:6 | call to rand | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.cpp:93:3:93:6 | call to rand | rand | test.cpp:86:6:86:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.cpp:93:3:93:6 | call to rand | concurrent call to non-reentrant function | test.cpp:86:6:86:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | | test.cpp:94:3:94:11 | call to rand | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.cpp:94:3:94:11 | call to rand | rand | test.cpp:86:6:86:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.cpp:94:3:94:11 | call to rand | concurrent call to non-reentrant function | test.cpp:86:6:86:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | | test.cpp:96:3:96:8 | call to getenv | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.cpp:96:3:96:8 | call to getenv | getenv | test.cpp:86:6:86:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.cpp:96:3:96:8 | call to getenv | concurrent call to non-reentrant function | test.cpp:86:6:86:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.cpp:99:3:99:8 | call to strtok | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.cpp:99:3:99:8 | call to strtok | strtok | test.cpp:86:6:86:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.cpp:99:3:99:8 | call to strtok | concurrent call to non-reentrant function | test.cpp:86:6:86:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.cpp:100:3:100:13 | call to strtok | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.cpp:100:3:100:13 | call to strtok | strtok | test.cpp:86:6:86:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.cpp:100:3:100:13 | call to strtok | concurrent call to non-reentrant function | test.cpp:86:6:86:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | | test.cpp:101:3:101:10 | call to strerror | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.cpp:101:3:101:10 | call to strerror | strerror | test.cpp:86:6:86:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.cpp:101:3:101:10 | call to strerror | concurrent call to non-reentrant function | test.cpp:86:6:86:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | | test.cpp:102:3:102:15 | call to strerror | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.cpp:102:3:102:15 | call to strerror | strerror | test.cpp:86:6:86:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.cpp:102:3:102:15 | call to strerror | concurrent call to non-reentrant function | test.cpp:86:6:86:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | | test.cpp:103:3:103:9 | call to asctime | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.cpp:103:3:103:9 | call to asctime | asctime | test.cpp:86:6:86:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.cpp:103:3:103:9 | call to asctime | concurrent call to non-reentrant function | test.cpp:86:6:86:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | diff --git a/cpp/common/test/rules/possibledataracebetweenthreadsshared/test.cpp b/cpp/common/test/rules/possibledataracebetweenthreadsshared/test.cpp index e2943c9a1b..7dd289981f 100644 --- a/cpp/common/test/rules/possibledataracebetweenthreadsshared/test.cpp +++ b/cpp/common/test/rules/possibledataracebetweenthreadsshared/test.cpp @@ -89,15 +89,15 @@ void many_thread13_calls_nonreentrant_funcs(void *p) { // Not all are defined in std:: in our stubs. std::setlocale(LC_ALL, "C"); // NON-COMPLIANT setlocale(LC_ALL, "C"); // NON-COMPLIANT - std::tmpnam(""); // NON-COMPLIANT + std::tmpnam(nullptr); // NON-COMPLIANT rand(); // NON-COMPLIANT std::rand(); // NON-COMPLIANT // srand(0); // NON-COMPLIANT getenv("PATH"); // NON-COMPLIANT // std::getenv("PATH"); // NON-COMPLIANT ////getenv_s(NULL, NULL, 0, NULL); // NON-COMPLIANT - strtok("a", "b"); // NON-COMPLIANT[False negative] - std::strtok("a", "b"); // NON-COMPLIANT[False negative] + strtok("a", "b"); // NON-COMPLIANT + std::strtok("a", "b"); // NON-COMPLIANT strerror(0); // NON-COMPLIANT std::strerror(0); // NON-COMPLIANT asctime(NULL); // NON-COMPLIANT diff --git a/cpp/common/test/rules/readofuninitializedmemory/ReadOfUninitializedMemory.expected b/cpp/common/test/rules/readofuninitializedmemory/ReadOfUninitializedMemory.expected index 2fb2b79a0f..d350f38cf7 100644 --- a/cpp/common/test/rules/readofuninitializedmemory/ReadOfUninitializedMemory.expected +++ b/cpp/common/test/rules/readofuninitializedmemory/ReadOfUninitializedMemory.expected @@ -3,3 +3,15 @@ | test.cpp:39:7:39:8 | l3 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:38:6:38:7 | l3 | l3 | | test.cpp:86:9:86:16 | arrayPtr | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:79:8:79:15 | arrayPtr | arrayPtr | | test.cpp:93:9:93:10 | l5 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:89:7:89:8 | l5 | l5 | +| test.cpp:134:11:134:11 | i | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:133:7:133:7 | i | i | +| test.cpp:137:13:137:14 | i1 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:136:8:136:9 | i1 | i1 | +| test.cpp:141:7:141:8 | i3 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:139:8:139:9 | i3 | i3 | +| test.cpp:204:8:204:9 | p0 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:202:8:202:9 | p0 | p0 | +| test.cpp:207:4:207:5 | p1 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:206:8:206:9 | p1 | p1 | +| test.cpp:211:8:211:9 | p1 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:206:8:206:9 | p1 | p1 | +| test.cpp:217:8:217:9 | p2 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:214:8:214:9 | p2 | p2 | +| test.cpp:220:10:220:11 | p2 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:214:8:214:9 | p2 | p2 | +| test.cpp:228:7:228:8 | p4 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:226:8:226:9 | p4 | p4 | +| test.cpp:230:8:230:9 | p4 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:226:8:226:9 | p4 | p4 | +| test.cpp:233:14:233:15 | p5 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:232:8:232:9 | p5 | p5 | +| test.cpp:237:8:237:9 | p6 | Local variable $@ is read here and may not be initialized on all paths. | test.cpp:235:8:235:9 | p6 | p6 | diff --git a/cpp/common/test/rules/readofuninitializedmemory/test.cpp b/cpp/common/test/rules/readofuninitializedmemory/test.cpp index 6ed07d795f..347903296d 100644 --- a/cpp/common/test/rules/readofuninitializedmemory/test.cpp +++ b/cpp/common/test/rules/readofuninitializedmemory/test.cpp @@ -123,4 +123,119 @@ void test_non_default_init() { use(tlp); // COMPLIANT - thread local variables are zero initialized _Atomic int ai; use(ai); // COMPLIANT - atomics are special and not covered by this rule +} + +namespace { +int i; // COMPLIANT +} + +void extra_test() { + int i; + int j = i + 1; // NON_COMPLIANT + + int *i1 = new int; + int i2 = *i1; // NON_COMPLIANT + + int *i3; + + if (i3 == i1) { // NON_COMPLIANT + } +} + +void extra_conditionals(bool b) { + if (b) { + goto L; + } + int i; + i = 1; +L: + i = i + 1; // NON_COMPLIANT[FALSE_NEGATIVE] +} + +struct S { + int m1; + int m2; +}; + +void struct_test() { + S s1; + S s2 = {1}; + + auto i1 = s1.m1; // NON_COMPLIANT[FALSE_NEGATIVE] - rule currently is not + // field sensitive + auto i2 = s2.m2; // COMPLIANT + + int a1[10] = {1, 1, 1}; + int a2[10]; + + auto a3 = a1[5]; // COMPLIANT + auto a4 = a2[5]; // NON_COMPLIANT[FALSE_NEGATIVE] +} + +class C { +private: + int m1; + int m2; + +public: + C() : m1(1), m2(1) {} + + C(int a) : m1(a) {} + + int getm2() { return m2; } +}; + +void test_class() { + C c1; + if (c1.getm2() > 0) { // COMPLIANT + } + + C c2(5); + if (c2.getm2() > 0) { // NON_COMPLIANT[FALSE_NEGATIVE] - rule currently is not + // field sensitive + } +} + +void initialize(int *p) { *p = 0; } + +void extra_extra_test() { + int *p0 = new int; + use(p0); // COMPLIANT -- the pointer is valid + use(*p0); // NON_COMPLIANT -- the pointer is valid but there is no value yet + + int *p1 = new int; + *p1 = 0; // COMPLIANT[FALSE_POSITIVE] -- this is not found bc this is not an + // lvalue access + use(p1); // COMPLIANT -- the pointee of p1 has been + // initialized + use(*p1); // COMPLIANT[FALSE_POSITIVE] -- the pointee of p1 has been + // initialized + + int *p2 = new int; + p2 = new int; + use(p2); // COMPLIANT -- the pointer is valid + use(*p2); // NON_COMPLIANT -- the value may be read + + int *p3 = new int(1); + *p3 = *p2; // NON_COMPLIANT -- the pointee of p2 has not been + // initialized + use(p3); // COMPLIANT -- the pointer is valid + use(*p3); // NON_COMPLIANT[FALSE_NEGATIVE] -- the pointee of p3 has been + // overridden + + int *p4; + p4 = new int; + use(p4); // COMPLIANT[FALSE_POSITIVE] -- the pointer is valid but new int isnt + // seen + use(*p4); // NON_COMPLIANT -- the value may be read + + int *p5; + initialize(p5); // NON_COMPLIANT + + int *p6 = new int; + initialize(p6); // COMPLIANT + use(*p6); // COMPLIANT[FALSE_POSITIVE] + + int p7; + initialize(&p7); // COMPLIANT } \ No newline at end of file diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index 3a5f3b34b0..5adc6b9b6f 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards -version: 2.55.0-dev +version: 2.56.0-dev description: MISRA C++ 2023 default-suite: codeql-suites/misra-cpp-default.qls license: MIT diff --git a/cpp/misra/src/rules/RULE-11-6-2/ValueOfAnObjectMustNotBeReadBeforeItHasBeenSet.ql b/cpp/misra/src/rules/RULE-11-6-2/ValueOfAnObjectMustNotBeReadBeforeItHasBeenSet.ql new file mode 100644 index 0000000000..3b1ab81c2e --- /dev/null +++ b/cpp/misra/src/rules/RULE-11-6-2/ValueOfAnObjectMustNotBeReadBeforeItHasBeenSet.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/value-of-an-object-must-not-be-read-before-it-has-been-set + * @name RULE-11-6-2: The value of an object must not be read before it has been set + * @description Reading from uninitialized indeterminate values may produce undefined behavior. + * @kind problem + * @precision medium + * @problem.severity error + * @tags external/misra/id/rule-11-6-2 + * correctness + * security + * scope/system + * external/misra/enforcement/undecidable + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.readofuninitializedmemory.ReadOfUninitializedMemory + +class ValueOfAnObjectMustNotBeReadBeforeItHasBeenSetQuery extends ReadOfUninitializedMemorySharedQuery +{ + ValueOfAnObjectMustNotBeReadBeforeItHasBeenSetQuery() { + this = LifetimePackage::valueOfAnObjectMustNotBeReadBeforeItHasBeenSetQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-13-3-3/DeclarationsOfAFunctionSameParameterName.ql b/cpp/misra/src/rules/RULE-13-3-3/DeclarationsOfAFunctionSameParameterName.ql new file mode 100644 index 0000000000..9f96d36fcb --- /dev/null +++ b/cpp/misra/src/rules/RULE-13-3-3/DeclarationsOfAFunctionSameParameterName.ql @@ -0,0 +1,46 @@ +/** + * @id cpp/misra/declarations-of-a-function-same-parameter-name + * @name RULE-13-3-3: The parameters in all declarations or overrides of a function shall either be unnamed or have identical names + * @description Parameters in some number of declarations or overrides of a function that do not + * have identical names can lead to developer confusion. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-13-3-3 + * maintainability + * readability + * scope/system + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.types.Compatible + +predicate parameterNamesUnmatchedOverrides(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { + pragma[only_bind_into](f1).getFunction().(MemberFunction).getAnOverridingFunction+() = + pragma[only_bind_into](f2).getFunction() and + exists(string p1Name, string p2Name, int i | + p1Name = f1.getParameterDeclarationEntry(i).getName() and + p2Name = f2.getParameterDeclarationEntry(i).getName() + | + not p1Name = p2Name + ) +} + +from FunctionDeclarationEntry f1, FunctionDeclarationEntry f2, string case +where + not isExcluded(f1, Declarations1Package::declarationsOfAFunctionSameParameterNameQuery()) and + not isExcluded(f2, Declarations1Package::declarationsOfAFunctionSameParameterNameQuery()) and + not f1 = f2 and + ( + f1.getDeclaration() = f2.getDeclaration() and + parameterNamesUnmatched(f1, f2) and + case = "re-declaration" + or + parameterNamesUnmatchedOverrides(f1, f2) and + case = "override" + ) +select f1, "The parameter names of " + case + " of $@ do not use the same names as declaration $@", + f1, f1.getName(), f2, f2.getName() diff --git a/cpp/misra/src/rules/RULE-22-3-1/AssertMacroUsedWithAConstantExpression.ql b/cpp/misra/src/rules/RULE-22-3-1/AssertMacroUsedWithAConstantExpression.ql new file mode 100644 index 0000000000..90aad3517a --- /dev/null +++ b/cpp/misra/src/rules/RULE-22-3-1/AssertMacroUsedWithAConstantExpression.ql @@ -0,0 +1,30 @@ +/** + * @id cpp/misra/assert-macro-used-with-a-constant-expression + * @name RULE-22-3-1: The assert macro shall not be used with a constant-expression + * @description Compile time checking of constant expressions via static_assert is preferred to + * potentially disabled runtime checking via the assert macro. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-22-3-1 + * scope/single-translation-unit + * correctness + * maintainability + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.standardlibrary.Assert + +predicate isConstantExpression(Expr e) { exists(e.getValue()) } + +from AssertInvocation assertion, Expr assertedExpr +where + not isExcluded(assertion, Preconditions3Package::assertMacroUsedWithAConstantExpressionQuery()) and + not assertion.isAssertFalse() and + assertedExpr = assertion.getAssertCondition() and + isConstantExpression(assertedExpr) +select assertion, "Call to 'assert' macro with constant expression value $@.", assertedExpr, + assertedExpr.getValue().toString() diff --git a/cpp/misra/src/rules/RULE-4-1-3/ArrayDeletedThroughPointerOfIncorrectType.ql b/cpp/misra/src/rules/RULE-4-1-3/ArrayDeletedThroughPointerOfIncorrectType.ql new file mode 100644 index 0000000000..ac9bab4d6e --- /dev/null +++ b/cpp/misra/src/rules/RULE-4-1-3/ArrayDeletedThroughPointerOfIncorrectType.ql @@ -0,0 +1,30 @@ +/** + * @id cpp/misra/array-deleted-through-pointer-of-incorrect-type + * @name RULE-4-1-3: Array deleted through pointer of incorrect type leads to undefined behavior + * @description Deleting an array through a pointer of an incorrect type leads to undefined + * behavior. + * @kind path-problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-4-1-3 + * correctness + * scope/system + * external/misra/enforcement/undecidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.donotdeleteanarraythroughapointeroftheincorrecttypeshared.DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared + +module ArrayDeletedThroughPointerOfIncorrectTypeConfig implements + DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeSharedConfigSig +{ + Query getQuery() { result = UndefinedPackage::arrayDeletedThroughPointerOfIncorrectTypeQuery() } +} + +module Shared = + DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared; + +import Shared::PathGraph +import Shared diff --git a/cpp/misra/src/rules/RULE-6-8-3/AutomaticStorageAssignedToObjectGreaterLifetime.ql b/cpp/misra/src/rules/RULE-6-8-3/AutomaticStorageAssignedToObjectGreaterLifetime.ql new file mode 100644 index 0000000000..d1d155e5ab --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-8-3/AutomaticStorageAssignedToObjectGreaterLifetime.ql @@ -0,0 +1,26 @@ +/** + * @id cpp/misra/automatic-storage-assigned-to-object-greater-lifetime + * @name RULE-6-8-3: Do not assign the address of an object with automatic storage to an object that may persist after it's lifetime + * @description When storage durations are not compatible between assigned pointers it can lead to + * referring to objects outside of their lifetime, which is undefined behaviour. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-6-8-3 + * correctness + * security + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.donotcopyaddressofautostorageobjecttootherobject.DoNotCopyAddressOfAutoStorageObjectToOtherObject + +class AutomaticStorageAssignedToObjectGreaterLifetimeConfig extends DoNotCopyAddressOfAutoStorageObjectToOtherObjectSharedQuery +{ + AutomaticStorageAssignedToObjectGreaterLifetimeConfig() { + this = LifetimePackage::automaticStorageAssignedToObjectGreaterLifetimeQuery() + } +} diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index d396bc53bb..60f7b64289 100644 --- a/cpp/misra/test/qlpack.yml +++ b/cpp/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards-tests -version: 2.55.0-dev +version: 2.56.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/misra/test/rules/RULE-11-6-2/ValueOfAnObjectMustNotBeReadBeforeItHasBeenSet.testref b/cpp/misra/test/rules/RULE-11-6-2/ValueOfAnObjectMustNotBeReadBeforeItHasBeenSet.testref new file mode 100644 index 0000000000..e2ec5838e7 --- /dev/null +++ b/cpp/misra/test/rules/RULE-11-6-2/ValueOfAnObjectMustNotBeReadBeforeItHasBeenSet.testref @@ -0,0 +1 @@ +cpp/common/test/rules/readofuninitializedmemory/ReadOfUninitializedMemory.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-13-3-3/DeclarationsOfAFunctionSameParameterName.expected b/cpp/misra/test/rules/RULE-13-3-3/DeclarationsOfAFunctionSameParameterName.expected new file mode 100644 index 0000000000..6472ae2e99 --- /dev/null +++ b/cpp/misra/test/rules/RULE-13-3-3/DeclarationsOfAFunctionSameParameterName.expected @@ -0,0 +1,7 @@ +| functions1.cpp:5:6:5:7 | declaration of f4 | The parameter names of re-declaration of $@ do not use the same names as declaration $@ | functions1.cpp:5:6:5:7 | declaration of f4 | f4 | functions2.cpp:6:6:6:7 | declaration of f4 | f4 | +| functions1.cpp:6:6:6:7 | declaration of f5 | The parameter names of re-declaration of $@ do not use the same names as declaration $@ | functions1.cpp:6:6:6:7 | declaration of f5 | f5 | functions2.cpp:7:6:7:7 | declaration of f5 | f5 | +| functions1.cpp:8:6:8:7 | definition of f6 | The parameter names of re-declaration of $@ do not use the same names as declaration $@ | functions1.cpp:8:6:8:7 | definition of f6 | f6 | functions2.cpp:9:13:9:14 | declaration of f6 | f6 | +| functions1.cpp:21:16:21:22 | declaration of methodA | The parameter names of override of $@ do not use the same names as declaration $@ | functions1.cpp:21:16:21:22 | declaration of methodA | methodA | functions1.cpp:26:8:26:14 | declaration of methodA | methodA | +| functions2.cpp:6:6:6:7 | declaration of f4 | The parameter names of re-declaration of $@ do not use the same names as declaration $@ | functions2.cpp:6:6:6:7 | declaration of f4 | f4 | functions1.cpp:5:6:5:7 | declaration of f4 | f4 | +| functions2.cpp:7:6:7:7 | declaration of f5 | The parameter names of re-declaration of $@ do not use the same names as declaration $@ | functions2.cpp:7:6:7:7 | declaration of f5 | f5 | functions1.cpp:6:6:6:7 | declaration of f5 | f5 | +| functions2.cpp:9:13:9:14 | declaration of f6 | The parameter names of re-declaration of $@ do not use the same names as declaration $@ | functions2.cpp:9:13:9:14 | declaration of f6 | f6 | functions1.cpp:8:6:8:7 | definition of f6 | f6 | diff --git a/cpp/misra/test/rules/RULE-13-3-3/DeclarationsOfAFunctionSameParameterName.qlref b/cpp/misra/test/rules/RULE-13-3-3/DeclarationsOfAFunctionSameParameterName.qlref new file mode 100644 index 0000000000..7cb81c0bad --- /dev/null +++ b/cpp/misra/test/rules/RULE-13-3-3/DeclarationsOfAFunctionSameParameterName.qlref @@ -0,0 +1 @@ +rules/RULE-13-3-3/DeclarationsOfAFunctionSameParameterName.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-13-3-3/functions1.cpp b/cpp/misra/test/rules/RULE-13-3-3/functions1.cpp new file mode 100644 index 0000000000..758572b2d3 --- /dev/null +++ b/cpp/misra/test/rules/RULE-13-3-3/functions1.cpp @@ -0,0 +1,28 @@ +void f1(int a); // COMPLIANT -- same name +void f2(int a); // COMPLIANT -- unnamed is fine + +void f3(int a); // COMPLIANT -- diff number but for those that exist, same +void f4(int p, int b); // NON_COMPLIANT -- diff name +void f5(int b, int a); // NON_COMPLIANT -- swapped names + +void f6(int b, int a) { // NON_COMPLIANT + return; +} + +void f7(int a) { // COMPLIANT + return; +} + +template void f8(T t); // COMPLIANT +template <> +void f8(int i); // COMPLIANT - specialization is a diff declaration + +class ClassA { + virtual void methodA(int i); // NON_COMPLIANT + virtual void methodB(int i); // COMPLIANT +}; + +class ClassB : ClassA { + void methodA(int d) override; + void methodB(int i) override; +}; \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-13-3-3/functions2.cpp b/cpp/misra/test/rules/RULE-13-3-3/functions2.cpp new file mode 100644 index 0000000000..4f8a148231 --- /dev/null +++ b/cpp/misra/test/rules/RULE-13-3-3/functions2.cpp @@ -0,0 +1,11 @@ +void f1(int a); // COMPLIANT -- same name +void f2(int); // COMPLIANT -- unnamed is fine + +void f3(int a, + int b); // COMPLIANT -- diff number but for those that exist, same +void f4(int a, int b); // NON_COMPLIANT -- diff name +void f5(int a, int b); // NON_COMPLIANT -- swapped names + +extern void f6(int a, int b); // NON_COMPLIANT + +extern void f7(int); // COMPLIANT \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-13-3-3/test.cpp b/cpp/misra/test/rules/RULE-13-3-3/test.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/misra/test/rules/RULE-22-3-1/AssertMacroUsedWithAConstantExpression.expected b/cpp/misra/test/rules/RULE-22-3-1/AssertMacroUsedWithAConstantExpression.expected new file mode 100644 index 0000000000..b6a5a5002a --- /dev/null +++ b/cpp/misra/test/rules/RULE-22-3-1/AssertMacroUsedWithAConstantExpression.expected @@ -0,0 +1,14 @@ +| test.cpp:21:3:21:26 | assert(e) | Call to 'assert' macro with constant expression value $@. | test.cpp:21:10:21:25 | ... == ... | 1 | +| test.cpp:22:3:22:14 | assert(e) | Call to 'assert' macro with constant expression value $@. | test.cpp:22:10:22:13 | 1 | 1 | +| test.cpp:23:3:23:20 | assert(e) | Call to 'assert' macro with constant expression value $@. | test.cpp:23:10:23:19 | ... == ... | 1 | +| test.cpp:24:3:24:16 | assert(e) | Call to 'assert' macro with constant expression value $@. | test.cpp:24:10:24:15 | ... > ... | 1 | +| test.cpp:28:3:28:42 | assert(e) | Call to 'assert' macro with constant expression value $@. | test.cpp:28:10:28:41 | ... && ... | 1 | +| test.cpp:29:3:29:31 | assert(e) | Call to 'assert' macro with constant expression value $@. | test.cpp:29:10:29:30 | ... && ... | 1 | +| test.cpp:30:3:30:38 | assert(e) | Call to 'assert' macro with constant expression value $@. | test.cpp:30:10:30:37 | ... && ... | 1 | +| test.cpp:63:3:63:18 | assert(e) | Call to 'assert' macro with constant expression value $@. | test.cpp:63:10:63:17 | ... == ... | 1 | +| test.cpp:68:3:68:21 | assert(e) | Call to 'assert' macro with constant expression value $@. | test.cpp:68:10:68:20 | ... == ... | 1 | +| test.cpp:76:5:76:19 | assert(e) | Call to 'assert' macro with constant expression value $@. | test.cpp:76:12:76:18 | ... == ... | 1 | +| test.cpp:77:5:77:29 | assert(e) | Call to 'assert' macro with constant expression value $@. | test.cpp:77:12:77:28 | ... > ... | 1 | +| test.cpp:82:3:82:28 | assert(e) | Call to 'assert' macro with constant expression value $@. | test.cpp:82:10:82:27 | ... == ... | 1 | +| test.cpp:86:3:86:19 | assert(e) | Call to 'assert' macro with constant expression value $@. | test.cpp:86:10:86:18 | ... == ... | 1 | +| test.cpp:87:3:87:19 | assert(e) | Call to 'assert' macro with constant expression value $@. | test.cpp:87:10:87:18 | ... < ... | 1 | diff --git a/cpp/misra/test/rules/RULE-22-3-1/AssertMacroUsedWithAConstantExpression.qlref b/cpp/misra/test/rules/RULE-22-3-1/AssertMacroUsedWithAConstantExpression.qlref new file mode 100644 index 0000000000..bca61ba2d7 --- /dev/null +++ b/cpp/misra/test/rules/RULE-22-3-1/AssertMacroUsedWithAConstantExpression.qlref @@ -0,0 +1 @@ +rules/RULE-22-3-1/AssertMacroUsedWithAConstantExpression.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-22-3-1/test.cpp b/cpp/misra/test/rules/RULE-22-3-1/test.cpp new file mode 100644 index 0000000000..0b10d7c77f --- /dev/null +++ b/cpp/misra/test/rules/RULE-22-3-1/test.cpp @@ -0,0 +1,93 @@ +#include +#include + +// Test cases for MISRA C++ 2023 Rule 22.3.1 +// The assert macro shall not be used with a constant-expression + +void test_assert_with_variable_expression() { + std::int32_t l1 = 42; + assert(l1 > 0); // COMPLIANT + + std::int32_t l2 = 100; + assert(l2 < 1000); // COMPLIANT +} + +void test_assert_with_function_call() { + auto f1 = []() { return true; }; + assert(f1()); // COMPLIANT +} + +void test_assert_with_constant_expression() { + assert(sizeof(int) == 4); // NON_COMPLIANT + assert(true); // NON_COMPLIANT + assert(1 + 1 == 2); // NON_COMPLIANT + assert(42 > 0); // NON_COMPLIANT +} + +void test_assert_with_constant_expression_and_string() { + assert((sizeof(int) == 4) && "Bad size"); // NON_COMPLIANT + assert(true && "Always true"); // NON_COMPLIANT + assert((1 + 1 == 2) && "Math works"); // NON_COMPLIANT +} + +void test_assert_false_exception() { + assert(false); // COMPLIANT + assert(false && "Unexpected path"); // COMPLIANT + assert(false && "Should not reach here"); // COMPLIANT +} + +void test_assert_with_mixed_expressions() { + std::int32_t l1 = 10; + // When dynamic and constant expressions are mixed, we treat the assertion as + // compliant. + // + // Technically, some cases such as `assert(dynamic && static)` is equivalent + // to `assert(dynamic); assert(static)` and we could report them. However, + // other cases such as `assert(dynamic || static)` are *not* equivalent to any + // standalone static assertion. + // + // Distinguishing these cases correctly in all cases is non-trivial, so we do + // not report any mixed cases at this time. + // + // We do not consider the following cases to be false negatives: + assert(l1 > 0 && sizeof(int) == 8); // COMPLIANT + assert(sizeof(int) == 4 && l1 > 0); // COMPLIANT + // Because they are difficult to distinguish from the following, which are + // clearly compliant: + assert(l1 > 0 || sizeof(int) == 4); // COMPLIANT + assert(sizeof(int) == 8 || l1 > 0); // COMPLIANT +} + +void test_assert_with_template_constant() { + constexpr std::int32_t l1 = 42; + assert(l1 == 42); // NON_COMPLIANT +} + +void test_assert_with_enum_constant() { + enum { VALUE = 10 }; + assert(VALUE == 10); // NON_COMPLIANT +} + +class TestClass { +public: + static constexpr std::int32_t m1 = 5; + + void test_assert_with_static_member() { + assert(m1 == 5); // NON_COMPLIANT + assert(TestClass::m1 > 0); // NON_COMPLIANT + } +}; + +void test_assert_with_nullptr_constant() { + assert(nullptr == nullptr); // NON_COMPLIANT +} + +void test_assert_with_character_literal() { + assert('a' == 97); // NON_COMPLIANT + assert('A' < 'Z'); // NON_COMPLIANT +} + +void test_assert_with_string_literal_comparison() { + const char *l1 = "test"; + assert(l1 != nullptr); // COMPLIANT +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-4-1-3/ArrayDeletedThroughPointerOfIncorrectType.testref b/cpp/misra/test/rules/RULE-4-1-3/ArrayDeletedThroughPointerOfIncorrectType.testref new file mode 100644 index 0000000000..069f5724f8 --- /dev/null +++ b/cpp/misra/test/rules/RULE-4-1-3/ArrayDeletedThroughPointerOfIncorrectType.testref @@ -0,0 +1 @@ +cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.ql diff --git a/cpp/misra/test/rules/RULE-6-8-3/AutomaticStorageAssignedToObjectGreaterLifetime.testref b/cpp/misra/test/rules/RULE-6-8-3/AutomaticStorageAssignedToObjectGreaterLifetime.testref new file mode 100644 index 0000000000..fc0808753a --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-8-3/AutomaticStorageAssignedToObjectGreaterLifetime.testref @@ -0,0 +1 @@ +cpp/common/test/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.ql \ No newline at end of file diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index d0619b3ae8..c5f2be81fa 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/report-cpp-coding-standards -version: 2.55.0-dev +version: 2.56.0-dev license: MIT dependencies: codeql/cpp-all: 5.0.0 diff --git a/docs/user_manual.md b/docs/user_manual.md index c01c333d9b..a56f73f410 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -37,14 +37,14 @@ ## Release information -This user manual documents release `2.55.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). +This user manual documents release `2.56.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). The release page documents the release notes and contains the following artifacts part of the release: - `coding-standards-codeql-packs-2.37.0-dev.zip`: CodeQL packs that can be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `code-scanning-cpp-query-pack-2.55.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `supported_rules_list_2.55.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. -- `supported_rules_list_2.55.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. -- `user_manual_2.55.0-dev.md`: This user manual. +- `code-scanning-cpp-query-pack-2.56.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. +- `supported_rules_list_2.56.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. +- `supported_rules_list_2.56.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. +- `user_manual_2.56.0-dev.md`: This user manual. - `Source Code (zip)`: A zip archive containing the contents of https://github.com/github/codeql-coding-standards - `Source Code (tar.gz)`: A GZip compressed tar archive containing the contents of https://github.com/github/codeql-coding-standards - `checksums.txt`: A text file containing sha256 checksums for the aforementioned artifacts. @@ -671,7 +671,7 @@ This section describes known failure modes for "CodeQL Coding Standards" and des | | Out of space | Less output. Some files may be only be partially analyzed, or not analyzed at all. | Error reported on the command line. | Increase space. If it remains an issue report space consumption issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False positives | More output. Results are reported which are not violations of the guidelines. | All reported results must be reviewed. | Report false positive issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False negatives | Less output. Violations of the guidelines are not reported. | Other validation and verification processes during software development should be used to complement the analysis performed by CodeQL Coding Standards. | Report false negative issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | -| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.55.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | +| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.56.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | | | Incorrect deviation record specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation records with a reason. Ensure that all deviation records are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Incorrect deviation permit specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation permits with a reason. Ensure that all deviation permits are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Unapproved use of a deviation record | Less output. Results for guideline violations are not reported. | Validate that the deviation record use is approved by verifying the approved-by attribute of the deviation record specification. | Ensure that each raised deviation record is approved by an independent approver through an auditable process. | diff --git a/rule_packages/cpp/Declarations1.json b/rule_packages/cpp/Declarations1.json new file mode 100644 index 0000000000..2e321fdb32 --- /dev/null +++ b/rule_packages/cpp/Declarations1.json @@ -0,0 +1,26 @@ +{ + "MISRA-C++-2023": { + "RULE-13-3-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Parameters in some number of declarations or overrides of a function that do not have identical names can lead to developer confusion.", + "kind": "problem", + "name": "The parameters in all declarations or overrides of a function shall either be unnamed or have identical names", + "precision": "very-high", + "severity": "error", + "short_name": "DeclarationsOfAFunctionSameParameterName", + "tags": [ + "maintainability", + "readability", + "scope/system" + ] + } + ], + "title": "The parameters in all declarations or overrides of a function shall either be unnamed or have identical names" + } + } +} \ No newline at end of file diff --git a/rule_packages/cpp/Freed.json b/rule_packages/cpp/Freed.json index 30ab6982b2..4fd0fddb05 100644 --- a/rule_packages/cpp/Freed.json +++ b/rule_packages/cpp/Freed.json @@ -109,6 +109,7 @@ "name": "Do not delete an array through a pointer of the incorrect type", "precision": "high", "severity": "error", + "shared_implementation_short_name": "DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared", "short_name": "DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType", "tags": [ "correctness", diff --git a/rule_packages/cpp/Lifetime.json b/rule_packages/cpp/Lifetime.json new file mode 100644 index 0000000000..a69a6d8c07 --- /dev/null +++ b/rule_packages/cpp/Lifetime.json @@ -0,0 +1,56 @@ +{ + "MISRA-C++-2023": { + "RULE-11-6-2": { + "properties": { + "enforcement": "undecidable", + "obligation": "mandatory" + }, + "queries": [ + { + "description": "Reading from uninitialized indeterminate values may produce undefined behavior.", + "kind": "problem", + "name": "The value of an object must not be read before it has been set", + "precision": "medium", + "severity": "error", + "short_name": "ValueOfAnObjectMustNotBeReadBeforeItHasBeenSet", + "shared_implementation_short_name": "ReadOfUninitializedMemory", + "tags": [ + "correctness", + "security", + "scope/system" + ], + "implementation_scope": { + "description": "The rule currently does not track member initialization or arrays at all (that have been declared with array types when they have not been assigned via pointers)." + } + } + ], + "title": "The value of an object must not be read before it has been set" + }, + "RULE-6-8-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "When storage durations are not compatible between assigned pointers it can lead to referring to objects outside of their lifetime, which is undefined behaviour.", + "kind": "problem", + "name": "Do not assign the address of an object with automatic storage to an object that may persist after it's lifetime", + "precision": "very-high", + "severity": "error", + "short_name": "AutomaticStorageAssignedToObjectGreaterLifetime", + "shared_implementation_short_name": "DoNotCopyAddressOfAutoStorageObjectToOtherObject", + "tags": [ + "correctness", + "security", + "scope/single-translation-unit" + ], + "implementation_scope": { + "description": "The rule checks specifically for pointers to objects with automatic storage duration that are assigned to static storage duration variables." + } + } + ], + "title": "An assignment operator shall not assign the address of an object with automatic storage duration to an object with a greater lifetime" + } + } +} \ No newline at end of file diff --git a/rule_packages/cpp/Preconditions3.json b/rule_packages/cpp/Preconditions3.json new file mode 100644 index 0000000000..393eb98605 --- /dev/null +++ b/rule_packages/cpp/Preconditions3.json @@ -0,0 +1,26 @@ +{ + "MISRA-C++-2023": { + "RULE-22-3-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Compile time checking of constant expressions via static_assert is preferred to potentially disabled runtime checking via the assert macro.", + "kind": "problem", + "name": "The assert macro shall not be used with a constant-expression", + "precision": "very-high", + "severity": "error", + "short_name": "AssertMacroUsedWithAConstantExpression", + "tags": [ + "scope/single-translation-unit", + "correctness", + "maintainability" + ] + } + ], + "title": "The assert macro shall not be used with a constant-expression" + } + } +} \ No newline at end of file diff --git a/rule_packages/cpp/Undefined.json b/rule_packages/cpp/Undefined.json index be82bd5d77..d42960360f 100644 --- a/rule_packages/cpp/Undefined.json +++ b/rule_packages/cpp/Undefined.json @@ -20,6 +20,19 @@ "scope/system" ] }, + { + "description": "Deleting an array through a pointer of an incorrect type leads to undefined behavior.", + "kind": "path-problem", + "name": "Array deleted through pointer of incorrect type leads to undefined behavior", + "precision": "high", + "severity": "error", + "shared_implementation_short_name": "DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared", + "short_name": "ArrayDeletedThroughPointerOfIncorrectType", + "tags": [ + "correctness", + "scope/system" + ] + }, { "description": "Signed integer overflow or underflow from arithmetic operations results in critical unspecified behavior.", "kind": "problem", diff --git a/rules.csv b/rules.csv index 6f2f204789..172087714d 100644 --- a/rules.csv +++ b/rules.csv @@ -925,7 +925,7 @@ cpp,MISRA-C++-2023,RULE-10-4-1,Yes,Required,Decidable,Single Translation Unit,Th cpp,MISRA-C++-2023,RULE-11-3-1,Yes,Advisory,Decidable,Single Translation Unit,Variables of array type should not be declared,,Declarations2,Easy, cpp,MISRA-C++-2023,RULE-11-3-2,Yes,Advisory,Decidable,Single Translation Unit,The declaration of an object should contain no more than two levels of pointer indirection,A5-0-3,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-11-6-1,Yes,Advisory,Decidable,Single Translation Unit,All variables should be initialized,,Declarations2,Easy, -cpp,MISRA-C++-2023,RULE-11-6-2,Yes,Mandatory,Undecidable,System,The value of an object must not be read before it has been set,A8-5-0,Lifetime,Very Hard, +cpp,MISRA-C++-2023,RULE-11-6-2,Yes,Mandatory,Undecidable,System,The value of an object must not be read before it has been set,A8-5-0,Lifetime,Import cpp,MISRA-C++-2023,RULE-11-6-3,Yes,Required,Decidable,Single Translation Unit,"Within an enumerator list, the value of an implicitly-specified enumeration constant shall be unique",RULE-8-12,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-12-2-1,Yes,Advisory,Decidable,Single Translation Unit,Bit-fields should not be declared,A9-6-2,Banned,Easy, cpp,MISRA-C++-2023,RULE-12-2-2,Yes,Required,Decidable,Single Translation Unit,A bit-field shall have an appropriate type,RULE-6-1,ImportMisra23,Import, @@ -935,7 +935,7 @@ cpp,MISRA-C++-2023,RULE-13-1-1,Yes,Advisory,Decidable,Single Translation Unit,Cl cpp,MISRA-C++-2023,RULE-13-1-2,Yes,Required,Decidable,Single Translation Unit,An accessible base class shall not be both virtual and non-virtual in the same hierarchy,M10-1-3,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-13-3-1,Yes,Required,Decidable,Single Translation Unit,"User-declared member functions shall use the virtual, override and final specifiers appropriately",,Classes2,Easy, cpp,MISRA-C++-2023,RULE-13-3-2,Yes,Required,Decidable,Single Translation Unit,Parameters in an overriding virtual function shall not specify different default arguments,M8-3-1,ImportMisra23,Import, -cpp,MISRA-C++-2023,RULE-13-3-3,Yes,Required,Decidable,System,The parameters in all declarations or overrides of a function shall either be unnamed or have identical names,RULE-8-3,Declarations2,Easy, +cpp,MISRA-C++-2023,RULE-13-3-3,Yes,Required,Decidable,System,The parameters in all declarations or overrides of a function shall either be unnamed or have identical names,RULE-8-3,Declarations1,Easy, cpp,MISRA-C++-2023,RULE-13-3-4,Yes,Required,Decidable,Single Translation Unit,A comparison of a potentially virtual pointer to member function shall only be with nullptr,A5-10-1,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-14-1-1,Yes,Advisory,Decidable,Single Translation Unit,Non-static data members should be either all private or all public,,Classes2,Easy, cpp,MISRA-C++-2023,RULE-15-0-1,Yes,Required,Decidable,Single Translation Unit,Special member functions shall be provided appropriately,A12-0-1,Classes3,Medium, @@ -986,7 +986,7 @@ cpp,MISRA-C++-2023,RULE-21-6-5,Yes,Required,Decidable,Single Translation Unit,A cpp,MISRA-C++-2023,RULE-21-10-1,Yes,Required,Decidable,Single Translation Unit,The features of shall not be used,DCL50-CPP,BannedAPIs,Easy, cpp,MISRA-C++-2023,RULE-21-10-2,Yes,Required,Decidable,Single Translation Unit,The standard header file shall not be used,ERR52-CPP,BannedAPIs,Easy, cpp,MISRA-C++-2023,RULE-21-10-3,Yes,Required,Decidable,Single Translation Unit,The facilities provided by the standard header file shall not be used,M18-7-1,ImportMisra23,Import, -cpp,MISRA-C++-2023,RULE-22-3-1,Yes,Required,Decidable,Single Translation Unit,The assert macro shall not be used with a constant-expression,,Preconditions,Easy, +cpp,MISRA-C++-2023,RULE-22-3-1,Yes,Required,Decidable,Single Translation Unit,The assert macro shall not be used with a constant-expression,,Preconditions3,Easy, cpp,MISRA-C++-2023,RULE-22-4-1,Yes,Required,Decidable,Single Translation Unit,The literal value zero shall be the only value assigned to errno,,Preconditions4,Easy, cpp,MISRA-C++-2023,RULE-23-11-1,Yes,Advisory,Decidable,Single Translation Unit,The raw pointer constructors of std::shared_ptr and std::unique_ptr should not be used,,BannedAPIs,Easy, cpp,MISRA-C++-2023,RULE-24-5-1,Yes,Required,Decidable,Single Translation Unit,The character handling functions from and shall not be used,,BannedAPIs,Easy,