diff --git a/.github/actions/check-permissions/action.yml b/.github/actions/check-permissions/action.yml new file mode 100644 index 0000000000..b47466d080 --- /dev/null +++ b/.github/actions/check-permissions/action.yml @@ -0,0 +1,49 @@ +name: Check current actor permissions +description: | + Checks whether the current actor has the specified permssions +inputs: + minimum-permission: + description: | + The minimum required permission. One of: read, write, admin + required: true +outputs: + has-permission: + description: "Whether the actor had the minimum required permission" + value: ${{ steps.check-permission.outputs.has-permission }} + +runs: + using: composite + steps: + - uses: actions/github-script@v7 + id: check-permission + env: + INPUT_MINIMUM-PERMISSION: ${{ inputs.minimum-permission }} + with: + script: | + // Valid permissions are none, read, write, admin (legacy base permissions) + const permissionsRanking = ["none", "read", "write", "admin"]; + + // Note: core.getInput doesn't work by default in a composite action - in this case + // it would try to fetch the input to the github-script instead of the action + // itself. Instead, we set the appropriate magic env var with the actions input. + // See: https://github.com/actions/runner/issues/665 + const minimumPermission = core.getInput('minimum-permission'); + if (!permissionsRanking.includes(minimumPermission)) { + core.setFailed(`Invalid minimum permission: ${minimumPermission}`); + return; + } + + const { data : { permission : actorPermission } } = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: context.repo.owner, + repo: context.repo.repo, + username: context.actor + }); + + // Confirm whether the actor permission is at least the selected permission + const hasPermission = permissionsRanking.indexOf(minimumPermission) <= permissionsRanking.indexOf(actorPermission) ? "1" : ""; + core.setOutput('has-permission', hasPermission); + if (!hasPermission) { + core.info(`Current actor (${context.actor}) does not have the minimum required permission '${minimumPermission}' (has '${actorPermission}')`); + } else { + core.info(`Current actor (${context.actor}) has the minimum required permission '${minimumPermission}' (has '${actorPermission}')`); + } diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..73f11c1f47 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 +updates: + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates to GitHub Actions every week + interval: "weekly" \ No newline at end of file diff --git a/.github/workflows/code-scanning-pack-gen.yml b/.github/workflows/code-scanning-pack-gen.yml index 1fd57cf755..dde0a1a3f6 100644 --- a/.github/workflows/code-scanning-pack-gen.yml +++ b/.github/workflows/code-scanning-pack-gen.yml @@ -8,7 +8,6 @@ on: - main - next - "rc/**" - push: branches: - main @@ -27,7 +26,7 @@ jobs: matrix: ${{ steps.export-code-scanning-pack-matrix.outputs.matrix }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Export Code Scanning pack matrix id: export-code-scanning-pack-matrix run: | @@ -43,11 +42,11 @@ jobs: fail-fast: false matrix: ${{ fromJSON(needs.prepare-code-scanning-pack-matrix.outputs.matrix) }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Cache CodeQL id: cache-codeql - uses: actions/cache@v2.1.3 + uses: actions/cache@v4 with: path: ${{ github.workspace }}/codeql_home key: codeql-home-${{ matrix.os }}-${{ matrix.codeql_cli }}-${{ matrix.codeql_standard_library }} @@ -69,17 +68,21 @@ jobs: - name: Determine ref for external help files id: determine-ref run: | - if [[ $GITHUB_EVENT_NAME == "pull_request" || $GITHUB_EVENT_NAME == "merge_group" ]]; then - echo "EXTERNAL_HELP_REF=$GITHUB_HEAD_REF" >> "$GITHUB_ENV" + if [[ $GITHUB_EVENT_NAME == "pull_request" ]]; then + EXTERNAL_HELP_REF="${{ github.event.pull_request.base.ref }}" + elif [[ $GITHUB_EVENT_NAME == "merge_group" ]]; then + EXTERNAL_HELP_REF="${{ github.event.merge_group.base_ref }}" else - echo "EXTERNAL_HELP_REF=$GITHUB_REF" >> "$GITHUB_ENV" + EXTERNAL_HELP_REF="$GITHUB_REF" fi + echo "EXTERNAL_HELP_REF=$EXTERNAL_HELP_REF" >> "$GITHUB_ENV" echo "Using ref $EXTERNAL_HELP_REF for external help files." - name: Checkout external help files - continue-on-error: true id: checkout-external-help-files - uses: actions/checkout@v4 + # 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 with: ssh-key: ${{ secrets.CODEQL_CODING_STANDARDS_HELP_KEY }} repository: "github/codeql-coding-standards-help" @@ -87,7 +90,7 @@ jobs: path: external-help-files - name: Include external help files - if: steps.checkout-external-help-files.outcome == 'success' + if: ${{ !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]'&& steps.checkout-external-help-files.outcome == 'success' }} run: | pushd external-help-files find . -name '*.md' -exec rsync -av --relative {} "$GITHUB_WORKSPACE" \; @@ -98,15 +101,36 @@ jobs: CODEQL_HOME: ${{ github.workspace }}/codeql_home run: | PATH=$PATH:$CODEQL_HOME/codeql - - codeql query compile --precompile --threads 0 cpp - codeql query compile --precompile --threads 0 c + # Precompile all queries, and use a compilation cache larger than default + # to ensure we cache all the queries for later steps + codeql query compile --precompile --threads 0 --compilation-cache-size=1024 cpp c cd .. - zip -r codeql-coding-standards/code-scanning-cpp-query-pack.zip codeql-coding-standards/c/ codeql-coding-standards/cpp/ codeql-coding-standards/.codeqlmanifest.json codeql-coding-standards/supported_codeql_configs.json codeql-coding-standards/scripts/configuration codeql-coding-standards/scripts/reports codeql-coding-standards/scripts/shared codeql-coding-standards/scripts/guideline_recategorization codeql-coding-standards/scripts/shared codeql-coding-standards/scripts/schemas + zip -r codeql-coding-standards/code-scanning-cpp-query-pack.zip codeql-coding-standards/c/ codeql-coding-standards/cpp/ codeql-coding-standards/.codeqlmanifest.json codeql-coding-standards/supported_codeql_configs.json codeql-coding-standards/scripts/configuration codeql-coding-standards/scripts/reports codeql-coding-standards/scripts/shared codeql-coding-standards/scripts/guideline_recategorization codeql-coding-standards/schemas - name: Upload GHAS Query Pack - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: code-scanning-cpp-query-pack.zip path: code-scanning-cpp-query-pack.zip + + - name: Create qlpack bundles + env: + CODEQL_HOME: ${{ github.workspace }}/codeql_home + run: | + PATH=$PATH:$CODEQL_HOME/codeql + + codeql pack bundle --output=common-cpp-coding-standards.tgz cpp/common/src + codeql pack bundle --output=common-c-coding-standards.tgz c/common/src + codeql pack bundle --output=misra-c-coding-standards.tgz c/misra/src + codeql pack bundle --output=cert-c-coding-standards.tgz c/cert/src + codeql pack bundle --output=cert-cpp-coding-standards.tgz cpp/cert/src + codeql pack bundle --output=autosar-cpp-coding-standards.tgz cpp/autosar/src + codeql pack bundle --output=misra-cpp-coding-standards.tgz cpp/misra/src + codeql pack bundle --output=report-coding-standards.tgz cpp/report/src + + - name: Upload qlpack bundles + uses: actions/upload-artifact@v4 + with: + name: coding-standards-codeql-packs + path: '*-coding-standards.tgz' \ No newline at end of file diff --git a/.github/workflows/codeql_unit_tests.yml b/.github/workflows/codeql_unit_tests.yml index 62660d973d..0f9aadb8b3 100644 --- a/.github/workflows/codeql_unit_tests.yml +++ b/.github/workflows/codeql_unit_tests.yml @@ -23,7 +23,7 @@ jobs: matrix: ${{ steps.export-unit-test-matrix.outputs.matrix }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Export unit test matrix id: export-unit-test-matrix @@ -45,10 +45,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.9" @@ -57,7 +57,7 @@ jobs: - name: Cache CodeQL id: cache-codeql - uses: actions/cache@v3 + uses: actions/cache@v4 with: # A list of files, directories, and wildcard patterns to cache and restore path: ${{github.workspace}}/codeql_home @@ -151,7 +151,7 @@ jobs: file.close() - name: Upload test results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ matrix.language }}-test-results-${{ runner.os }}-${{ matrix.codeql_cli }}-${{ matrix.codeql_standard_library_ident }} path: | @@ -160,11 +160,18 @@ jobs: validate-test-results: name: Validate test results + if: ${{ always() }} needs: run-test-suites runs-on: ubuntu-22.04 steps: + - name: Check if run-test-suites job failed to complete, if so fail + if: ${{ needs.run-test-suites.result == 'failure' }} + uses: actions/github-script@v7 + with: + script: | + core.setFailed('Test run job failed') - name: Collect test results - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 - name: Validate test results run: | diff --git a/.github/workflows/dispatch-matrix-check.yml b/.github/workflows/dispatch-matrix-check.yml deleted file mode 100644 index 350f2fb73f..0000000000 --- a/.github/workflows/dispatch-matrix-check.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: 🤖 Run Matrix Check - -on: - pull_request_target: - types: [synchronize,opened] - branches: - - "matrix/**" - workflow_dispatch: - -jobs: - dispatch-matrix-check: - runs-on: ubuntu-22.04 - steps: - - - name: Test Variables - shell: pwsh - run: | - Write-Host "Running as: ${{github.actor}}" - - - name: Dispatch Matrix Testing Job - if: ${{ contains(fromJSON('["jsinglet", "mbaluda", "lcartey", "rvermeulen", "ravikprasad", "jeongsoolee09", "hohn", "knewbury01", "kraiouchkine"]'), github.actor) }} - uses: peter-evans/repository-dispatch@v2 - with: - token: ${{ secrets.RELEASE_ENGINEERING_TOKEN }} - repository: github/codeql-coding-standards-release-engineering - event-type: matrix-test - client-payload: '{"pr": "${{ github.event.number }}"}' - - - - uses: actions/github-script@v6 - if: ${{ contains(fromJSON('["jsinglet", "mbaluda", "lcartey", "rvermeulen", "ravikprasad", "jeongsoolee09", "hohn", "knewbury01", "kraiouchkine"]'), github.actor) }} - with: - script: | - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: '🤖 Beep Boop! Matrix Testing for this PR has been initiated. Please check back later for results.

:bulb: If you do not hear back from me please check my status! **I will report even if this PR does not contain files eligible for matrix testing.**' - }) \ No newline at end of file diff --git a/.github/workflows/dispatch-matrix-test-on-comment.yml b/.github/workflows/dispatch-matrix-test-on-comment.yml index bef0ba7232..4990694512 100644 --- a/.github/workflows/dispatch-matrix-test-on-comment.yml +++ b/.github/workflows/dispatch-matrix-test-on-comment.yml @@ -3,42 +3,45 @@ name: 🤖 Run Matrix Check (On Comment) on: issue_comment: types: [created] - branches: - - main - - "rc/**" - - next - jobs: dispatch-matrix-check: runs-on: ubuntu-22.04 steps: + - name: Checkout repository + uses: actions/checkout@v5 - - name: Test Variables - shell: pwsh - run: | - Write-Host "Running as: ${{github.actor}}" - - $actor = "${{github.actor}}" - - $acl = @("jsinglet","mbaluda", "lcartey", "rvermeulen", "ravikprasad", "jeongsoolee09", "hohn", "knewbury01", "kraiouchkine") - - if(-not ($actor -in $acl)){ - throw "Refusing to run workflow for user not in acl." - } - - - - name: Dispatch Matrix Testing Job - if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, '/test-matrix') }} - uses: peter-evans/repository-dispatch@v2 + - name: Check permission + id: check-write-permission + uses: ./.github/actions/check-permissions with: - token: ${{ secrets.RELEASE_ENGINEERING_TOKEN }} - repository: github/codeql-coding-standards-release-engineering - event-type: matrix-test - client-payload: '{"pr": "${{ github.event.issue.number }}"}' + minimum-permission: "write" - - uses: actions/github-script@v6 - if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, '/test-matrix') }} + - name: Generate token + id: generate-token + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ vars.AUTOMATION_APP_ID }} + private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} + owner: ${{ github.repository_owner }} + repositories: "codeql-coding-standards-release-engineering" + + - name: Invoke matrix testing job + if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, '/test-matrix') && steps.check-write-permission.outputs.has-permission }} + env: + ISSUE_NR: ${{ github.event.issue.number }} + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + run: | + jq -n \ + --arg issue_nr "$ISSUE_NR" \ + '{"issue-nr": $issue_nr}' \ + | \ + gh workflow run pr-compiler-validation.yml \ + --json \ + -R github/codeql-coding-standards-release-engineering + + - uses: actions/github-script@v7 + if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, '/test-matrix') && steps.check-write-permission.outputs.has-permission }} with: script: | github.rest.issues.createComment({ diff --git a/.github/workflows/dispatch-release-performance-check.yml b/.github/workflows/dispatch-release-performance-check.yml index 0858527721..25e293fa6a 100644 --- a/.github/workflows/dispatch-release-performance-check.yml +++ b/.github/workflows/dispatch-release-performance-check.yml @@ -3,41 +3,45 @@ name: 🏁 Run Release Performance Check on: issue_comment: types: [created] - branches: - - main - - "rc/**" - - next jobs: dispatch-matrix-check: runs-on: ubuntu-22.04 steps: + - name: Checkout repository + uses: actions/checkout@v5 - - name: Test Variables - shell: pwsh - run: | - Write-Host "Running as: ${{github.actor}}" - - $actor = "${{github.actor}}" - - $acl = @("jsinglet","mbaluda", "lcartey", "rvermeulen", "ravikprasad", "jeongsoolee09", "hohn", "knewbury01", "kraiouchkine") - - if(-not ($actor -in $acl)){ - throw "Refusing to run workflow for user not in acl." - } - - - name: Dispatch Performance Testing Job - if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, '/test-performance') }} - uses: peter-evans/repository-dispatch@v2 + - name: Check permission + id: check-write-permission + uses: ./.github/actions/check-permissions with: - token: ${{ secrets.RELEASE_ENGINEERING_TOKEN }} - repository: github/codeql-coding-standards-release-engineering - event-type: performance-test - client-payload: '{"pr": "${{ github.event.issue.number }}"}' - + minimum-permission: "write" - - uses: actions/github-script@v6 - if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, '/test-performance') }} + - name: Generate token + id: generate-token + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ vars.AUTOMATION_APP_ID }} + private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} + owner: ${{ github.repository_owner }} + repositories: "codeql-coding-standards-release-engineering" + + - name: Invoke performance test + if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, '/test-performance') && steps.check-write-permission.outputs.has-permission }} + env: + ISSUE_NR: ${{ github.event.issue.number }} + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + run: | + jq -n \ + --arg issue_nr "$ISSUE_NR" \ + '{"issue-nr": $issue_nr}' \ + | \ + gh workflow run pr-performance-testing.yml \ + --json \ + -R github/codeql-coding-standards-release-engineering + + - uses: actions/github-script@v7 + if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, '/test-performance') && steps.check-write-permission.outputs.has-permission }} with: script: | github.rest.issues.createComment({ @@ -45,4 +49,4 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, body: '🏁 Beep Boop! Performance testing for this PR has been initiated. Please check back later for results. Note that the query package generation step must complete before testing will start so it might be a minute.

:bulb: If you do not hear back from me please check my status! **I will report even if I fail!**' - }) \ No newline at end of file + }) diff --git a/.github/workflows/extra-rule-validation.yml b/.github/workflows/extra-rule-validation.yml index a18f47c65d..7fef7818aa 100644 --- a/.github/workflows/extra-rule-validation.yml +++ b/.github/workflows/extra-rule-validation.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v5 - name: Check Rules shell: pwsh @@ -33,7 +33,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v5 - name: Ensure CPP Shared Rules Have Valid Structure shell: pwsh @@ -44,13 +44,13 @@ jobs: run: scripts/util/Test-SharedImplementationsHaveTestCases.ps1 -Language c -CIMode - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 if: failure() with: name: missing-test-report.csv path: MissingTestReport*.csv - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 if: failure() with: name: test-report.csv diff --git a/.github/workflows/finalize-release.yml b/.github/workflows/finalize-release.yml index d3f511caba..c6ebc8f3dc 100644 --- a/.github/workflows/finalize-release.yml +++ b/.github/workflows/finalize-release.yml @@ -39,20 +39,20 @@ jobs: fi - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ env.REF }} fetch-depth: 0 path: release - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ env.TOOL_REF }} path: tooling - name: Install Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.9" @@ -103,7 +103,7 @@ jobs: - name: Generate token if: env.HOTFIX_RELEASE == 'false' id: generate-token - uses: actions/create-github-app-token@eaddb9eb7e4226c68cf4b39f167c83e5bd132b3e + uses: actions/create-github-app-token@v2 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 f8e3d6d30c..a28bfd7905 100644 --- a/.github/workflows/generate-html-docs.yml +++ b/.github/workflows/generate-html-docs.yml @@ -20,10 +20,10 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v5 - name: Install Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.9" @@ -35,7 +35,7 @@ jobs: python scripts/documentation/generate_iso26262_docs.py coding-standards-html-docs - name: Upload HTML documentation - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: coding-standards-docs-${{ github.sha }} path: coding-standards-html-docs/ diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index 9bbd27ce26..a789c8450d 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -34,12 +34,12 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v5 with: ref: ${{ inputs.ref }} - name: Install Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.9" @@ -143,7 +143,7 @@ jobs: - name: Generate token id: generate-token - uses: actions/create-github-app-token@eaddb9eb7e4226c68cf4b39f167c83e5bd132b3e + uses: actions/create-github-app-token@v2 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 aac2fd1e0e..277082d3a5 100644 --- a/.github/workflows/standard_library_upgrade_tests.yml +++ b/.github/workflows/standard_library_upgrade_tests.yml @@ -19,7 +19,7 @@ jobs: matrix: ${{ steps.export-unit-test-matrix.outputs.matrix }} steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v5 - name: Export unit test matrix id: export-unit-test-matrix @@ -41,16 +41,16 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v5 - name: Setup Python 3 - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: "3.x" - name: Cache CodeQL id: cache-codeql - uses: actions/cache@v2.1.3 + uses: actions/cache@v4 with: # A list of files, directories, and wildcard patterns to cache and restore path: ${{github.workspace}}/codeql_home @@ -143,7 +143,7 @@ jobs: }, test_summary_file) - name: Upload test results - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: test-results-${{runner.os}}-${{matrix.codeql_cli}}-${{matrix.codeql_standard_library_ident}} path: | @@ -157,12 +157,12 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Install Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.9" - name: Collect test results - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 - name: Validate test results shell: python diff --git a/.github/workflows/tooling-unit-tests.yml b/.github/workflows/tooling-unit-tests.yml index 490d399e8b..00a36d5c6a 100644 --- a/.github/workflows/tooling-unit-tests.yml +++ b/.github/workflows/tooling-unit-tests.yml @@ -22,7 +22,7 @@ jobs: matrix: ${{ steps.export-supported-codeql-env-matrix.outputs.matrix }} steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v5 - name: Export supported CodeQL environment matrix id: export-supported-codeql-env-matrix @@ -40,10 +40,10 @@ jobs: matrix: ${{ fromJSON(needs.prepare-supported-codeql-env-matrix.outputs.matrix) }} steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v5 - name: Install Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.9" @@ -52,7 +52,7 @@ jobs: - name: Cache CodeQL id: cache-codeql - uses: actions/cache@v2.1.3 + uses: actions/cache@v4 with: path: ${{ github.workspace }}/codeql_home key: codeql-home-${{ matrix.os }}-${{ matrix.codeql_cli }}-${{ matrix.codeql_standard_library }} @@ -83,10 +83,10 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v5 - name: Install Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.9" @@ -102,10 +102,10 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v5 - name: Install Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.9" diff --git a/.github/workflows/update-release-status.yml b/.github/workflows/update-release-status.yml index 874bc4d0b2..50df8d8c00 100644 --- a/.github/workflows/update-release-status.yml +++ b/.github/workflows/update-release-status.yml @@ -24,7 +24,7 @@ jobs: conclusion: ${{ steps.set-output.outputs.conclusion }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ inputs.head-sha }} diff --git a/.github/workflows/update-release.yml b/.github/workflows/update-release.yml index 21838c1d9f..6baf99279b 100644 --- a/.github/workflows/update-release.yml +++ b/.github/workflows/update-release.yml @@ -28,13 +28,13 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 # We need the full history to compute the changelog ref: ${{ inputs.head-sha }} - name: Install Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.9" @@ -43,7 +43,7 @@ jobs: - name: Generate token id: generate-token - uses: actions/create-github-app-token@eaddb9eb7e4226c68cf4b39f167c83e5bd132b3e + uses: actions/create-github-app-token@v2 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 73721d5581..de187e0e95 100644 --- a/.github/workflows/upgrade_codeql_dependencies.yml +++ b/.github/workflows/upgrade_codeql_dependencies.yml @@ -18,10 +18,20 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v5 + + - name: Fetch CodeQL + env: + GITHUB_TOKEN: ${{ github.token }} + RUNNER_TEMP: ${{ runner.temp }} + run: | + cd $RUNNER_TEMP + gh release download "v${CODEQL_CLI_VERSION}" --repo https://github.com/github/codeql-cli-binaries --pattern codeql-linux64.zip + unzip -q codeql-linux64.zip + echo "$RUNNER_TEMP/codeql/" >> $GITHUB_PATH - name: Install Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.9" @@ -35,27 +45,27 @@ jobs: run: | python3 scripts/upgrade-codeql-dependencies/upgrade-codeql-dependencies.py --cli-version "$CODEQL_CLI_VERSION" - - name: Fetch CodeQL - env: - GITHUB_TOKEN: ${{ github.token }} - RUNNER_TEMP: ${{ runner.temp }} - run: | - cd $RUNNER_TEMP - gh release download "v${CODEQL_CLI_VERSION}" --repo https://github.com/github/codeql-cli-binaries --pattern codeql-linux64.zip - unzip -q codeql-linux64.zip - - name: Update CodeQL formatting based on new CLI version env: RUNNER_TEMP: ${{ runner.temp }} run: | - find cpp \( -name '*.ql' -or -name '*.qll' \) -print0 | xargs -0 --max-procs "$XARGS_MAX_PROCS" $RUNNER_TEMP/codeql/codeql query format --in-place - find c \( -name '*.ql' -or -name '*.qll' \) -print0 | xargs -0 --max-procs "$XARGS_MAX_PROCS" $RUNNER_TEMP/codeql/codeql query format --in-place + find cpp \( -name '*.ql' -or -name '*.qll' \) -print0 | xargs -0 --max-procs "$XARGS_MAX_PROCS" codeql query format --in-place + find c \( -name '*.ql' -or -name '*.qll' \) -print0 | xargs -0 --max-procs "$XARGS_MAX_PROCS" codeql query format --in-place - name: Create Pull Request - uses: peter-evans/create-pull-request@v3 + uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 with: - title: "Upgrading `github/codeql` dependency to ${{ github.event.inputs.codeql_cli_version }}" - body: "This PR upgrades the CodeQL CLI version to ${{ github.event.inputs.codeql_cli_version }}." + title: "Upgrade `github/codeql` dependency to ${{ github.event.inputs.codeql_cli_version }}" + body: | + This PR upgrades the CodeQL CLI version to ${{ github.event.inputs.codeql_cli_version }}. + + ## CodeQL dependency upgrade checklist: + + - [ ] Confirm the code has been correctly reformatted according to the new CodeQL CLI. + - [ ] Identify any CodeQL compiler warnings and errors, and update queries as required. + - [ ] Validate that the `github/codeql` test cases succeed. + - [ ] Address any CodeQL test failures in the `github/codeql-coding-standards` repository. + - [ ] Validate performance vs pre-upgrade, using /test-performance commit-message: "Upgrading `github/codeql` dependency to ${{ github.event.inputs.codeql_cli_version }}" delete-branch: true branch: "codeql/upgrade-to-${{ github.event.inputs.codeql_cli_version }}" diff --git a/.github/workflows/validate-package-files.yml b/.github/workflows/validate-package-files.yml index 0573b00590..4e0a51a3b5 100644 --- a/.github/workflows/validate-package-files.yml +++ b/.github/workflows/validate-package-files.yml @@ -16,12 +16,12 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v5 with: ref: ${{ inputs.ref }} - name: Install Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.9" @@ -56,4 +56,10 @@ jobs: find rule_packages/$LANGUAGE -name \*.json -exec basename {} .json \; | xargs python scripts/generate_rules/generate_package_files.py $LANGUAGE git diff git diff --compact-summary - git diff --quiet \ No newline at end of file + git diff --quiet + + - name: Validate Amendments + env: + LANGUAGE: ${{ matrix.language }} + run: | + python scripts/validate-amendments-csv.py $LANGUAGE \ No newline at end of file diff --git a/.github/workflows/validate-query-formatting.yml b/.github/workflows/validate-query-formatting.yml index e4c6871ad5..ed78505298 100644 --- a/.github/workflows/validate-query-formatting.yml +++ b/.github/workflows/validate-query-formatting.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v5 with: ref: ${{ inputs.ref }} diff --git a/.github/workflows/validate-query-help.yml b/.github/workflows/validate-query-help.yml index d99144fc7f..3ce97d8e9f 100644 --- a/.github/workflows/validate-query-help.yml +++ b/.github/workflows/validate-query-help.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v5 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 7b95484376..1777cacdd9 100644 --- a/.github/workflows/validate-query-test-case-formatting.yml +++ b/.github/workflows/validate-query-test-case-formatting.yml @@ -20,7 +20,7 @@ jobs: fail-fast: false steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v5 with: ref: ${{ inputs.ref }} diff --git a/.github/workflows/validate-release.yml b/.github/workflows/validate-release.yml index 5f5382f5dd..cd7d27f6fa 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@eaddb9eb7e4226c68cf4b39f167c83e5bd132b3e + uses: actions/create-github-app-token@v2 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@eaddb9eb7e4226c68cf4b39f167c83e5bd132b3e + uses: actions/create-github-app-token@v2 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 cd5d35248d..4900f11172 100644 --- a/.github/workflows/verify-standard-library-dependencies.yml +++ b/.github/workflows/verify-standard-library-dependencies.yml @@ -22,7 +22,7 @@ jobs: matrix: ${{ steps.export-matrix.outputs.matrix }} steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v5 - name: Export unit test matrix id: export-matrix @@ -44,16 +44,16 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v5 - name: Setup Python 3 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.9" - name: Cache CodeQL id: cache-codeql - uses: actions/cache@v2.1.3 + uses: actions/cache@v4 with: # A list of files, directories, and wildcard patterns to cache and restore path: ${{github.workspace}}/codeql_home diff --git a/README.md b/README.md index d1de9b6372..02c226f84a 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,15 @@ The following coding standards are supported: - [MISRA C 2012, 3rd Edition, 1st revision](https://www.misra.org.uk/product/misra-c2012-third-edition-first-revision/) (incoporating Amendment 1 & Technical Corrigendum 1). In addition, we support the following additional amendments and technical corrigendums: - [MISRA C 2012 Amendment 2](https://misra.org.uk/app/uploads/2021/06/MISRA-C-2012-AMD2.pdf) - [MISRA C 2012 Technical Corrigendum 2](https://misra.org.uk/app/uploads/2022/04/MISRA-C-2012-TC2.pdf) + - [MISRA C 2012 Amendment 3](https://misra.org.uk/app/uploads/2021/06/MISRA-C-2012-AMD3.pdf) + - [MISRA C 2012 Amendment 4](https://misra.org.uk/app/uploads/2021/06/MISRA-C-2012-AMD4.pdf) +- [MISRA C 2023](https://misra.org.uk/product/misra-c2023/) ## :construction: Standards under development :construction: -- [MISRA C++ 2023](https://misra.org.uk/product/misra-cpp2023/) - under development _scheduled for release 2024 Q4_. +The following standards are under active development for [C++17](https://www.iso.org/standard/68564.html): + +- [MISRA C++ 2023](https://misra.org.uk/product/misra-cpp2023/) - under development - _scheduled for release 2025 Q2/Q3_ ## How do I use the CodeQL Coding Standards Queries? diff --git a/amendments.csv b/amendments.csv new file mode 100644 index 0000000000..7bcc65327c --- /dev/null +++ b/amendments.csv @@ -0,0 +1,49 @@ +language,standard,amendment,rule_id,supportable,implementation_category,implemented,difficulty +c,MISRA-C-2012,Amendment3,DIR-4-6,Yes,Expand,Yes,Easy +c,MISRA-C-2012,Amendment3,DIR-4-9,Yes,Refine,Yes,Easy +c,MISRA-C-2012,Amendment3,DIR-4-11,Yes,Refine,Yes,Import +c,MISRA-C-2012,Amendment3,RULE-1-4,Yes,Replace,Yes,Easy +c,MISRA-C-2012,Amendment3,RULE-10-1,Yes,Replace,Yes,Easy +c,MISRA-C-2012,Amendment3,RULE-10-3,Yes,Refine,Yes,Easy +c,MISRA-C-2012,Amendment3,RULE-10-4,Yes,Refine,Yes,Import +c,MISRA-C-2012,Amendment3,RULE-10-5,Yes,Expand,Yes,Easy +c,MISRA-C-2012,Amendment3,RULE-10-7,Yes,Refine,Yes,Import +c,MISRA-C-2012,Amendment3,RULE-10-8,Yes,Refine,Yes,Import +c,MISRA-C-2012,Amendment3,RULE-21-11,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Amendment3,RULE-21-12,Yes,Replace,Yes,Easy +c,MISRA-C-2012,Amendment4,RULE-11-3,Yes,Expand,Yes,Easy +c,MISRA-C-2012,Amendment4,RULE-11-8,Yes,Expand,Yes,Easy +c,MISRA-C-2012,Amendment4,RULE-13-2,Yes,Expand,Yes,Very Hard +c,MISRA-C-2012,Amendment4,RULE-18-6,Yes,Expand,Yes,Medium +c,MISRA-C-2012,Amendment4,RULE-18-8,Yes,Split,Yes,Easy +c,MISRA-C-2012,Amendment4,RULE-2-2,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Amendment4,RULE-2-7,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Amendment4,RULE-3-1,Yes,Refine,Yes,Easy +c,MISRA-C-2012,Amendment4,RULE-8-6,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Amendment4,RULE-8-9,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Amendment4,RULE-9-4,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Amendment4,RULE-10-1,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Amendment4,RULE-18-3,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Amendment4,RULE-1-4,Yes,Replace,Yes,Easy +c,MISRA-C-2012,Amendment4,RULE-9-1,Yes,Refine,Yes,Easy +c,MISRA-C-2012,Corrigendum2,DIR-4-10,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-7-4,Yes,Refine,Yes,Easy +c,MISRA-C-2012,Corrigendum2,RULE-8-2,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-8-3,Yes,Refine,Yes,Easy +c,MISRA-C-2012,Corrigendum2,RULE-8-7,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-10-1,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-10-2,Yes,Refine,Yes,Easy +c,MISRA-C-2012,Corrigendum2,RULE-10-3,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-11-3,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-11-6,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-13-2,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-13-6,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-14-3,Yes,Refine,Yes,Easy +c,MISRA-C-2012,Corrigendum2,RULE-15-7,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-17-4,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-17-5,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-18-1,Yes,Refine,Yes,Easy +c,MISRA-C-2012,Corrigendum2,RULE-20-14,No,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-21-19,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-21-20,Yes,Refine,Yes,Easy +c,MISRA-C-2012,Corrigendum2,RULE-22-9,Yes,Clarification,Yes,Import diff --git a/apply-configuration/action.yml b/apply-configuration/action.yml new file mode 100644 index 0000000000..89a702b72a --- /dev/null +++ b/apply-configuration/action.yml @@ -0,0 +1,24 @@ +name: Applies Coding Standard configuration files in the repository +description: | + Installs Python and indexes the CodeQL Coding Standard configuration files in the repository + +runs: + using: composite + steps: + - name: Install Python + id: cs-install-python + uses: actions/setup-python@v5 + with: + python-version: 3.9 + update-environment: false + - name: Install dependencies and process files + shell: bash + run: | + install_dir=$(dirname $(dirname "${{ steps.cs-install-python.outputs.python-path }}")) + if [[ -z "$LD_LIBRARY_PATH" ]]; then + export LD_LIBRARY_PATH="$install_dir/lib" + else + export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$install_dir/lib" + fi + ${{ steps.cs-install-python.outputs.python-path }} -m pip install -r ${GITHUB_ACTION_PATH}/../scripts/configuration/requirements.txt + ${{ steps.cs-install-python.outputs.python-path }} ${GITHUB_ACTION_PATH}/../scripts/configuration/process_coding_standards_config.py \ No newline at end of file diff --git a/c/cert/src/codeql-pack.lock.yml b/c/cert/src/codeql-pack.lock.yml index 514e6963d0..a45ea8f438 100644 --- a/c/cert/src/codeql-pack.lock.yml +++ b/c/cert/src/codeql-pack.lock.yml @@ -2,13 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.9.3 + version: 4.0.3 codeql/dataflow: - version: 0.0.4 + version: 2.0.3 + codeql/mad: + version: 1.0.19 + codeql/rangeanalysis: + version: 1.0.19 codeql/ssa: - version: 0.1.5 + version: 1.0.19 codeql/tutorial: - version: 0.1.5 + version: 1.0.19 + codeql/typeflow: + version: 1.0.19 + codeql/typetracking: + version: 2.0.3 codeql/util: - version: 0.1.5 + version: 2.0.6 + codeql/xml: + version: 1.0.19 compiled: false diff --git a/c/cert/src/codeql-suites/cert-c-default.qls b/c/cert/src/codeql-suites/cert-c-default.qls new file mode 100644 index 0000000000..348d2f37ae --- /dev/null +++ b/c/cert/src/codeql-suites/cert-c-default.qls @@ -0,0 +1,10 @@ +- description: CERT C 2016 (Default) +- qlpack: codeql/cert-c-coding-standards +- include: + kind: + - problem + - path-problem + - external/cert/obligation/rule +- exclude: + tags contain: + - external/cert/default-disabled diff --git a/c/cert/src/codeql-suites/cert-c-l1.qls b/c/cert/src/codeql-suites/cert-c-l1.qls new file mode 100644 index 0000000000..b2056fbec8 --- /dev/null +++ b/c/cert/src/codeql-suites/cert-c-l1.qls @@ -0,0 +1,12 @@ +- description: CERT C 2016 Level 1 Rules (Priority 12 - Priority 27) +- qlpack: codeql/cert-c-coding-standards +- include: + kind: + - problem + - path-problem + - external/cert/obligation/rule + tags contain: + - external/cert/level/l1 +- exclude: + tags contain: + - external/cert/default-disabled \ No newline at end of file diff --git a/c/cert/src/codeql-suites/cert-c-l2.qls b/c/cert/src/codeql-suites/cert-c-l2.qls new file mode 100644 index 0000000000..9c0a4b1ef9 --- /dev/null +++ b/c/cert/src/codeql-suites/cert-c-l2.qls @@ -0,0 +1,12 @@ +- description: CERT C 2016 Level 2 Rules (Priority 6 - Priority 9) +- qlpack: codeql/cert-c-coding-standards +- include: + kind: + - problem + - path-problem + - external/cert/obligation/rule + tags contain: + - external/cert/level/l2 +- exclude: + tags contain: + - external/cert/default-disabled \ No newline at end of file diff --git a/c/cert/src/codeql-suites/cert-c-l3.qls b/c/cert/src/codeql-suites/cert-c-l3.qls new file mode 100644 index 0000000000..462a6d816f --- /dev/null +++ b/c/cert/src/codeql-suites/cert-c-l3.qls @@ -0,0 +1,12 @@ +- description: CERT C 2016 Level 3 Rules (Priority 1 - Priority 4) +- qlpack: codeql/cert-c-coding-standards +- include: + kind: + - problem + - path-problem + - external/cert/obligation/rule + tags contain: + - external/cert/level/l3 +- exclude: + tags contain: + - external/cert/default-disabled \ No newline at end of file diff --git a/c/cert/src/codeql-suites/cert-c-recommendation.qls b/c/cert/src/codeql-suites/cert-c-recommendation.qls new file mode 100644 index 0000000000..59ac5e9c2d --- /dev/null +++ b/c/cert/src/codeql-suites/cert-c-recommendation.qls @@ -0,0 +1,10 @@ +- description: CERT C 2016 (Recommendations) +- qlpack: codeql/cert-c-coding-standards +- include: + kind: + - problem + - path-problem + - external/cert/obligation/recommendation +- exclude: + tags contain: + - external/cert/default-disabled diff --git a/c/cert/src/codeql-suites/cert-default.qls b/c/cert/src/codeql-suites/cert-default.qls index 1e11a0afca..c093b31fa7 100644 --- a/c/cert/src/codeql-suites/cert-default.qls +++ b/c/cert/src/codeql-suites/cert-default.qls @@ -1,9 +1,2 @@ -- description: CERT C 2016 (Default) -- qlpack: codeql/cert-c-coding-standards -- include: - kind: - - problem - - path-problem -- exclude: - tags contain: - - external/cert/default-disabled +- description: "DEPRECATED - CERT C 2016 - use cert-c-default.qls instead" +- import: codeql-suites/cert-c-default.qls diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index 58b6100d68..ecf2a573e4 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,8 +1,9 @@ name: codeql/cert-c-coding-standards -version: 2.32.0-dev +version: 2.52.0-dev description: CERT C 2016 suites: codeql-suites license: MIT +default-suite-file: codeql-suites/cert-c-default.qls dependencies: codeql/common-c-coding-standards: '*' - codeql/cpp-all: 0.9.3 + codeql/cpp-all: 4.0.3 diff --git a/c/cert/src/rules/ARR30-C/DoNotFormOutOfBoundsPointersOrArraySubscripts.ql b/c/cert/src/rules/ARR30-C/DoNotFormOutOfBoundsPointersOrArraySubscripts.ql index cc4c99c002..fed579bf34 100644 --- a/c/cert/src/rules/ARR30-C/DoNotFormOutOfBoundsPointersOrArraySubscripts.ql +++ b/c/cert/src/rules/ARR30-C/DoNotFormOutOfBoundsPointersOrArraySubscripts.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/arr30-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/high + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.ql b/c/cert/src/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.ql index 40a800aa69..1356777e5f 100644 --- a/c/cert/src/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.ql +++ b/c/cert/src/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.ql @@ -9,12 +9,18 @@ * @tags external/cert/id/arr32-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert import codingstandards.cpp.Overflow +import semmle.code.cpp.dataflow.TaintTracking /** * Gets the maximum size (in bytes) a variable-length array diff --git a/c/cert/src/rules/ARR36-C/DoNotRelatePointersThatDoNotReferToTheSameArray.ql b/c/cert/src/rules/ARR36-C/DoNotRelatePointersThatDoNotReferToTheSameArray.ql index 93244bd483..e42437042f 100644 --- a/c/cert/src/rules/ARR36-C/DoNotRelatePointersThatDoNotReferToTheSameArray.ql +++ b/c/cert/src/rules/ARR36-C/DoNotRelatePointersThatDoNotReferToTheSameArray.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/arr36-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ARR36-C/DoNotSubtractPointersThatDoNotReferToTheSameArray.ql b/c/cert/src/rules/ARR36-C/DoNotSubtractPointersThatDoNotReferToTheSameArray.ql index b3ed62d5d7..a9e53e68b7 100644 --- a/c/cert/src/rules/ARR36-C/DoNotSubtractPointersThatDoNotReferToTheSameArray.ql +++ b/c/cert/src/rules/ARR36-C/DoNotSubtractPointersThatDoNotReferToTheSameArray.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/arr36-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql b/c/cert/src/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql index 2f8ecec25d..635d9d5c03 100644 --- a/c/cert/src/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql +++ b/c/cert/src/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql @@ -8,12 +8,17 @@ * @problem.severity error * @tags external/cert/id/arr37-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import NonArrayPointerToArrayIndexingExprFlow::PathGraph /** diff --git a/c/cert/src/rules/ARR38-C/LibraryFunctionArgumentOutOfBounds.ql b/c/cert/src/rules/ARR38-C/LibraryFunctionArgumentOutOfBounds.ql index 5082743193..04e1c8a505 100644 --- a/c/cert/src/rules/ARR38-C/LibraryFunctionArgumentOutOfBounds.ql +++ b/c/cert/src/rules/ARR38-C/LibraryFunctionArgumentOutOfBounds.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/arr38-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql b/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql index c641c17124..c3ebd6ede6 100644 --- a/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql +++ b/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql @@ -8,13 +8,18 @@ * @problem.severity error * @tags external/cert/id/arr39-c * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert -import codingstandards.c.Pointers -import codingstandards.cpp.dataflow.TaintTracking +import codingstandards.cpp.types.Pointers +import semmle.code.cpp.dataflow.TaintTracking import ScaledIntegerPointerArithmeticFlow::PathGraph /** diff --git a/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql b/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql index 59fab6e455..1e03c089e8 100644 --- a/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql +++ b/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql @@ -9,14 +9,18 @@ * @tags external/cert/id/con30-c * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert import codingstandards.cpp.Concurrency -import codingstandards.cpp.dataflow.TaintTracking -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow module TssCreateToTssDeleteConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node node) { diff --git a/c/cert/src/rules/CON31-C/DoNotAllowAMutexToGoOutOfScopeWhileLocked.ql b/c/cert/src/rules/CON31-C/DoNotAllowAMutexToGoOutOfScopeWhileLocked.ql index 0bde0b0de7..345623fe0d 100644 --- a/c/cert/src/rules/CON31-C/DoNotAllowAMutexToGoOutOfScopeWhileLocked.ql +++ b/c/cert/src/rules/CON31-C/DoNotAllowAMutexToGoOutOfScopeWhileLocked.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con31-c * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON31-C/DoNotDestroyAMutexWhileItIsLocked.ql b/c/cert/src/rules/CON31-C/DoNotDestroyAMutexWhileItIsLocked.ql index b37dccab3a..40c4e936dd 100644 --- a/c/cert/src/rules/CON31-C/DoNotDestroyAMutexWhileItIsLocked.ql +++ b/c/cert/src/rules/CON31-C/DoNotDestroyAMutexWhileItIsLocked.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/con31-c * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.ql b/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.ql index d4f3cbbe10..3ea9e1e1fd 100644 --- a/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.ql +++ b/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con32-c * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.ql b/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.ql index 4efafd8ebf..c9bcaa6bd2 100644 --- a/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.ql +++ b/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/con33-c * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql index e0617c266d..4fb034406b 100644 --- a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql +++ b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql @@ -9,35 +9,53 @@ * @tags external/cert/id/con34-c * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert +import codingstandards.c.Objects import codingstandards.cpp.Concurrency -import codingstandards.cpp.dataflow.TaintTracking -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.commons.Alloc -from C11ThreadCreateCall tcc, StackVariable sv, Expr arg, Expr acc +from C11ThreadCreateCall tcc, Expr arg where not isExcluded(tcc, Concurrency4Package::appropriateThreadObjectStorageDurationsQuery()) and tcc.getArgument(2) = arg and - sv.getAnAccess() = acc and - // a stack variable that is given as an argument to a thread - TaintTracking::localTaint(DataFlow::exprNode(acc), DataFlow::exprNode(arg)) and - // or isn't one of the allowed usage patterns - not exists(Expr mfc | - isAllocationExpr(mfc) and - sv.getAnAssignedValue() = mfc and - acc.getAPredecessor*() = mfc - ) and - not exists(TSSGetFunctionCall tsg, TSSSetFunctionCall tss, DataFlow::Node src | - sv.getAnAssignedValue() = tsg and - acc.getAPredecessor*() = tsg and - // there should be dataflow from somewhere (the same somewhere) - // into each of the first arguments - DataFlow::localFlow(src, DataFlow::exprNode(tsg.getArgument(0))) and - DataFlow::localFlow(src, DataFlow::exprNode(tss.getArgument(0))) + ( + exists(ObjectIdentity obj, Expr acc | + obj.getASubobjectAccess() = acc and + obj.getStorageDuration().isAutomatic() and + exists(DataFlow::Node addrNode | + ( + addrNode = DataFlow::exprNode(any(AddressOfExpr e | e.getOperand() = acc)) + or + addrNode = DataFlow::exprNode(acc) and + exists(ArrayToPointerConversion c | c.getExpr() = acc) + ) and + TaintTracking::localTaint(addrNode, DataFlow::exprNode(arg)) + ) + ) + or + // TODO: This case is handling threadlocals in a useful way that's not intended to be covered + // by the rule. See issue #801. The actual rule should expect no tss_t objects is used, and + // this check that this is initialized doesn't seem to belong here. However, it is a useful + // check in and of itself, so we should figure out if this is part of an optional rule we + // haven't yet implemented and move this behavior there. + exists(TSSGetFunctionCall tsg | + TaintTracking::localTaint(DataFlow::exprNode(tsg), DataFlow::exprNode(arg)) and + not exists(TSSSetFunctionCall tss, DataFlow::Node src | + // there should be dataflow from somewhere (the same somewhere) + // into each of the first arguments + DataFlow::localFlow(src, DataFlow::exprNode(tsg.getArgument(0))) and + DataFlow::localFlow(src, DataFlow::exprNode(tss.getArgument(0))) + ) + ) ) select tcc, "$@ not declared with appropriate storage duration", arg, "Shared object" diff --git a/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql b/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql index 0fd94911ec..07b114d6ca 100644 --- a/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql +++ b/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql @@ -10,14 +10,18 @@ * external/cert/audit * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert import codingstandards.cpp.Concurrency -import codingstandards.cpp.dataflow.TaintTracking -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow from TSSGetFunctionCall tsg, ThreadedFunction tf where diff --git a/c/cert/src/rules/CON35-C/DeadlockByLockingInPredefinedOrder.ql b/c/cert/src/rules/CON35-C/DeadlockByLockingInPredefinedOrder.ql index 143e0a58be..764b0f263f 100644 --- a/c/cert/src/rules/CON35-C/DeadlockByLockingInPredefinedOrder.ql +++ b/c/cert/src/rules/CON35-C/DeadlockByLockingInPredefinedOrder.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con35-c * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON36-C/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.ql b/c/cert/src/rules/CON36-C/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.ql index 430a0e7c19..d0d948d9b2 100644 --- a/c/cert/src/rules/CON36-C/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.ql +++ b/c/cert/src/rules/CON36-C/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con36-c * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.ql b/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.ql index 00cf456948..17691f24dd 100644 --- a/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.ql +++ b/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con37-c * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/low + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON38-C/PreserveSafetyWhenUsingConditionVariables.ql b/c/cert/src/rules/CON38-C/PreserveSafetyWhenUsingConditionVariables.ql index 470480ae62..3b2ae558d8 100644 --- a/c/cert/src/rules/CON38-C/PreserveSafetyWhenUsingConditionVariables.ql +++ b/c/cert/src/rules/CON38-C/PreserveSafetyWhenUsingConditionVariables.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con38-c * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.ql b/c/cert/src/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.ql index a8dead535d..6ef617ca72 100644 --- a/c/cert/src/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.ql +++ b/c/cert/src/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.ql @@ -9,42 +9,20 @@ * @tags external/cert/id/con39-c * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert -import codingstandards.cpp.Concurrency +import codingstandards.cpp.rules.joinordetachthreadonlyonce.JoinOrDetachThreadOnlyOnce -// OK -// 1) Thread calls detach parent DOES NOT call join -// 2) Parent calls join, thread does NOT call detach() -// NOT OK -// 1) Thread calls detach, parent calls join -// 2) Thread calls detach twice, parent does not call join -// 3) Parent calls join twice, thread does not call detach -from C11ThreadCreateCall tcc -where - not isExcluded(tcc, Concurrency5Package::threadWasPreviouslyJoinedOrDetachedQuery()) and - // Note: These cases can be simplified but they are presented like this for clarity - // case 1 - calls to `thrd_join` and `thrd_detach` within the parent or - // within the parent / child CFG. - exists(C11ThreadWait tw, C11ThreadDetach dt | - tw = getAThreadContextAwareSuccessor(tcc) and - dt = getAThreadContextAwareSuccessor(tcc) - ) - or - // case 2 - multiple calls to `thrd_detach` within the threaded CFG. - exists(C11ThreadDetach dt1, C11ThreadDetach dt2 | - dt1 = getAThreadContextAwareSuccessor(tcc) and - dt2 = getAThreadContextAwareSuccessor(tcc) and - not dt1 = dt2 - ) - or - // case 3 - multiple calls to `thrd_join` within the threaded CFG. - exists(C11ThreadWait tw1, C11ThreadWait tw2 | - tw1 = getAThreadContextAwareSuccessor(tcc) and - tw2 = getAThreadContextAwareSuccessor(tcc) and - not tw1 = tw2 - ) -select tcc, "Thread may call join or detach after the thread is joined or detached." +class ThreadWasPreviouslyJoinedOrDetachedQuery extends JoinOrDetachThreadOnlyOnceSharedQuery { + ThreadWasPreviouslyJoinedOrDetachedQuery() { + this = Concurrency5Package::threadWasPreviouslyJoinedOrDetachedQuery() + } +} diff --git a/c/cert/src/rules/CON40-C/AtomicVariableTwiceInExpression.ql b/c/cert/src/rules/CON40-C/AtomicVariableTwiceInExpression.ql index 8a44013277..0ec195868f 100644 --- a/c/cert/src/rules/CON40-C/AtomicVariableTwiceInExpression.ql +++ b/c/cert/src/rules/CON40-C/AtomicVariableTwiceInExpression.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con40-c * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.ql b/c/cert/src/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.ql index dd8aed6a55..57be1bc488 100644 --- a/c/cert/src/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.ql +++ b/c/cert/src/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con41-c * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql b/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql index 9097f14297..2e1064ee9d 100644 --- a/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql +++ b/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql @@ -8,15 +8,26 @@ * @problem.severity error * @tags external/cert/id/dcl30-c * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert -import codingstandards.cpp.dataflow.DataFlow +import codingstandards.c.Objects +import semmle.code.cpp.dataflow.DataFlow -class Source extends StackVariable { - Source() { not this instanceof Parameter } +class Source extends Expr { + ObjectIdentity rootObject; + + Source() { + rootObject.getStorageDuration().isAutomatic() and + this = rootObject.getASubobjectAddressExpr() + } } class Sink extends DataFlow::Node { @@ -40,7 +51,7 @@ from DataFlow::Node src, DataFlow::Node sink where not isExcluded(sink.asExpr(), Declarations8Package::appropriateStorageDurationsFunctionReturnQuery()) and - exists(Source s | src.asExpr() = s.getAnAccess()) and + exists(Source s | src.asExpr() = s) and sink instanceof Sink and DataFlow::localFlow(src, sink) select sink, "$@ with automatic storage may be accessible outside of its lifetime.", src, diff --git a/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsStackAdressEscape.ql b/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsStackAdressEscape.ql index fb9b13b39c..a5749aa8bc 100644 --- a/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsStackAdressEscape.ql +++ b/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsStackAdressEscape.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/dcl30-c * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.ql b/c/cert/src/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.ql index 369baa4a63..35e6cd057a 100644 --- a/c/cert/src/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.ql +++ b/c/cert/src/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/dcl31-c * correctness * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/DCL37-C/DoNotDeclareOrDefineAReservedIdentifier.ql b/c/cert/src/rules/DCL37-C/DoNotDeclareOrDefineAReservedIdentifier.ql index 99c5a9708b..04a3030cc1 100644 --- a/c/cert/src/rules/DCL37-C/DoNotDeclareOrDefineAReservedIdentifier.ql +++ b/c/cert/src/rules/DCL37-C/DoNotDeclareOrDefineAReservedIdentifier.ql @@ -9,6 +9,11 @@ * correctness * maintainability * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.ql b/c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.ql index e9fa3f1017..d6000852c6 100644 --- a/c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.ql +++ b/c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.ql @@ -10,6 +10,11 @@ * correctness * maintainability * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/DCL39-C/InformationLeakageAcrossTrustBoundariesC.md b/c/cert/src/rules/DCL39-C/InformationLeakageAcrossTrustBoundariesC.md index cdc62493a1..4dd3bcbe3c 100644 --- a/c/cert/src/rules/DCL39-C/InformationLeakageAcrossTrustBoundariesC.md +++ b/c/cert/src/rules/DCL39-C/InformationLeakageAcrossTrustBoundariesC.md @@ -249,7 +249,7 @@ In addition, this solution assumes that there are no integer padding bits in an From this situation, it can be seen that special care must be taken because no solution to the bit-field padding issue will be 100% portable. -Risk Assessment +## Risk Assessment Padding units might contain sensitive data because the C Standard allows any padding to take [unspecified values](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unspecifiedvalue). A pointer to such a structure could be passed to other functions, causing information leakage. diff --git a/c/cert/src/rules/DCL39-C/InformationLeakageAcrossTrustBoundariesC.ql b/c/cert/src/rules/DCL39-C/InformationLeakageAcrossTrustBoundariesC.ql index 1199fbeb9b..dd2c1217cf 100644 --- a/c/cert/src/rules/DCL39-C/InformationLeakageAcrossTrustBoundariesC.ql +++ b/c/cert/src/rules/DCL39-C/InformationLeakageAcrossTrustBoundariesC.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/dcl39-c * security + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/high + * external/cert/priority/p1 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.ql b/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.ql index ba2cc5c23f..d002326fae 100644 --- a/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.ql +++ b/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.ql @@ -9,6 +9,11 @@ * correctness * maintainability * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql b/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql index 4660e69b68..3811d4e417 100644 --- a/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql +++ b/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql @@ -11,35 +11,52 @@ * correctness * maintainability * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert +import codingstandards.cpp.types.Compatible import ExternalIdentifiers -//checks if they are incompatible based on return type, number of parameters and parameter types -predicate checkMatchingFunction(FunctionDeclarationEntry d, FunctionDeclarationEntry d2) { - not d.getType() = d2.getType() - or - not d.getNumberOfParameters() = d2.getNumberOfParameters() - or - exists(ParameterDeclarationEntry p, ParameterDeclarationEntry p2, int i | - d.getParameterDeclarationEntry(i) = p and - d2.getParameterDeclarationEntry(i) = p2 and - not p.getType() = p2.getType() - ) +predicate interestedInFunctions( + FunctionDeclarationEntry f1, FunctionDeclarationEntry f2, ExternalIdentifiers d +) { + not f1 = f2 and + d = f1.getDeclaration() and + d = f2.getDeclaration() +} + +predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { + interestedInFunctions(f1, f2, _) } +module FuncDeclEquiv = + FunctionDeclarationTypeEquivalence; + from ExternalIdentifiers d, FunctionDeclarationEntry f1, FunctionDeclarationEntry f2 where not isExcluded(f1, Declarations2Package::incompatibleFunctionDeclarationsQuery()) and not isExcluded(f2, Declarations2Package::incompatibleFunctionDeclarationsQuery()) and - f1 = d.getADeclarationEntry() and - f2 = d.getADeclarationEntry() and - not f1 = f2 and - f1.getLocation().getStartLine() >= f2.getLocation().getStartLine() and - f1.getName() = f2.getName() and - checkMatchingFunction(f1, f2) + interestedInFunctions(f1, f2, d) and + ( + //return type check + not FuncDeclEquiv::equalReturnTypes(f1, f2) + or + //parameter type check + not FuncDeclEquiv::equalParameterTypes(f1, f2) + ) and + // Apply ordering on start line, trying to avoid the optimiser applying this join too early + // in the pipeline + exists(int f1Line, int f2Line | + f1.getLocation().hasLocationInfo(_, f1Line, _, _, _) and + f2.getLocation().hasLocationInfo(_, f2Line, _, _, _) and + f1Line >= f2Line + ) select f1, "The object $@ is not compatible with re-declaration $@", f1, f1.getName(), f2, f2.getName() diff --git a/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.ql b/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.ql index 151d33db5c..8e220062d4 100644 --- a/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.ql +++ b/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.ql @@ -10,6 +10,11 @@ * correctness * maintainability * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/DCL41-C/VariablesInsideSwitchStatement.ql b/c/cert/src/rules/DCL41-C/VariablesInsideSwitchStatement.ql index db42f7102c..6f06174b99 100644 --- a/c/cert/src/rules/DCL41-C/VariablesInsideSwitchStatement.ql +++ b/c/cert/src/rules/DCL41-C/VariablesInsideSwitchStatement.ql @@ -10,6 +10,11 @@ * correctness * maintainability * readability + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.ql b/c/cert/src/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.ql index 42f13f6244..f69a78ba2c 100644 --- a/c/cert/src/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.ql +++ b/c/cert/src/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/env30-c * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.ql b/c/cert/src/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.ql index a925b80e74..b4d4a74d57 100644 --- a/c/cert/src/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.ql +++ b/c/cert/src/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/env31-c * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ENV32-C/ExitHandlersMustReturnNormally.ql b/c/cert/src/rules/ENV32-C/ExitHandlersMustReturnNormally.ql index 1b360ca0d8..19cf28b3e9 100644 --- a/c/cert/src/rules/ENV32-C/ExitHandlersMustReturnNormally.ql +++ b/c/cert/src/rules/ENV32-C/ExitHandlersMustReturnNormally.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/env32-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ENV33-C/DoNotCallSystem.ql b/c/cert/src/rules/ENV33-C/DoNotCallSystem.ql index 58a9c8db79..3b21cd7544 100644 --- a/c/cert/src/rules/ENV33-C/DoNotCallSystem.ql +++ b/c/cert/src/rules/ENV33-C/DoNotCallSystem.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/env33-c * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ENV34-C/DoNotStorePointersReturnedByEnvFunctions.ql b/c/cert/src/rules/ENV34-C/DoNotStorePointersReturnedByEnvFunctions.ql index 505f26046a..af54dfa823 100644 --- a/c/cert/src/rules/ENV34-C/DoNotStorePointersReturnedByEnvFunctions.ql +++ b/c/cert/src/rules/ENV34-C/DoNotStorePointersReturnedByEnvFunctions.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/env34-c * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ENV34-C/DoNotStorePointersReturnedByEnvironmentFunWarn.ql b/c/cert/src/rules/ENV34-C/DoNotStorePointersReturnedByEnvironmentFunWarn.ql index b5dd9f4d80..784b7898d6 100644 --- a/c/cert/src/rules/ENV34-C/DoNotStorePointersReturnedByEnvironmentFunWarn.ql +++ b/c/cert/src/rules/ENV34-C/DoNotStorePointersReturnedByEnvironmentFunWarn.ql @@ -9,6 +9,11 @@ * @problem.severity warning * @tags external/cert/id/env34-c * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ERR30-C/ErrnoNotSetToZero.ql b/c/cert/src/rules/ERR30-C/ErrnoNotSetToZero.ql index cc1dd82bbb..06ac9d1198 100644 --- a/c/cert/src/rules/ERR30-C/ErrnoNotSetToZero.ql +++ b/c/cert/src/rules/ERR30-C/ErrnoNotSetToZero.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err30-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ERR30-C/ErrnoReadBeforeReturn.ql b/c/cert/src/rules/ERR30-C/ErrnoReadBeforeReturn.ql index df8519f13f..13f7e40303 100644 --- a/c/cert/src/rules/ERR30-C/ErrnoReadBeforeReturn.ql +++ b/c/cert/src/rules/ERR30-C/ErrnoReadBeforeReturn.ql @@ -8,12 +8,18 @@ * @problem.severity error * @tags external/cert/id/err30-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert import codingstandards.c.Errno +import semmle.code.cpp.dataflow.DataFlow /** * A call to an `OutOfBandErrnoSettingFunction` diff --git a/c/cert/src/rules/ERR30-C/FunctionCallBeforeErrnoCheck.ql b/c/cert/src/rules/ERR30-C/FunctionCallBeforeErrnoCheck.ql index 8d63bb5d06..8bf583faff 100644 --- a/c/cert/src/rules/ERR30-C/FunctionCallBeforeErrnoCheck.ql +++ b/c/cert/src/rules/ERR30-C/FunctionCallBeforeErrnoCheck.ql @@ -8,13 +8,17 @@ * @problem.severity error * @tags external/cert/id/err30-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert import codingstandards.c.Errno -import codingstandards.cpp.dataflow.DataFlow /** * A call to an `OutOfBandErrnoSettingFunction` diff --git a/c/cert/src/rules/ERR30-C/SetlocaleMightSetErrno.ql b/c/cert/src/rules/ERR30-C/SetlocaleMightSetErrno.ql index 899fa49e60..a7ccf8c041 100644 --- a/c/cert/src/rules/ERR30-C/SetlocaleMightSetErrno.ql +++ b/c/cert/src/rules/ERR30-C/SetlocaleMightSetErrno.ql @@ -7,12 +7,18 @@ * @problem.severity error * @tags external/cert/id/err30-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert import codingstandards.c.Errno +import semmle.code.cpp.dataflow.DataFlow class SetlocaleFunctionCall extends FunctionCall { SetlocaleFunctionCall() { this.getTarget().hasGlobalName("setlocale") } diff --git a/c/cert/src/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.ql b/c/cert/src/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.ql index ab121a5cc6..146d0cb30f 100644 --- a/c/cert/src/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.ql +++ b/c/cert/src/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/err32-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ @@ -15,22 +20,23 @@ import codingstandards.c.cert import codingstandards.c.Errno import codingstandards.c.Signal import semmle.code.cpp.controlflow.Guards +import semmle.code.cpp.dataflow.DataFlow /** * A check on `signal` call return value * `if (signal(SIGINT, handler) == SIG_ERR)` */ -class SignalCheckOperation extends EqualityOperation, GuardCondition { +class SignalCheckOperation extends EqualityOperation instanceof GuardCondition { BasicBlock errorSuccessor; SignalCheckOperation() { this.getAnOperand() = any(MacroInvocation m | m.getMacroName() = "SIG_ERR").getExpr() and ( this.getOperator() = "==" and - this.controls(errorSuccessor, true) + super.controls(errorSuccessor, true) or this.getOperator() = "!=" and - this.controls(errorSuccessor, false) + super.controls(errorSuccessor, false) ) } diff --git a/c/cert/src/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.ql b/c/cert/src/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.ql index 6641fe8a52..5e473b226e 100644 --- a/c/cert/src/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.ql +++ b/c/cert/src/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err33-c * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ @@ -15,6 +20,7 @@ import cpp import codingstandards.c.cert import semmle.code.cpp.commons.NULL import codingstandards.cpp.ReadErrorsAndEOF +import semmle.code.cpp.dataflow.DataFlow ComparisonOperation getAValidComparison(string spec) { spec = "=0" and result.(EqualityOperation).getAnOperand().getValue() = "0" diff --git a/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.md b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.md new file mode 100644 index 0000000000..b5a7c98bd6 --- /dev/null +++ b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.md @@ -0,0 +1,129 @@ +# EXP16-C: Do not compare function pointers to constant values + +This query implements the CERT-C rule EXP16-C: + +> Do not compare function pointers to constant values + + +## Description + +Comparing a function pointer to a value that is not a null function pointer of the same type will be diagnosed because it typically indicates programmer error and can result in [unexpected behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unexpectedbehavior). Implicit comparisons will be diagnosed, as well. + +## Noncompliant Code Example + +In this noncompliant code example, the addresses of the POSIX functions `getuid` and `geteuid` are compared for equality to 0. Because no function address shall be null, the first subexpression will always evaluate to false (0), and the second subexpression always to true (nonzero). Consequently, the entire expression will always evaluate to true, leading to a potential security vulnerability. + +```cpp +/* First the options that are allowed only for root */ +if (getuid == 0 || geteuid != 0) { + /* ... */ +} + +``` + +## Noncompliant Code Example + +In this noncompliant code example, the function pointers `getuid` and `geteuid` are compared to 0. This example is from an actual [vulnerability](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) ([VU\#837857](http://www.kb.cert.org/vuls/id/837857)) discovered in some versions of the X Window System server. The vulnerability exists because the programmer neglected to provide the open and close parentheses following the `geteuid()` function identifier. As a result, the `geteuid` token returns the address of the function, which is never equal to 0. Consequently, the `or` condition of this `if` statement is always true, and access is provided to the protected block for all users. Many compilers issue a warning noting such pointless expressions. Therefore, this coding error is normally detected by adherence to [MSC00-C. Compile cleanly at high warning levels](https://wiki.sei.cmu.edu/confluence/display/c/MSC00-C.+Compile+cleanly+at+high+warning+levels). + +```cpp +/* First the options that are allowed only for root */ +if (getuid() == 0 || geteuid != 0) { + /* ... */ +} + +``` + +## Compliant Solution + +The solution is to provide the open and close parentheses following the `geteuid` token so that the function is properly invoked: + +```cpp +/* First the options that are allowed only for root */ +if (getuid() == 0 || geteuid() != 0) { + /* ... */ +} + +``` + +## Compliant Solution + +A function pointer can be compared to a null function pointer of the same type: + +```cpp +/* First the options that are allowed only for root */ +if (getuid == (uid_t(*)(void))0 || geteuid != (uid_t(*)(void))0) { + /* ... */ +} + +``` +This code should not be diagnosed by an analyzer. + +## Noncompliant Code Example + +In this noncompliant code example, the function pointer `do_xyz` is implicitly compared unequal to 0: + +```cpp +int do_xyz(void); + +int f(void) { +/* ... */ + if (do_xyz) { + return -1; /* Indicate failure */ + } +/* ... */ + return 0; +} + +``` + +## Compliant Solution + +In this compliant solution, the function `do_xyz()` is invoked and the return value is compared to 0: + +```cpp +int do_xyz(void); + +int f(void) { +/* ... */ + if (do_xyz()) { + return -1; /* Indicate failure */ + } +/* ... */ + return 0; +} + +``` + +## Risk Assessment + +Errors of omission can result in unintended program flow. + +
Recommendation Severity Likelihood Remediation Cost Priority Level
EXP16-C Low Likely Medium P6 L2
+ + +## Automated Detection + +
Tool Version Checker Description
Astrée 24.04 function-name-constant-comparison Partially checked
Coverity 2017.07 BAD_COMPARE Can detect the specific instance where the address of a function is compared against 0, such as in the case of geteuid versus getuid() in the implementation-specific details
GCC 4.3.5 Can detect violations of this recommendation when the -Wall flag is used
Helix QAC 2024.4 C0428, C3004, C3344
Klocwork 2024.4 CWARN.NULLCHECK.FUNCNAMECWARN.FUNCADDR
LDRA tool suite 9.7.1 99 S Partially implemented
Parasoft C/C++test 2024.2 CERT_C-EXP16-a Function address should not be compared to zero
PC-lint Plus 1.4 2440, 2441 Partially supported: reports address of function, array, or variable directly or indirectly compared to null
PVS-Studio 7.35 V516, V1058
RuleChecker 24.04 function-name-constant-comparison Partially checked
+ + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+EXP16-C). + +## Related Guidelines + +
SEI CERT C++ Coding Standard VOID EXP16-CPP. Avoid conversions using void pointers
ISO/IEC TR 24772:2013 Likely incorrect expressions \[KOA\]
ISO/IEC TS 17961 Comparing function addresses to zero \[funcaddr\]
MITRE CWE CWE-480 , Use of incorrect operator CWE-482 , Comparing instead of assigning
+ + +## Bibliography + +
\[ Hatton 1995 \] Section 2.7.2, "Errors of Omission and Addition"
+ + +## Implementation notes + +None + +## References + +* CERT-C: [EXP16-C: Do not compare function pointers to constant values](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql new file mode 100644 index 0000000000..5f347d817a --- /dev/null +++ b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql @@ -0,0 +1,73 @@ +/** + * @id c/cert/do-not-compare-function-pointers-to-constant-values + * @name EXP16-C: Do not compare function pointers to constant values + * @description Comparing function pointers to a constant value is not reliable and likely indicates + * a programmer error. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/exp16-c + * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 + * external/cert/obligation/recommendation + */ + +import cpp +import semmle.code.cpp.controlflow.IRGuards +import codingstandards.c.cert +import codingstandards.cpp.types.FunctionType +import codingstandards.cpp.exprs.FunctionExprs +import codingstandards.cpp.exprs.Guards + +final class FinalElement = Element; + +abstract class EffectivelyComparison extends FinalElement { + abstract string getExplanation(); + + abstract FunctionExpr getFunctionExpr(); +} + +final class FinalComparisonOperation = ComparisonOperation; + +class ExplicitComparison extends EffectivelyComparison, FinalComparisonOperation { + Expr constantExpr; + FunctionExpr funcExpr; + + ExplicitComparison() { + funcExpr = getAnOperand() and + constantExpr = getAnOperand() and + exists(constantExpr.getValue()) and + not funcExpr = constantExpr and + not constantExpr.getExplicitlyConverted().getUnderlyingType() = + funcExpr.getExplicitlyConverted().getUnderlyingType() + } + + override string getExplanation() { result = "$@ compared to constant value." } + + override FunctionExpr getFunctionExpr() { result = funcExpr } +} + +class ImplicitComparison extends EffectivelyComparison, GuardCondition { + ImplicitComparison() { + this instanceof FunctionExpr and + not getParent() instanceof ComparisonOperation + } + + override string getExplanation() { result = "$@ undergoes implicit constant comparison." } + + override FunctionExpr getFunctionExpr() { result = this } +} + +from EffectivelyComparison comparison, FunctionExpr funcExpr, Element function, string funcName +where + not isExcluded(comparison, + Expressions2Package::doNotCompareFunctionPointersToConstantValuesQuery()) and + funcExpr = comparison.getFunctionExpr() and + not exists(NullFunctionCallGuard nullGuard | nullGuard.getFunctionExpr() = funcExpr) and + function = funcExpr.getFunction() and + funcName = funcExpr.describe() +select comparison, comparison.getExplanation(), function, funcName diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql index bf8f99fd27..48b9487728 100644 --- a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql @@ -8,14 +8,18 @@ * @problem.severity warning * @tags external/cert/id/exp30-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert import codingstandards.cpp.SideEffect -import codingstandards.cpp.dataflow.DataFlow -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import semmle.code.cpp.valuenumbering.GlobalValueNumbering /** Holds if the function's return value is derived from the `AliasParamter` p. */ diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.ql b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.ql index c478a3d51e..51b505ec63 100644 --- a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.ql +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/exp30-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.ql b/c/cert/src/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.ql index 47b94c5288..891b93bcda 100644 --- a/c/cert/src/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.ql +++ b/c/cert/src/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/exp32-c * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP33-C/DoNotReadUninitializedMemory.ql b/c/cert/src/rules/EXP33-C/DoNotReadUninitializedMemory.ql index ef59be1c10..94deea912e 100644 --- a/c/cert/src/rules/EXP33-C/DoNotReadUninitializedMemory.ql +++ b/c/cert/src/rules/EXP33-C/DoNotReadUninitializedMemory.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/exp33-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP34-C/DoNotDereferenceNullPointers.ql b/c/cert/src/rules/EXP34-C/DoNotDereferenceNullPointers.ql index 042e55dbfd..51b93c8000 100644 --- a/c/cert/src/rules/EXP34-C/DoNotDereferenceNullPointers.ql +++ b/c/cert/src/rules/EXP34-C/DoNotDereferenceNullPointers.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/exp34-c * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.ql b/c/cert/src/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.ql index 2d66b8643c..3f7d9ae142 100644 --- a/c/cert/src/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.ql +++ b/c/cert/src/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.ql @@ -8,31 +8,23 @@ * @problem.severity error * @tags external/cert/id/exp35-c * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert - -/** - * A struct or union type that contains an array type - */ -class StructOrUnionTypeWithArrayField extends Struct { - StructOrUnionTypeWithArrayField() { - this.getAField().getUnspecifiedType() instanceof ArrayType - or - // nested struct or union containing an array type - this.getAField().getUnspecifiedType().(Struct) instanceof StructOrUnionTypeWithArrayField - } -} +import codingstandards.c.Objects // Note: Undefined behavior is possible regardless of whether the accessed field from the returned // struct is an array or a scalar (i.e. arithmetic and pointer types) member, according to the standard. -from FieldAccess fa, FunctionCall fc +from FieldAccess fa, TemporaryObjectIdentity tempObject where not isExcluded(fa, InvalidMemory2Package::doNotModifyObjectsWithTemporaryLifetimeQuery()) and - not fa.getQualifier().isLValue() and - fa.getQualifier().getUnconverted() = fc and - fa.getQualifier().getUnconverted().getUnspecifiedType() instanceof StructOrUnionTypeWithArrayField -select fa, "Field access on $@ qualifier occurs after its temporary object lifetime.", fc, - "function call" + fa.getQualifier().getUnconverted() = tempObject +select fa, "Field access on $@ qualifier occurs after its temporary object lifetime.", tempObject, + "temporary object" diff --git a/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql b/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql index e5735a5fda..0d294e48b1 100644 --- a/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql +++ b/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql @@ -8,13 +8,18 @@ * @problem.severity error * @tags external/cert/id/exp36-c * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert import codingstandards.cpp.Alignment -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis import ExprWithAlignmentToCStyleCastFlow::PathGraph diff --git a/c/cert/src/rules/EXP37-C/CallPOSIXOpenWithCorrectArgumentCount.ql b/c/cert/src/rules/EXP37-C/CallPOSIXOpenWithCorrectArgumentCount.ql index ad8520e321..a6e633d7f6 100644 --- a/c/cert/src/rules/EXP37-C/CallPOSIXOpenWithCorrectArgumentCount.ql +++ b/c/cert/src/rules/EXP37-C/CallPOSIXOpenWithCorrectArgumentCount.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/exp37-c * correctness * security + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.ql b/c/cert/src/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.ql index e28dbddaaf..6d223dab72 100644 --- a/c/cert/src/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.ql +++ b/c/cert/src/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.ql @@ -8,12 +8,17 @@ * @problem.severity error * @tags external/cert/id/exp37-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import SuspectFunctionPointerToCallFlow::PathGraph /** diff --git a/c/cert/src/rules/EXP37-C/DoNotCallFunctionsWithIncompatibleArguments.ql b/c/cert/src/rules/EXP37-C/DoNotCallFunctionsWithIncompatibleArguments.ql index e76c62ee2d..4c5ba57504 100644 --- a/c/cert/src/rules/EXP37-C/DoNotCallFunctionsWithIncompatibleArguments.ql +++ b/c/cert/src/rules/EXP37-C/DoNotCallFunctionsWithIncompatibleArguments.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/exp37-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql b/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql index 825f85b0bd..856cad1d58 100644 --- a/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql +++ b/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql @@ -8,12 +8,17 @@ * @problem.severity error * @tags external/cert/id/exp39-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/high + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.controlflow.Dominance import IndirectCastFlow::PathGraph diff --git a/c/cert/src/rules/EXP40-C/DoNotModifyConstantObjects.ql b/c/cert/src/rules/EXP40-C/DoNotModifyConstantObjects.ql index d79224435f..9d8e4b16d4 100644 --- a/c/cert/src/rules/EXP40-C/DoNotModifyConstantObjects.ql +++ b/c/cert/src/rules/EXP40-C/DoNotModifyConstantObjects.ql @@ -7,12 +7,17 @@ * @problem.severity error * @tags external/cert/id/exp40-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import CastFlow::PathGraph import codingstandards.cpp.SideEffect diff --git a/c/cert/src/rules/EXP42-C/DoNotComparePaddingData.ql b/c/cert/src/rules/EXP42-C/DoNotComparePaddingData.ql index 9592ebfd30..4fb80352a3 100644 --- a/c/cert/src/rules/EXP42-C/DoNotComparePaddingData.ql +++ b/c/cert/src/rules/EXP42-C/DoNotComparePaddingData.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/exp42-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.ql b/c/cert/src/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.ql index a4cc4e8944..4aced57136 100644 --- a/c/cert/src/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.ql +++ b/c/cert/src/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.ql @@ -7,182 +7,21 @@ * @problem.severity error * @tags external/cert/id/exp43-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert -import codingstandards.c.Pointers -import codingstandards.c.Variable -import codingstandards.cpp.dataflow.DataFlow -import semmle.code.cpp.pointsto.PointsTo -import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis +import codingstandards.cpp.rules.donotpassaliasedpointertorestrictqualifiedparamshared.DoNotPassAliasedPointerToRestrictQualifiedParamShared -/** - * A function that has a parameter with a restrict-qualified pointer type. - */ -class FunctionWithRestrictParameters extends Function { - Parameter restrictPtrParam; - - FunctionWithRestrictParameters() { - restrictPtrParam.getUnspecifiedType() instanceof PointerOrArrayType and - ( - restrictPtrParam.getType().hasSpecifier(["restrict"]) and - restrictPtrParam = this.getAParameter() - or - this.hasGlobalName(["strcpy", "strncpy", "strcat", "strncat", "memcpy"]) and - restrictPtrParam = this.getParameter([0, 1]) - or - this.hasGlobalName(["strcpy_s", "strncpy_s", "strcat_s", "strncat_s", "memcpy_s"]) and - restrictPtrParam = this.getParameter([0, 2]) - or - this.hasGlobalName(["strtok_s"]) and - restrictPtrParam = this.getAParameter() - or - this.hasGlobalName(["printf", "printf_s", "scanf", "scanf_s"]) and - restrictPtrParam = this.getParameter(0) - or - this.hasGlobalName(["sprintf", "sprintf_s", "snprintf", "snprintf_s"]) and - restrictPtrParam = this.getParameter(3) - ) - } - - Parameter getARestrictPtrParam() { result = restrictPtrParam } -} - -/** - * A call to a function that has a parameter with a restrict-qualified pointer type. - */ -class CallToFunctionWithRestrictParameters extends FunctionCall { - CallToFunctionWithRestrictParameters() { - this.getTarget() instanceof FunctionWithRestrictParameters - } - - Expr getARestrictPtrArg() { - result = - this.getArgument(this.getTarget() - .(FunctionWithRestrictParameters) - .getARestrictPtrParam() - .getIndex()) - } - - Expr getAPtrArg(int index) { - result = this.getArgument(index) and - pointerValue(result) - } - - Expr getAPossibleSizeArg() { - exists(Parameter param | - param = this.getTarget().(FunctionWithRestrictParameters).getAParameter() and - param.getUnderlyingType() instanceof IntegralType and - // exclude __builtin_object_size - not result.(FunctionCall).getTarget() instanceof BuiltInFunction and - result = this.getArgument(param.getIndex()) - ) - } -} - -/** - * A `PointsToExpr` that is an argument of a pointer-type in a `CallToFunctionWithRestrictParameters` - */ -class CallToFunctionWithRestrictParametersArgExpr extends Expr { - int paramIndex; - - CallToFunctionWithRestrictParametersArgExpr() { - this = any(CallToFunctionWithRestrictParameters call).getAPtrArg(paramIndex) +class DoNotPassAliasedPointerToRestrictQualifiedParamQuery extends DoNotPassAliasedPointerToRestrictQualifiedParamSharedSharedQuery +{ + DoNotPassAliasedPointerToRestrictQualifiedParamQuery() { + this = Pointers3Package::doNotPassAliasedPointerToRestrictQualifiedParamQuery() } - - int getParamIndex() { result = paramIndex } -} - -int getStatedValue(Expr e) { - // `upperBound(e)` defaults to `exprMaxVal(e)` when `e` isn't analyzable. So to get a meaningful - // result in this case we pick the minimum value obtainable from dataflow and range analysis. - result = - upperBound(e) - .minimum(min(Expr source | DataFlow::localExprFlow(source, e) | source.getValue().toInt())) -} - -int getPointerArithmeticOperandStatedValue(CallToFunctionWithRestrictParametersArgExpr expr) { - result = getStatedValue(expr.(PointerArithmeticExpr).getOperand()) - or - // edge-case: &(array[index]) expressions - result = getStatedValue(expr.(AddressOfExpr).getOperand().(PointerArithmeticExpr).getOperand()) - or - // fall-back if `expr` is not a pointer arithmetic expression - not expr instanceof PointerArithmeticExpr and - not expr.(AddressOfExpr).getOperand() instanceof PointerArithmeticExpr and - result = 0 } - -module PointerValueToRestrictArgConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { pointerValue(source.asExpr()) } - - predicate isSink(DataFlow::Node sink) { - exists(CallToFunctionWithRestrictParameters call | - sink.asExpr() = call.getAPtrArg(_).getAChild*() - ) - } - - predicate isBarrierIn(DataFlow::Node node) { - exists(AddressOfExpr a | node.asExpr() = a.getOperand().getAChild*()) - } -} - -module PointerValueToRestrictArgFlow = DataFlow::Global; - -from - CallToFunctionWithRestrictParameters call, CallToFunctionWithRestrictParametersArgExpr arg1, - CallToFunctionWithRestrictParametersArgExpr arg2, int argOffset1, int argOffset2, Expr source1, - Expr source2, string sourceMessage1, string sourceMessage2 -where - not isExcluded(call, Pointers3Package::doNotPassAliasedPointerToRestrictQualifiedParamQuery()) and - arg1 = call.getARestrictPtrArg() and - arg2 = call.getAPtrArg(_) and - // enforce ordering to remove permutations if multiple restrict-qualified args exist - (not arg2 = call.getARestrictPtrArg() or arg2.getParamIndex() > arg1.getParamIndex()) and - ( - // check if two pointers address the same object - PointerValueToRestrictArgFlow::flow(DataFlow::exprNode(source1), - DataFlow::exprNode(arg1.getAChild*())) and - ( - // one pointer value flows to both args - PointerValueToRestrictArgFlow::flow(DataFlow::exprNode(source1), - DataFlow::exprNode(arg2.getAChild*())) and - sourceMessage1 = "$@" and - sourceMessage2 = "source" and - source1 = source2 - or - // there are two separate values that flow from an AddressOfExpr of the same target - getAddressOfExprTargetBase(source1) = getAddressOfExprTargetBase(source2) and - PointerValueToRestrictArgFlow::flow(DataFlow::exprNode(source2), - DataFlow::exprNode(arg2.getAChild*())) and - sourceMessage1 = "a pair of address-of expressions ($@, $@)" and - sourceMessage2 = "addressof1" and - not source1 = source2 - ) - ) and - // get the offset of the pointer arithmetic operand (or '0' if there is none) - argOffset1 = getPointerArithmeticOperandStatedValue(arg1) and - argOffset2 = getPointerArithmeticOperandStatedValue(arg2) and - ( - // case 1: the pointer args are the same. - // (definite aliasing) - argOffset1 = argOffset2 - or - // case 2: the pointer args are different, a size arg exists, - // and the size arg is greater than the difference between the offsets. - // (potential aliasing) - exists(Expr sizeArg | - sizeArg = call.getAPossibleSizeArg() and - getStatedValue(sizeArg) > (argOffset1 - argOffset2).abs() - ) - or - // case 3: the pointer args are different, and a size arg does not exist - // (potential aliasing) - not exists(call.getAPossibleSizeArg()) - ) -select call, - "Call to '" + call.getTarget().getName() + "' passes an $@ to a $@ (pointer value derived from " + - sourceMessage1 + ".", arg2, "aliased pointer", arg1, "restrict-qualified parameter", source1, - sourceMessage2, source2, "addressof2" diff --git a/c/cert/src/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.ql b/c/cert/src/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.ql index bbe41259b8..31618785d2 100644 --- a/c/cert/src/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.ql +++ b/c/cert/src/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.ql @@ -7,14 +7,19 @@ * @problem.severity error * @tags external/cert/id/exp43-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.controlflow.Dominance import codingstandards.c.cert -import codingstandards.c.Variable +import codingstandards.cpp.Variable /** * An `Expr` that is an assignment or initialization to a restrict-qualified pointer-type variable. diff --git a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.ql b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.ql index 32d30a09ad..02d71b3497 100644 --- a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.ql +++ b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/exp44-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.ql b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.ql index f6e29eb28c..c831713486 100644 --- a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.ql +++ b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/exp45-c * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP46-C/DoNotUseABitwiseOperatorWithABooleanLikeOperand.ql b/c/cert/src/rules/EXP46-C/DoNotUseABitwiseOperatorWithABooleanLikeOperand.ql index 040a8bb6ee..549e57236a 100644 --- a/c/cert/src/rules/EXP46-C/DoNotUseABitwiseOperatorWithABooleanLikeOperand.ql +++ b/c/cert/src/rules/EXP46-C/DoNotUseABitwiseOperatorWithABooleanLikeOperand.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/exp46-c * maintainability * readability + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.ql b/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.ql index b9df838b06..81ecf56ccf 100644 --- a/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.ql +++ b/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/fio30-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.ql b/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.ql index 5784e820d9..78817d31e9 100644 --- a/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.ql +++ b/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/fio32-c * correctness * security + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.ql b/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.ql index a55c2dbf29..01c13e642b 100644 --- a/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.ql +++ b/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/fio34-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.ql b/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.ql index 274514e598..3336a059cd 100644 --- a/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.ql +++ b/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/fio34-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql b/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql index 2dce0d465c..ad3a2c8192 100644 --- a/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql +++ b/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/fio37-c * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ @@ -14,7 +19,7 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.FgetsErrorManagement import codingstandards.cpp.Dereferenced -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.DataFlow /* * CFG nodes that follows a successful call to `fgets` diff --git a/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.ql b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.ql index e8e897009e..5b5a043395 100644 --- a/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.ql +++ b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/fio38-c * correctness * security + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql index 668a7d982e..09289d1f79 100644 --- a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql +++ b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/fio39-c * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql index 69fb92a15c..9b0882ac66 100644 --- a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql +++ b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/fio40-c * correctness * security + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ @@ -16,6 +21,7 @@ import cpp import codingstandards.cpp.FgetsErrorManagement import codingstandards.cpp.Dereferenced import codingstandards.c.cert +import semmle.code.cpp.dataflow.DataFlow /* * Models calls to `memcpy` `strcpy` `strncpy` and their wrappers diff --git a/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.ql b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.ql index 7fc1c11d26..5c7d759606 100644 --- a/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.ql +++ b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/fio41-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql index 3650fad82f..26f8aa239d 100644 --- a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql +++ b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/fio42-c * correctness * security + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql index 33a906136f..bc0a417bd0 100644 --- a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql +++ b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql @@ -7,12 +7,17 @@ * @problem.severity error * @tags external/cert/id/fio44-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow class FgetposCall extends FunctionCall { FgetposCall() { this.getTarget().hasGlobalOrStdName("fgetpos") } diff --git a/c/cert/src/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.ql b/c/cert/src/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.ql index 2ddfa6cf4c..85369b502e 100644 --- a/c/cert/src/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.ql +++ b/c/cert/src/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.ql @@ -8,13 +8,18 @@ * @tags external/cert/id/fio45-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert import codingstandards.cpp.standardlibrary.FileAccess -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.valuenumbering.GlobalValueNumbering /** diff --git a/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.ql b/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.ql index 6bc284c2c7..dc52dca487 100644 --- a/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.ql +++ b/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/fio46-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO47-C/UseValidSpecifiers.ql b/c/cert/src/rules/FIO47-C/UseValidSpecifiers.ql index 2062cba2c4..8ed99d4541 100644 --- a/c/cert/src/rules/FIO47-C/UseValidSpecifiers.ql +++ b/c/cert/src/rules/FIO47-C/UseValidSpecifiers.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/fio47-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO47-C/WrongNumberOfFormatArguments.ql b/c/cert/src/rules/FIO47-C/WrongNumberOfFormatArguments.ql index a8b9e9fbac..7266f1fc7c 100644 --- a/c/cert/src/rules/FIO47-C/WrongNumberOfFormatArguments.ql +++ b/c/cert/src/rules/FIO47-C/WrongNumberOfFormatArguments.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/fio47-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO47-C/WrongTypeFormatArguments.ql b/c/cert/src/rules/FIO47-C/WrongTypeFormatArguments.ql index 66cbe409f6..00853abfbc 100644 --- a/c/cert/src/rules/FIO47-C/WrongTypeFormatArguments.ql +++ b/c/cert/src/rules/FIO47-C/WrongTypeFormatArguments.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/fio47-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.ql b/c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.ql index a26736707c..a042d80ba5 100644 --- a/c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.ql +++ b/c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.ql @@ -9,6 +9,11 @@ * maintainability * readability * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/low + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FLP32-C/UncheckedRangeDomainPoleErrors.md b/c/cert/src/rules/FLP32-C/UncheckedRangeDomainPoleErrors.md index d6427b9081..ca24a02498 100644 --- a/c/cert/src/rules/FLP32-C/UncheckedRangeDomainPoleErrors.md +++ b/c/cert/src/rules/FLP32-C/UncheckedRangeDomainPoleErrors.md @@ -345,7 +345,7 @@ Independent( INT34-C, FLP32-C, INT33-C) CWE-682 = Union( FLP32-C, list) where li ## Implementation notes -None +This query identifies possible domain, pole and range errors on a selection of C standard library fuctions from math.h. ## References diff --git a/c/cert/src/rules/FLP32-C/UncheckedRangeDomainPoleErrors.ql b/c/cert/src/rules/FLP32-C/UncheckedRangeDomainPoleErrors.ql index fc054d7289..1e87aa3fae 100644 --- a/c/cert/src/rules/FLP32-C/UncheckedRangeDomainPoleErrors.ql +++ b/c/cert/src/rules/FLP32-C/UncheckedRangeDomainPoleErrors.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/flp32-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FLP34-C/UncheckedFloatingPointConversion.ql b/c/cert/src/rules/FLP34-C/UncheckedFloatingPointConversion.ql index 4637985076..eebc16afe3 100644 --- a/c/cert/src/rules/FLP34-C/UncheckedFloatingPointConversion.ql +++ b/c/cert/src/rules/FLP34-C/UncheckedFloatingPointConversion.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/flp34-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FLP36-C/IntToFloatPreservePrecision.ql b/c/cert/src/rules/FLP36-C/IntToFloatPreservePrecision.ql index e3b98c61c5..81e5670b11 100644 --- a/c/cert/src/rules/FLP36-C/IntToFloatPreservePrecision.ql +++ b/c/cert/src/rules/FLP36-C/IntToFloatPreservePrecision.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/flp36-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FLP37-C/MemcmpUsedToCompareFloats.ql b/c/cert/src/rules/FLP37-C/MemcmpUsedToCompareFloats.ql index 0e3031262e..8735a804fa 100644 --- a/c/cert/src/rules/FLP37-C/MemcmpUsedToCompareFloats.ql +++ b/c/cert/src/rules/FLP37-C/MemcmpUsedToCompareFloats.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/flp37-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/INT30-C/UnsignedIntegerOperationsWrapAround.ql b/c/cert/src/rules/INT30-C/UnsignedIntegerOperationsWrapAround.ql index 3d25313915..c893584a1e 100644 --- a/c/cert/src/rules/INT30-C/UnsignedIntegerOperationsWrapAround.ql +++ b/c/cert/src/rules/INT30-C/UnsignedIntegerOperationsWrapAround.ql @@ -10,29 +10,21 @@ * @tags external/cert/id/int30-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/high + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert -import codingstandards.cpp.Overflow -import semmle.code.cpp.controlflow.Guards -import semmle.code.cpp.valuenumbering.GlobalValueNumbering +import codingstandards.cpp.rules.unsignedoperationwithconstantoperandswraps.UnsignedOperationWithConstantOperandsWraps -from InterestingOverflowingOperation op -where - not isExcluded(op, IntegerOverflowPackage::unsignedIntegerOperationsWrapAroundQuery()) and - op.getType().getUnderlyingType().(IntegralType).isUnsigned() and - // Not within a guard condition - not exists(GuardCondition gc | gc.getAChild*() = op) and - // Not guarded by a check, where the check is not an invalid overflow check - not op.hasValidPreCheck() and - // Is not checked after the operation - not op.hasValidPostCheck() and - // Permitted by exception 3 - not op instanceof LShiftExpr and - // Permitted by exception 2 - zero case is handled in separate query - not op instanceof DivExpr and - not op instanceof RemExpr -select op, - "Operation " + op.getOperator() + " of type " + op.getType().getUnderlyingType() + " may wrap." +class UnsignedIntegerOperationsWrapAroundQuery extends UnsignedOperationWithConstantOperandsWrapsSharedQuery +{ + UnsignedIntegerOperationsWrapAroundQuery() { + this = IntegerOverflowPackage::unsignedIntegerOperationsWrapAroundQuery() + } +} diff --git a/c/cert/src/rules/INT31-C/IntegerConversionCausesDataLoss.ql b/c/cert/src/rules/INT31-C/IntegerConversionCausesDataLoss.ql index 51ae704461..203e60a9e3 100644 --- a/c/cert/src/rules/INT31-C/IntegerConversionCausesDataLoss.ql +++ b/c/cert/src/rules/INT31-C/IntegerConversionCausesDataLoss.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/int31-c * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/INT32-C/SignedIntegerOverflow.md b/c/cert/src/rules/INT32-C/SignedIntegerOverflow.md index dbe36775bf..50a9d01dcd 100644 --- a/c/cert/src/rules/INT32-C/SignedIntegerOverflow.md +++ b/c/cert/src/rules/INT32-C/SignedIntegerOverflow.md @@ -398,7 +398,8 @@ void func(signed long s_a) { } ``` -Risk Assessment + +## Risk Assessment Integer overflow can lead to buffer overflows and the execution of arbitrary code by an attacker. diff --git a/c/cert/src/rules/INT32-C/SignedIntegerOverflow.ql b/c/cert/src/rules/INT32-C/SignedIntegerOverflow.ql index 4c781c4e50..2edee2e5c6 100644 --- a/c/cert/src/rules/INT32-C/SignedIntegerOverflow.ql +++ b/c/cert/src/rules/INT32-C/SignedIntegerOverflow.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/int32-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/high + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/INT33-C/DivOrRemByZero.ql b/c/cert/src/rules/INT33-C/DivOrRemByZero.ql index a5e34f13c4..6090e8842a 100644 --- a/c/cert/src/rules/INT33-C/DivOrRemByZero.ql +++ b/c/cert/src/rules/INT33-C/DivOrRemByZero.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/int33-c * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/INT34-C/ExprShiftedbyNegativeOrGreaterPrecisionOperand.ql b/c/cert/src/rules/INT34-C/ExprShiftedbyNegativeOrGreaterPrecisionOperand.ql index d6445d4937..4260a5e677 100644 --- a/c/cert/src/rules/INT34-C/ExprShiftedbyNegativeOrGreaterPrecisionOperand.ql +++ b/c/cert/src/rules/INT34-C/ExprShiftedbyNegativeOrGreaterPrecisionOperand.ql @@ -7,6 +7,11 @@ * @precision very-high * @problem.severity error * @tags external/cert/id/int34-c + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/INT35-C/UseCorrectIntegerPrecisions.ql b/c/cert/src/rules/INT35-C/UseCorrectIntegerPrecisions.ql index cf510bf999..1bc372506d 100644 --- a/c/cert/src/rules/INT35-C/UseCorrectIntegerPrecisions.ql +++ b/c/cert/src/rules/INT35-C/UseCorrectIntegerPrecisions.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/int35-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/INT36-C/ConvertingAPointerToIntegerOrIntegerToPointer.ql b/c/cert/src/rules/INT36-C/ConvertingAPointerToIntegerOrIntegerToPointer.ql index 3052f0aadd..1cbdcc4e12 100644 --- a/c/cert/src/rules/INT36-C/ConvertingAPointerToIntegerOrIntegerToPointer.ql +++ b/c/cert/src/rules/INT36-C/ConvertingAPointerToIntegerOrIntegerToPointer.ql @@ -7,6 +7,11 @@ * @precision very-high * @problem.severity error * @tags external/cert/id/int36-c + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MEM30-C/DoNotAccessFreedMemory.ql b/c/cert/src/rules/MEM30-C/DoNotAccessFreedMemory.ql index 800ec103ff..59ab0df670 100644 --- a/c/cert/src/rules/MEM30-C/DoNotAccessFreedMemory.ql +++ b/c/cert/src/rules/MEM30-C/DoNotAccessFreedMemory.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/mem30-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MEM31-C/FreeMemoryWhenNoLongerNeededCert.ql b/c/cert/src/rules/MEM31-C/FreeMemoryWhenNoLongerNeededCert.ql index d4c81748a2..18e9478aee 100644 --- a/c/cert/src/rules/MEM31-C/FreeMemoryWhenNoLongerNeededCert.ql +++ b/c/cert/src/rules/MEM31-C/FreeMemoryWhenNoLongerNeededCert.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/mem31-c * correctness * security + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MEM33-C/AllocStructsWithAFlexibleArrayMemberDynamically.ql b/c/cert/src/rules/MEM33-C/AllocStructsWithAFlexibleArrayMemberDynamically.ql index 620c4486a9..2ed5035ff0 100644 --- a/c/cert/src/rules/MEM33-C/AllocStructsWithAFlexibleArrayMemberDynamically.ql +++ b/c/cert/src/rules/MEM33-C/AllocStructsWithAFlexibleArrayMemberDynamically.ql @@ -8,12 +8,18 @@ * @problem.severity error * @tags external/cert/id/mem33-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert import codingstandards.c.Variable +import codingstandards.c.Objects import semmle.code.cpp.models.interfaces.Allocation import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis @@ -21,7 +27,7 @@ abstract class FlexibleArrayAlloc extends Element { /** * Returns the `Variable` being allocated. */ - abstract Variable getVariable(); + abstract Element getReportElement(); } /** @@ -53,18 +59,26 @@ class FlexibleArrayStructDynamicAlloc extends FlexibleArrayAlloc, FunctionCall { ) } - override Variable getVariable() { result = v } + override Element getReportElement() { result = v } } /** * A `Variable` of type `FlexibleArrayStructType` that is not allocated dynamically. */ -class FlexibleArrayNonDynamicAlloc extends FlexibleArrayAlloc, Variable { +class FlexibleArrayNonDynamicAlloc extends FlexibleArrayAlloc { + ObjectIdentity object; + FlexibleArrayNonDynamicAlloc() { - this.getUnspecifiedType().getUnspecifiedType() instanceof FlexibleArrayStructType + this = object and + not object.getStorageDuration().isAllocated() and + // Exclude temporaries. Though they should violate this rule, in practice these results are + // often spurious and redundant, such as (*x = *x) which creates an unused temporary object. + not object.hasTemporaryLifetime() and + object.getType().getUnspecifiedType() instanceof FlexibleArrayStructType and + not exists(Variable v | v.getInitializer().getExpr() = this) } - override Variable getVariable() { result = this } + override Element getReportElement() { result = object } } from FlexibleArrayAlloc alloc, string message @@ -77,4 +91,4 @@ where alloc instanceof FlexibleArrayNonDynamicAlloc and message = "$@ contains a flexible array member but is not dynamically allocated." ) -select alloc, message, alloc.getVariable(), alloc.getVariable().getName() +select alloc, message, alloc.getReportElement(), alloc.getReportElement().toString() diff --git a/c/cert/src/rules/MEM33-C/CopyStructsWithAFlexibleArrayMemberDynamically.ql b/c/cert/src/rules/MEM33-C/CopyStructsWithAFlexibleArrayMemberDynamically.ql index b4993e2cae..b4d2a9127b 100644 --- a/c/cert/src/rules/MEM33-C/CopyStructsWithAFlexibleArrayMemberDynamically.ql +++ b/c/cert/src/rules/MEM33-C/CopyStructsWithAFlexibleArrayMemberDynamically.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/mem33-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MEM34-C/OnlyFreeMemoryAllocatedDynamicallyCert.ql b/c/cert/src/rules/MEM34-C/OnlyFreeMemoryAllocatedDynamicallyCert.ql index 95da1cc86a..78081944be 100644 --- a/c/cert/src/rules/MEM34-C/OnlyFreeMemoryAllocatedDynamicallyCert.ql +++ b/c/cert/src/rules/MEM34-C/OnlyFreeMemoryAllocatedDynamicallyCert.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/mem34-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MEM35-C/InsufficientMemoryAllocatedForObject.ql b/c/cert/src/rules/MEM35-C/InsufficientMemoryAllocatedForObject.ql index 7683140327..06fd267560 100644 --- a/c/cert/src/rules/MEM35-C/InsufficientMemoryAllocatedForObject.ql +++ b/c/cert/src/rules/MEM35-C/InsufficientMemoryAllocatedForObject.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/mem35-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ @@ -16,7 +21,7 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.Overflow import semmle.code.cpp.controlflow.Guards -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import semmle.code.cpp.models.Models /** diff --git a/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql b/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql index 512b783030..90c34a44a2 100644 --- a/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql +++ b/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql @@ -9,13 +9,18 @@ * @tags external/cert/id/mem36-c * correctness * security + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert import codingstandards.cpp.Alignment -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import AlignedAllocToReallocFlow::PathGraph int getStatedValue(Expr e) { diff --git a/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.ql b/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.ql index ed553b9814..722e6fff80 100644 --- a/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.ql +++ b/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/msc30-c * security + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.ql b/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.ql index 2c3db87ee8..85623d9390 100644 --- a/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.ql +++ b/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/msc32-c * security + * external/cert/severity/medium + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.ql b/c/cert/src/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.ql index 52dd0b1046..67fa83e852 100644 --- a/c/cert/src/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.ql +++ b/c/cert/src/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.ql @@ -9,12 +9,17 @@ * @tags external/cert/id/msc33-c * security * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p27 + * external/cert/level/l1 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /** * The argument of a call to `asctime` diff --git a/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.ql b/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.ql index c56f3e48c1..265fc0af55 100644 --- a/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.ql +++ b/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/msc37-c * correctness + * external/cert/severity/high + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MSC38-C/DoNotTreatAPredefinedIdentifierAsObject.ql b/c/cert/src/rules/MSC38-C/DoNotTreatAPredefinedIdentifierAsObject.ql index 76e9c4539f..828f86dd95 100644 --- a/c/cert/src/rules/MSC38-C/DoNotTreatAPredefinedIdentifierAsObject.ql +++ b/c/cert/src/rules/MSC38-C/DoNotTreatAPredefinedIdentifierAsObject.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/msc38-c * correctness * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql b/c/cert/src/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql index 821b79c8e4..56613c1943 100644 --- a/c/cert/src/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql +++ b/c/cert/src/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql @@ -7,13 +7,18 @@ * @problem.severity error * @tags external/cert/id/msc39-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert import codingstandards.cpp.Macro -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow abstract class VaAccess extends Expr { } @@ -71,12 +76,19 @@ predicate sameSource(VaAccess e1, VaAccess e2) { ) } +/** + * Extracted to avoid poor magic join ordering on the `isExcluded` predicate. + */ +predicate query(VaAccess va_acc, VaArgArg va_arg, FunctionCall fc) { + sameSource(va_acc, va_arg) and + fc = preceedsFC(va_acc) and + fc.getTarget().calls*(va_arg.getEnclosingFunction()) +} + from VaAccess va_acc, VaArgArg va_arg, FunctionCall fc where not isExcluded(va_acc, Contracts7Package::doNotCallVaArgOnAVaListThatHasAnIndeterminateValueQuery()) and - sameSource(va_acc, va_arg) and - fc = preceedsFC(va_acc) and - fc.getTarget().calls*(va_arg.getEnclosingFunction()) + query(va_acc, va_arg, fc) select va_acc, "The value of " + va_acc.toString() + " is indeterminate after the $@.", fc, fc.toString() diff --git a/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.md b/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.md new file mode 100644 index 0000000000..f767c91baf --- /dev/null +++ b/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.md @@ -0,0 +1,210 @@ +# MSC40-C: Do not violate inline linkage constraints + +This query implements the CERT-C rule MSC40-C: + +> Do not violate constraints + + +## Description + +According to the C Standard, 3.8 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO%2FIEC9899-2011)\], a constraint is a "restriction, either syntactic or semantic, by which the exposition of language elements is to be interpreted." Despite the similarity of the terms, a runtime constraint is not a kind of constraint. + +Violating any *shall* statement within a constraint clause in the C Standard requires an [implementation](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation) to issue a diagnostic message, the C Standard, 5.1.1.3 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO%2FIEC9899-2011)\] states + +> A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined. Diagnostic messages need not be produced in other circumstances. + + +The C Standard further explains in a footnote + +> The intent is that an implementation should identify the nature of, and where possible localize, each violation. Of course, an implementation is free to produce any number of diagnostics as long as a valid program is still correctly translated. It may also successfully translate an invalid program. + + +Any constraint violation is a violation of this rule because it can result in an invalid program. + +## Noncompliant Code Example (Inline, Internal Linkage) + +The C Standard, 6.7.4, paragraph 3 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO%2FIEC9899-2011)\], states + +> An inline definition of a function with external linkage shall not contain a definition of a modifiable object with static or thread storage duration, and shall not contain a reference to an identifier with internal linkage. + + +The motivation behind this constraint lies in the semantics of inline definitions. Paragraph 7 of subclause 6.7.4 reads, in part: + +> An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition. + + +That is, if a function has an external and inline definition, implementations are free to choose which definition to invoke (two distinct invocations of the function may call different definitions, one the external definition, the other the inline definition). Therefore, issues can arise when these definitions reference internally linked objects or mutable objects with static or thread storage duration. + +This noncompliant code example refers to a static variable with file scope and internal linkage from within an external inline function: + +```cpp +static int I = 12; +extern inline void func(int a) { + int b = a * I; + /* ... */ +} + +``` + +## Compliant Solution (Inline, Internal Linkage) + +This compliant solution omits the `static` qualifier; consequently, the variable `I` has external linkage by default: + +```cpp +int I = 12; +extern inline void func(int a) { + int b = a * I; + /* ... */ +} + +``` + +## Noncompliant Code Example (inline, Modifiable Static) + +This noncompliant code example defines a modifiable `static` variable within an `extern inline` function. + +```cpp +extern inline void func(void) { + static int I = 12; + /* Perform calculations which may modify I */ +} + +``` + +## Compliant Solution (Inline, Modifiable Static) + +This compliant solution removes the `static` keyword from the local variable definition. If the modifications to `I` must be retained between invocations of `func()`, it must be declared at file scope so that it will be defined with external linkage. + +```cpp +extern inline void func(void) { + int I = 12; + /* Perform calculations which may modify I */ +} +``` + +## Noncompliant Code Example (Inline, Modifiable static) + +This noncompliant code example includes two translation units: `file1.c` and `file2.c`. The first file, `file1.c`, defines a pseudorandom number generation function: + +```cpp +/* file1.c */ + +/* Externally linked definition of the function get_random() */ +extern unsigned int get_random(void) { + /* Initialize the seeds */ + static unsigned int m_z = 0xdeadbeef; + static unsigned int m_w = 0xbaddecaf; + + /* Compute the next pseudorandom value and update the seeds */ + m_z = 36969 * (m_z & 65535) + (m_z >> 16); + m_w = 18000 * (m_w & 65535) + (m_w >> 16); + return (m_z << 16) + m_w; +} + +``` +The left-shift operation in the last line may wrap, but this is permitted by exception INT30-C-EX3 to rule [INT30-C. Ensure that unsigned integer operations do not wrap](https://wiki.sei.cmu.edu/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap). + +The second file, `file2.c`, defines an `inline` version of this function that references mutable `static` objects—namely, objects that maintain the state of the pseudorandom number generator. Separate invocations of the `get_random()` function can call different definitions, each operating on separate static objects, resulting in a faulty pseudorandom number generator. + +```cpp +/* file2.c */ + +/* Inline definition of get_random function */ +inline unsigned int get_random(void) { + /* + * Initialize the seeds + * Constraint violation: static duration storage referenced + * in non-static inline definition + */ + static unsigned int m_z = 0xdeadbeef; + static unsigned int m_w = 0xbaddecaf; + + /* Compute the next pseudorandom value and update the seeds */ + m_z = 36969 * (m_z & 65535) + (m_z >> 16); + m_w = 18000 * (m_w & 65535) + (m_w >> 16); + return (m_z << 16) + m_w; +} + +int main(void) { + unsigned int rand_no; + for (int ii = 0; ii < 100; ii++) { + /* + * Get a pseudorandom number. Implementation defined whether the + * inline definition in this file or the external definition + * in file2.c is called. + */ + rand_no = get_random(); + /* Use rand_no... */ + } + + /* ... */ + + /* + * Get another pseudorandom number. Behavior is + * implementation defined. + */ + rand_no = get_random(); + /* Use rand_no... */ + return 0; +} + +``` + +## Compliant Solution (Inline, Modifiable static) + +This compliant solution adds the `static` modifier to the `inline` function definition in `file2.c`, giving it internal linkage. All references to `get_random()` in `file.2.c` will now reference the internally linked definition. The first file, which was not changed, is not shown here. + +```cpp +/* file2.c */ + +/* Static inline definition of get_random function */ +static inline unsigned int get_random(void) { + /* + * Initialize the seeds. + * No more constraint violation; the inline function is now + * internally linked. + */ + static unsigned int m_z = 0xdeadbeef; + static unsigned int m_w = 0xbaddecaf; + + /* Compute the next pseudorandom value and update the seeds */ + m_z = 36969 * (m_z & 65535) + (m_z >> 16); + m_w = 18000 * (m_w & 65535) + (m_w >> 16); + return (m_z << 16) + m_w; +} + +int main(void) { + /* Generate pseudorandom numbers using get_random()... */ + return 0; +} + +``` + +## Risk Assessment + +Constraint violations are a broad category of error that can result in unexpected control flow and corrupted data. + +
Rule Severity Likelihood Remediation Cost Priority Level
MSC40-C Low Unlikely Medium P2 L3
+ + +## Automated Detection + +
Tool Version Checker Description
Astrée 23.04 alignas-extended assignment-to-non-modifiable-lvalue cast-pointer-void-arithmetic-implicit element-type-incomplete function-pointer-integer-cast-implicit function-return-type inappropriate-pointer-cast-implicit incompatible-function-pointer-conversion incompatible-object-pointer-conversion initializer-excess invalid-array-size non-constant-static-assert parameter-match-type pointer-integral-cast-implicit pointer-qualifier-cast-const-implicit pointer-qualifier-cast-volatile-implicit redeclaration return-empty return-non-empty static-assert type-compatibility type-compatibility-link type-specifier undeclared-parameter unnamed-parameter Partially checked
Helix QAC 2023.4 C0232, C0233, C0244, C0268, C0321, C0322, C0338, C0422, C0423, C0426, C0427, C0429, C0430, C0431, C0432, C0435, C0436, C0437, C0446, C0447, C0448, C0449, C0451, C0452, C0453, C0454, C0456, C0457, C0458, C0460, C0461, C0462, C0463, C0466, C0467, C0468, C0469, C0476, C0477, C0478, C0481, C0482, C0483, C0484, C0485, C0486, C0487, C0493, C0494, C0495, C0496, C0497, C0513, C0514, C0515, C0536, C0537, C0540, C0541, C0542, C0546, C0547, C0550, C0554, C0555, C0556, C0557, C0558, C0559, C0560, C0561, C0562, C0563, C0564, C0565, C0580, C0588, C0589, C0590, C0591, C0605, C0616, C0619, C0620, C0621, C0622, C0627, C0628, C0629, C0631, C0638, C0640, C0641, C0642, C0643, C0644, C0645, C0646, C0649, C0650, C0651, C0653, C0655, C0656, C0657, C0659, C0664, C0665, C0669, C0671, C0673, C0674, C0675, C0677, C0682, C0683, C0684, C0685, C0690, C0698, C0699, C0708, C0709, C0736, C0737, C0738, C0746, C0747, C0755, C0756, C0757, C0758, C0766, C0767, C0768, C0774, C0775, C0801, C0802, C0803, C0804, C0811, C0821, C0834, C0835, C0844, C0845, C0851, C0852, C0866, C0873, C0877, C0940, C0941, C0943, C0944, C1023, C1024, C1025, C1033, C1047, C1048, C1050, C1061, C1062, C3236, C3237, C3238, C3244 C++4122
Klocwork 2023.4 MISRA.FUNC.STATIC.REDECL
LDRA tool suite 9.7.1 21 S, 145 S, 323 S, 345 S, 387 S, 404 S, 481 S, 580 S, 612 S, 615 S, 646 S
Parasoft C/C++test 2023.1 CERT_C-MSC40-a An inline definition of a function with external linkage shall not contain definitions and uses of static objects
Polyspace Bug Finder CERT C: Rule MSC40-C Checks for inline constraint not respected (rule partially covered)
RuleChecker 23.04 alignas-extended assignment-to-non-modifiable-lvalue cast-pointer-void-arithmetic-implicit element-type-incomplete function-pointer-integer-cast-implicit function-return-type inappropriate-pointer-cast-implicit incompatible-function-pointer-conversion incompatible-object-pointer-conversion initializer-excess invalid-array-size non-constant-static-assert parameter-match-type pointer-integral-cast-implicit pointer-qualifier-cast-const-implicit pointer-qualifier-cast-volatile-implicit redeclaration return-empty return-non-empty static-assert type-compatibility type-compatibility-link type-specifier undeclared-parameter unnamed-parameter Partially checked
+ + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+MSC40-C). + +## Bibliography + +
\[ ISO/IEC 9899:2011 \] 4, "Conformance" 5.1.1.3, "Diagnostics" 6.7.4, "Function Specifiers"
+ + +## Implementation notes + +This query only considers the constraints related to inline extern functions. + +## References + +* CERT-C: [MSC40-C: Do not violate constraints](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.ql b/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.ql new file mode 100644 index 0000000000..746cea2e9f --- /dev/null +++ b/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.ql @@ -0,0 +1,64 @@ +/** + * @id c/cert/do-not-violate-in-line-linkage-constraints + * @name MSC40-C: Do not violate inline linkage constraints + * @description Inlined external functions are prohibited by the language standard from defining + * modifiable static or thread storage objects, or referencing identifiers with + * internal linkage. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/msc40-c + * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.Linkage + +/* + * This is C specific, because in C++ all extern function definitions must be identical. + * Only in C is it permitted for an extern function to be defined in multiple translation + * units with different implementations, when using the inline keyword. + */ + +from Element accessOrDecl, Variable v, Function f, string message +where + not isExcluded(f, ContractsPackage::doNotViolateInLineLinkageConstraintsQuery()) and + f.isInline() and + hasExternalLinkage(f) and + // Pre-emptively exclude compiler generated functions + not f.isCompilerGenerated() and + // This rule does not apply to C++, but exclude C++ specific cases anyway + not f instanceof MemberFunction and + not f.isFromUninstantiatedTemplate(_) and + ( + // There exists a modifiable local variable which is static or thread local + exists(LocalVariable lsv, string storageModifier | + lsv.isStatic() and storageModifier = "Static" + or + lsv.isThreadLocal() and storageModifier = "Thread-local" + | + lsv.getFunction() = f and + not lsv.isConst() and + accessOrDecl = lsv and + message = storageModifier + " local variable $@ declared" and + v = lsv + ) + or + // References an identifier with internal linkage + exists(GlobalOrNamespaceVariable gv | + accessOrDecl = v.getAnAccess() and + accessOrDecl.(VariableAccess).getEnclosingFunction() = f and + hasInternalLinkage(v) and + message = "Identifier $@ with internal linkage referenced" and + v = gv + ) + ) +select accessOrDecl, message + " in the extern inlined function $@.", v, v.getName(), f, + f.getQualifiedName() diff --git a/c/cert/src/rules/PRE31-C/SideEffectsInArgumentsToUnsafeMacros.ql b/c/cert/src/rules/PRE31-C/SideEffectsInArgumentsToUnsafeMacros.ql index 4ae6619227..322048f6de 100644 --- a/c/cert/src/rules/PRE31-C/SideEffectsInArgumentsToUnsafeMacros.ql +++ b/c/cert/src/rules/PRE31-C/SideEffectsInArgumentsToUnsafeMacros.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/pre31-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ @@ -15,7 +20,6 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.Macro import codingstandards.cpp.SideEffect -import codingstandards.cpp.StructuralEquivalence import codingstandards.cpp.sideeffect.DefaultEffects import codingstandards.cpp.sideeffect.Customizations import semmle.code.cpp.valuenumbering.HashCons diff --git a/c/cert/src/rules/PRE32-C/MacroOrFunctionArgsContainHashToken.ql b/c/cert/src/rules/PRE32-C/MacroOrFunctionArgsContainHashToken.ql index c323c2d31f..0a777dc25d 100644 --- a/c/cert/src/rules/PRE32-C/MacroOrFunctionArgsContainHashToken.ql +++ b/c/cert/src/rules/PRE32-C/MacroOrFunctionArgsContainHashToken.ql @@ -10,6 +10,11 @@ * @tags external/cert/id/pre32-c * correctness * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ @@ -32,11 +37,38 @@ predicate isFunctionSuccessorLocation(ControlFlowNode node, File f, int endline) PreprocessorDirective isLocatedInAFunctionInvocation(FunctionCall c) { exists(PreprocessorDirective p, File f, int startCall, int endCall | isFunctionInvocationLocation(c, f, startCall, endCall) and - exists(int startLine, int endLine | isPreprocDirectiveLine(p, f, startLine, endLine) | - startCall < startLine and - startCall < endLine and - endLine <= endCall and - endLine <= endCall + exists(Expr arg, int preprocStartLine, int preprocEndLine | + c.getAnArgument() = arg and + isPreprocDirectiveLine(p, f, preprocStartLine, preprocEndLine) and + // function call begins before preprocessor directive + startCall < preprocStartLine and + ( + // argument's location is after the preprocessor directive + arg.getLocation().getStartLine() > preprocStartLine + or + // arg's location is before an endif token that is part of a + // preprocessor directive defined before the argument. + // E.g. + // memcpy(dest, src, + // #ifdef SOMEMACRO + // 12 + // #else + // 24 // 'arg' exists here + // #endif // endif after 'arg', but part of a preproc. branch before 'arg' + // ); + p instanceof PreprocessorEndif and + // exists a preprocessor branch of which this is the endif + // and that preprocessor directive exists before + // the argument and after the function call begins. + exists(PreprocessorBranchDirective another | + another.getEndIf() = p and + another.getLocation().getFile() = f and + startCall < another.getLocation().getStartLine() and + arg.getLocation().getStartLine() > another.getLocation().getStartLine() + ) + ) and + // function call ends after preprocessor directive + endCall > preprocEndLine ) and result = p ) diff --git a/c/cert/src/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql b/c/cert/src/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql index 19730b4677..e5dc33f817 100644 --- a/c/cert/src/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql +++ b/c/cert/src/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql @@ -8,13 +8,18 @@ * @tags external/cert/id/sig30-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert import codingstandards.c.Signal -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /** * Does not access an external variable except @@ -32,7 +37,7 @@ class AsyncSafeVariableAccess extends VariableAccess { abstract class AsyncSafeFunction extends Function { } /** - * C standard library ayncronous-safe functions + * C standard library asynchronous-safe functions */ class CAsyncSafeFunction extends AsyncSafeFunction { //tion, or the signal function with the first argument equal to the signal number corresponding to the signal that caused the invocation of the handler @@ -40,7 +45,7 @@ class CAsyncSafeFunction extends AsyncSafeFunction { } /** - * POSIX defined ayncronous-safe functions + * POSIX defined asynchronous-safe functions */ class PosixAsyncSafeFunction extends AsyncSafeFunction { PosixAsyncSafeFunction() { @@ -68,7 +73,7 @@ class PosixAsyncSafeFunction extends AsyncSafeFunction { } /** - * Application defined ayncronous-safe functions + * Application defined asynchronous-safe functions */ class ApplicationAsyncSafeFunction extends AsyncSafeFunction { pragma[nomagic] @@ -117,5 +122,5 @@ where or fc instanceof AsyncUnsafeRaiseCall ) -select fc, "Asyncronous-unsafe function calls within a $@ can lead to undefined behavior.", +select fc, "Asynchronous-unsafe function calls within a $@ can lead to undefined behavior.", handler.getRegistration(), "signal handler" diff --git a/c/cert/src/rules/SIG31-C/DoNotAccessSharedObjectsInSignalHandlers.ql b/c/cert/src/rules/SIG31-C/DoNotAccessSharedObjectsInSignalHandlers.ql index 8f9e907019..eaa0a446b5 100644 --- a/c/cert/src/rules/SIG31-C/DoNotAccessSharedObjectsInSignalHandlers.ql +++ b/c/cert/src/rules/SIG31-C/DoNotAccessSharedObjectsInSignalHandlers.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/sig31-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/high + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ @@ -21,18 +26,19 @@ import codingstandards.c.Signal */ class UnsafeSharedVariableAccess extends VariableAccess { UnsafeSharedVariableAccess() { - // static or thread local storage duration - ( - this.getTarget() instanceof StaticStorageDurationVariable or - this.getTarget().isThreadLocal() - ) and // excluding `volatile sig_atomic_t` type not this.getType().(SigAtomicType).isVolatile() and - // excluding lock-free atomic objects - not exists(MacroInvocation mi, VariableAccess va | - mi.getMacroName() = "atomic_is_lock_free" and - mi.getExpr().getChild(0) = va.getEnclosingElement*() and - va.getTarget() = this.getTarget() + exists(Variable target | target = this.getTarget() | + // static or thread local storage duration + ( + target instanceof StaticStorageDurationVariable or + target.isThreadLocal() + ) and + // excluding lock-free atomic objects + not exists(MacroInvocation mi, VariableAccess va | va.getTarget() = target | + mi.getMacroName() = "atomic_is_lock_free" and + mi.getExpr().getChild(0) = va.getEnclosingElement*() + ) ) } } diff --git a/c/cert/src/rules/SIG34-C/DoNotCallSignalFromInterruptibleSignalHandlers.ql b/c/cert/src/rules/SIG34-C/DoNotCallSignalFromInterruptibleSignalHandlers.ql index d1eb773acb..0586c40c36 100644 --- a/c/cert/src/rules/SIG34-C/DoNotCallSignalFromInterruptibleSignalHandlers.ql +++ b/c/cert/src/rules/SIG34-C/DoNotCallSignalFromInterruptibleSignalHandlers.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/sig34-c * correctness * security + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.ql b/c/cert/src/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.ql index 5a064c0904..bd65019f98 100644 --- a/c/cert/src/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.ql +++ b/c/cert/src/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.ql @@ -8,13 +8,18 @@ * @tags external/cert/id/sig35-c * correctness * security + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/high + * external/cert/priority/p1 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert import codingstandards.c.Signal -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /** * CFG nodes preceeding a `ReturnStmt` diff --git a/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql b/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql index 40f19ed4a0..397e1bfc9e 100644 --- a/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql +++ b/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql @@ -8,13 +8,18 @@ * @tags external/cert/id/str30-c * correctness * security + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert import semmle.code.cpp.security.BufferWrite -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /** * Class that includes into `BufferWrite` functions that will modify their diff --git a/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.ql b/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.ql index 4e2e48708a..437b13f7f9 100644 --- a/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.ql +++ b/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.ql @@ -10,12 +10,17 @@ * @tags external/cert/id/str31-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import codingstandards.cpp.PossiblyUnsafeStringOperation /** diff --git a/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.ql b/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.ql index b5f246ca65..723c8ee0ea 100644 --- a/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.ql +++ b/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.ql @@ -9,13 +9,18 @@ * @tags external/cert/id/str32-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert import codingstandards.cpp.Naming -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import codingstandards.cpp.PossiblyUnsafeStringOperation import semmle.code.cpp.valuenumbering.GlobalValueNumbering diff --git a/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql b/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql index b0d4088f9f..d814951b37 100644 --- a/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql +++ b/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql @@ -9,23 +9,21 @@ * @tags external/cert/id/str34-c * correctness * security + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ import cpp import codingstandards.c.cert -import semmle.code.cpp.commons.CommonType +import codingstandards.cpp.rules.castcharbeforeconvertingtolargersizes.CastCharBeforeConvertingToLargerSizes -from Cast c -where - not isExcluded(c, Strings3Package::castCharBeforeConvertingToLargerSizesQuery()) and - // find cases where there is a conversion happening wherein the - // base type is a char - c.getExpr().getType() instanceof CharType and - not c.getExpr().getType() instanceof UnsignedCharType and - // it's a bigger type - c.getType().getSize() > c.getExpr().getType().getSize() and - // and it's some kind of integer type - c.getType() instanceof IntegralType -select c.getExpr(), - "Expression not converted to `unsigned char` before converting to a larger integer type." +class CastCharBeforeConvertingToLargerSizesQuery extends CastCharBeforeConvertingToLargerSizesSharedQuery +{ + CastCharBeforeConvertingToLargerSizesQuery() { + this = Strings3Package::castCharBeforeConvertingToLargerSizesQuery() + } +} diff --git a/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.ql b/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.ql index 8dda9012d2..a29dbd34b9 100644 --- a/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.ql +++ b/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/str37-c * correctness * security + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.ql b/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.ql index a45f7ec7e1..58b2b1c7dd 100644 --- a/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.ql +++ b/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/str38-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p27 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/test/codeql-pack.lock.yml b/c/cert/test/codeql-pack.lock.yml index 514e6963d0..a45ea8f438 100644 --- a/c/cert/test/codeql-pack.lock.yml +++ b/c/cert/test/codeql-pack.lock.yml @@ -2,13 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.9.3 + version: 4.0.3 codeql/dataflow: - version: 0.0.4 + version: 2.0.3 + codeql/mad: + version: 1.0.19 + codeql/rangeanalysis: + version: 1.0.19 codeql/ssa: - version: 0.1.5 + version: 1.0.19 codeql/tutorial: - version: 0.1.5 + version: 1.0.19 + codeql/typeflow: + version: 1.0.19 + codeql/typetracking: + version: 2.0.3 codeql/util: - version: 0.1.5 + version: 2.0.6 + codeql/xml: + version: 1.0.19 compiled: false diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index 6ff293b9fd..80311bdd57 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.32.0-dev +version: 2.52.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected b/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected index 25153f195b..1617571bbe 100644 --- a/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected +++ b/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected @@ -1,3 +1,5 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (VariableLengthArraySizeNotInValidRange.ql:110,11-19) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (VariableLengthArraySizeNotInValidRange.ql:93,5-18) | test.c:14:8:14:8 | VLA declaration | Variable-length array dimension size may be in an invalid range. | | test.c:15:8:15:8 | VLA declaration | Variable-length array dimension size may be in an invalid range. | | test.c:16:8:16:8 | VLA declaration | Variable-length array dimension size may be in an invalid range. | diff --git a/c/cert/test/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.expected b/c/cert/test/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.expected index 8a7bfe553b..fb0074e0e6 100644 --- a/c/cert/test/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.expected +++ b/c/cert/test/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.expected @@ -1,13 +1,18 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:28,60-68) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:29,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:41,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:49,26-34) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:70,3-11) edges -| test.c:14:38:14:39 | p1 | test.c:18:10:18:11 | v1 | -| test.c:14:38:14:39 | p1 | test.c:19:10:19:11 | v2 | -| test.c:14:38:14:39 | p1 | test.c:20:10:20:11 | p1 | -| test.c:14:38:14:39 | p1 | test.c:21:10:21:11 | p1 | -| test.c:14:38:14:39 | p1 | test.c:22:9:22:10 | p1 | -| test.c:14:38:14:39 | p1 | test.c:23:13:23:14 | p1 | -| test.c:14:38:14:39 | p1 | test.c:24:9:24:10 | p1 | -| test.c:14:38:14:39 | p1 | test.c:25:9:25:10 | p1 | -| test.c:51:30:51:38 | & ... | test.c:14:38:14:39 | p1 | +| test.c:14:38:14:39 | p1 | test.c:18:10:18:11 | v1 | provenance | | +| test.c:14:38:14:39 | p1 | test.c:19:10:19:11 | v2 | provenance | | +| test.c:14:38:14:39 | p1 | test.c:20:10:20:11 | p1 | provenance | | +| test.c:14:38:14:39 | p1 | test.c:21:10:21:11 | p1 | provenance | | +| test.c:14:38:14:39 | p1 | test.c:22:9:22:10 | p1 | provenance | | +| test.c:14:38:14:39 | p1 | test.c:23:13:23:14 | p1 | provenance | | +| test.c:14:38:14:39 | p1 | test.c:24:9:24:10 | p1 | provenance | | +| test.c:14:38:14:39 | p1 | test.c:25:9:25:10 | p1 | provenance | | +| test.c:51:30:51:38 | & ... | test.c:14:38:14:39 | p1 | provenance | | nodes | test.c:14:38:14:39 | p1 | semmle.label | p1 | | test.c:18:10:18:11 | v1 | semmle.label | v1 | diff --git a/c/cert/test/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.expected b/c/cert/test/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.expected index 1d3f5dcf13..0a6471deac 100644 --- a/c/cert/test/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.expected +++ b/c/cert/test/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.expected @@ -1,9 +1,13 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:77,56-64) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:78,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:80,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:89,45-53) edges -| test.c:7:13:7:14 | p1 | test.c:9:9:9:10 | p1 | -| test.c:16:19:16:41 | ... - ... | test.c:18:26:18:31 | offset | -| test.c:16:19:16:41 | ... - ... | test.c:29:6:29:11 | offset | -| test.c:17:17:17:26 | sizeof() | test.c:23:9:23:12 | size | -| test.c:29:6:29:11 | offset | test.c:7:13:7:14 | p1 | +| test.c:7:13:7:14 | p1 | test.c:9:9:9:10 | p1 | provenance | | +| test.c:16:19:16:41 | ... - ... | test.c:18:26:18:31 | offset | provenance | | +| test.c:16:19:16:41 | ... - ... | test.c:29:6:29:11 | offset | provenance | | +| test.c:17:17:17:26 | sizeof() | test.c:23:9:23:12 | size | provenance | | +| test.c:29:6:29:11 | offset | test.c:7:13:7:14 | p1 | provenance | | nodes | test.c:7:13:7:14 | p1 | semmle.label | p1 | | test.c:9:9:9:10 | p1 | semmle.label | p1 | diff --git a/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected b/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected index e03b665a1c..f3ea87136a 100644 --- a/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected +++ b/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected @@ -1,3 +1,9 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:25,46-54) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:26,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:35,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:45,35-43) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:53,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:55,36-44) | test.c:27:3:27:12 | call to tss_create | Resources used by thread specific storage may not be cleaned up. | | test.c:49:3:49:12 | call to tss_create | Resources used by thread specific storage may not be cleaned up. | | test.c:71:3:71:12 | call to tss_create | Resources used by thread specific storage may not be cleaned up. | diff --git a/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected b/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected index c3cdc8bd7b..2cd844f81b 100644 --- a/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected +++ b/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected @@ -1,3 +1,16 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:35,14-22) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:37,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:39,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:42,45-53) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:52,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:52,58-66) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:53,42-50) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:56,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:56,34-42) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:57,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:57,34-42) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:42,9-22) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:52,7-20) | test.c:23:3:23:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:23:24:23:29 | & ... | Shared object | | test.c:74:3:74:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:74:24:74:24 | p | Shared object | | test.c:85:3:85:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:85:24:85:24 | p | Shared object | diff --git a/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected b/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected index 95d0a20041..b2ac853fbf 100644 --- a/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected +++ b/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected @@ -1 +1,6 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:32,38-46) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:35,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:35,30-38) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:36,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:36,30-38) | test.c:14:7:14:13 | call to tss_get | Call to a thread specific storage function from within a threaded context on an object that may not be owned by this thread. | diff --git a/c/cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.qlref b/c/cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.qlref deleted file mode 100644 index 5daa5a5046..0000000000 --- a/c/cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.ql \ No newline at end of file diff --git a/c/cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.testref b/c/cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.testref new file mode 100644 index 0000000000..61fa88fd08 --- /dev/null +++ b/c/cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.testref @@ -0,0 +1 @@ +c/common/test/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.ql \ No newline at end of file diff --git a/c/cert/test/rules/CON40-C/AtomicVariableTwiceInExpression.expected b/c/cert/test/rules/CON40-C/AtomicVariableTwiceInExpression.expected index ddff311b59..42d3ea924d 100644 --- a/c/cert/test/rules/CON40-C/AtomicVariableTwiceInExpression.expected +++ b/c/cert/test/rules/CON40-C/AtomicVariableTwiceInExpression.expected @@ -1,6 +1,6 @@ | test.c:7:18:7:39 | ATOMIC_VAR_INIT(value) | Atomic variable possibly referred to twice in an $@. | test.c:33:3:33:10 | ... += ... | expression | | test.c:7:18:7:39 | ATOMIC_VAR_INIT(value) | Atomic variable possibly referred to twice in an $@. | test.c:34:3:34:13 | ... = ... | expression | -| test.c:11:3:11:23 | atomic_store(a,b) | Atomic variable possibly referred to twice in an $@. | test.c:11:3:11:23 | atomic_store(a,b) | expression | -| test.c:12:3:12:35 | atomic_store_explicit(a,b,c) | Atomic variable possibly referred to twice in an $@. | test.c:12:3:12:35 | atomic_store_explicit(a,b,c) | expression | -| test.c:25:3:25:49 | atomic_compare_exchange_weak(a,b,c) | Atomic variable possibly referred to twice in an $@. | test.c:25:3:25:49 | atomic_compare_exchange_weak(a,b,c) | expression | -| test.c:26:3:27:42 | atomic_compare_exchange_weak_explicit(a,b,c,d,e) | Atomic variable possibly referred to twice in an $@. | test.c:26:3:27:42 | atomic_compare_exchange_weak_explicit(a,b,c,d,e) | expression | +| test.c:11:3:11:23 | atomic_store(object,desired) | Atomic variable possibly referred to twice in an $@. | test.c:11:3:11:23 | atomic_store(object,desired) | expression | +| test.c:12:3:12:23 | atomic_store_explicit | Atomic variable possibly referred to twice in an $@. | test.c:12:3:12:23 | atomic_store_explicit | expression | +| test.c:25:3:25:49 | atomic_compare_exchange_weak(object,expected,desired) | Atomic variable possibly referred to twice in an $@. | test.c:25:3:25:49 | atomic_compare_exchange_weak(object,expected,desired) | expression | +| test.c:26:3:26:39 | atomic_compare_exchange_weak_explicit | Atomic variable possibly referred to twice in an $@. | test.c:26:3:26:39 | atomic_compare_exchange_weak_explicit | expression | diff --git a/c/cert/test/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.expected b/c/cert/test/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.expected index 0c1e25cd00..b1c224173e 100644 --- a/c/cert/test/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.expected +++ b/c/cert/test/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.expected @@ -1,4 +1,4 @@ -| test.c:6:8:6:46 | atomic_compare_exchange_weak(a,b,c) | Function that can spuriously fail not wrapped in a loop. | -| test.c:10:3:10:41 | atomic_compare_exchange_weak(a,b,c) | Function that can spuriously fail not wrapped in a loop. | -| test.c:12:8:13:47 | atomic_compare_exchange_weak_explicit(a,b,c,d,e) | Function that can spuriously fail not wrapped in a loop. | -| test.c:17:3:17:56 | atomic_compare_exchange_weak_explicit(a,b,c,d,e) | Function that can spuriously fail not wrapped in a loop. | +| test.c:6:8:6:46 | atomic_compare_exchange_weak(object,expected,desired) | Function that can spuriously fail not wrapped in a loop. | +| test.c:10:3:10:41 | atomic_compare_exchange_weak(object,expected,desired) | Function that can spuriously fail not wrapped in a loop. | +| test.c:12:8:12:44 | atomic_compare_exchange_weak_explicit | Function that can spuriously fail not wrapped in a loop. | +| test.c:17:3:17:39 | atomic_compare_exchange_weak_explicit | Function that can spuriously fail not wrapped in a loop. | diff --git a/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected b/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected index ff842ddcad..a4359d7000 100644 --- a/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected +++ b/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected @@ -1,2 +1,7 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:33,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:37,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:50,6-14) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:50,26-34) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:56,3-11) | test.c:3:10:3:10 | a | $@ with automatic storage may be accessible outside of its lifetime. | test.c:3:10:3:10 | a | a | | test.c:15:4:15:8 | param [inner post update] | $@ with automatic storage may be accessible outside of its lifetime. | test.c:15:12:15:13 | a2 | a2 | diff --git a/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected b/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected index b6d7caa513..125f55118b 100644 --- a/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected +++ b/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected @@ -1,3 +1,4 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ErrnoReadBeforeReturn.ql:46,7-15) | test.c:69:7:69:11 | * ... | Do not read `errno` before checking the return value of function $@. | test.c:68:3:68:7 | call to ftell | call to ftell | | test.c:69:7:69:11 | call to __errno_location | Do not read `errno` before checking the return value of function $@. | test.c:68:3:68:7 | call to ftell | call to ftell | | test.c:70:5:70:10 | call to perror | Do not read `errno` before checking the return value of function $@. | test.c:68:3:68:7 | call to ftell | call to ftell | diff --git a/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected b/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected index 9ab88a3395..20a7ff60b1 100644 --- a/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected +++ b/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected @@ -1,2 +1,3 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (SetlocaleMightSetErrno.ql:70,7-15) | test.c:98:3:98:11 | call to setlocale | Do not read `errno` before checking the return value of a call to `setlocale`. | | test.c:104:7:104:15 | call to setlocale | The value of `errno` may be different than `0` when `setlocale` is called. The following `errno` check might be invalid. | diff --git a/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected b/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected index da9122cfd4..b79a17ca35 100644 --- a/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected +++ b/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected @@ -1,3 +1,7 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:56,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:56,27-35) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:57,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:60,9-17) | test.c:12:5:12:10 | call to perror | `errno` has indeterminate value after this $@. | test.c:10:21:10:26 | call to signal | call to signal | | test.c:30:5:30:10 | call to perror | `errno` has indeterminate value after this $@. | test.c:26:21:26:26 | call to signal | call to signal | | test.c:49:5:49:10 | call to perror | `errno` has indeterminate value after this $@. | test.c:45:21:45:26 | call to signal | call to signal | diff --git a/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected b/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected index fbcc44b856..f4006c013e 100644 --- a/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected +++ b/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected @@ -1,3 +1,4 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleStandardLibraryErrors.ql:459,5-13) | test.c:18:3:18:11 | call to setlocale | Missing error detection for the call to function `setlocale`. | | test.c:24:23:24:31 | call to setlocale | Missing error detection for the call to function `setlocale`. | | test.c:29:22:29:27 | call to calloc | Missing error detection for the call to function `calloc`. | diff --git a/c/cert/test/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.expected b/c/cert/test/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.expected new file mode 100644 index 0000000000..403d211651 --- /dev/null +++ b/c/cert/test/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.expected @@ -0,0 +1,20 @@ +| test.c:17:7:17:13 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Address of function f1 | +| test.c:20:7:20:12 | ... > ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Address of function f1 | +| test.c:29:7:29:13 | ... == ... | $@ compared to constant value. | test.c:4:8:4:9 | g1 | Function pointer variable g1 | +| test.c:32:7:32:16 | ... == ... | $@ compared to constant value. | test.c:5:7:5:8 | g2 | Function pointer variable g2 | +| test.c:35:7:35:15 | ... != ... | $@ compared to constant value. | test.c:4:8:4:9 | g1 | Function pointer variable g1 | +| test.c:38:7:38:8 | f1 | $@ undergoes implicit constant comparison. | test.c:3:5:3:6 | f1 | Address of function f1 | +| test.c:41:7:41:8 | g1 | $@ undergoes implicit constant comparison. | test.c:4:8:4:9 | g1 | Function pointer variable g1 | +| test.c:68:7:68:27 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Address of function f1 | +| test.c:71:7:71:18 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Address of function f1 | +| test.c:74:7:76:14 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Address of function f1 | +| test.c:83:3:83:9 | ... == ... | $@ compared to constant value. | test.c:82:10:82:11 | l1 | Function pointer variable l1 | +| test.c:84:3:84:12 | ... == ... | $@ compared to constant value. | test.c:82:10:82:11 | l1 | Function pointer variable l1 | +| test.c:91:3:91:4 | g1 | $@ undergoes implicit constant comparison. | test.c:4:8:4:9 | g1 | Function pointer variable g1 | +| test.c:96:7:96:18 | ... == ... | $@ compared to constant value. | test.c:9:9:9:10 | fp | Function pointer variable fp | +| test.c:102:7:102:22 | ... == ... | $@ compared to constant value. | test.c:14:11:14:21 | get_handler | Address of function get_handler | +| test.c:105:7:105:24 | ... == ... | $@ compared to constant value. | test.c:105:7:105:17 | call to get_handler | Expression with function pointer type | +| test.c:121:7:121:13 | ... != ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Address of function f1 | +| test.c:133:7:133:13 | ... != ... | $@ compared to constant value. | test.c:4:8:4:9 | g1 | Function pointer variable g1 | +| test.c:139:7:139:13 | ... == ... | $@ compared to constant value. | test.c:4:8:4:9 | g1 | Function pointer variable g1 | +| test.c:149:8:149:9 | g1 | $@ undergoes implicit constant comparison. | test.c:4:8:4:9 | g1 | Function pointer variable g1 | diff --git a/c/cert/test/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.qlref b/c/cert/test/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.qlref new file mode 100644 index 0000000000..7d99fa9879 --- /dev/null +++ b/c/cert/test/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.qlref @@ -0,0 +1 @@ +rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql \ No newline at end of file diff --git a/c/cert/test/rules/EXP16-C/test.c b/c/cert/test/rules/EXP16-C/test.c new file mode 100644 index 0000000000..16dfea9bc2 --- /dev/null +++ b/c/cert/test/rules/EXP16-C/test.c @@ -0,0 +1,153 @@ +#include + +int f1(); +void (*g1)(void); +int (*g2)(int); +void *g3 = NULL; + +struct S { + int (*fp)(void); + int x; +}; + +typedef int (*handler_t)(void); +handler_t get_handler(void); + +void f2(void) { + if (f1 == 0) // NON-COMPLIANT + return; + + if (f1 > 0) // NON-COMPLIANT + return; + + if (f1() == 0) // COMPLIANT + return; + + if (f1() > 0) // COMPLIANT + return; + + if (g1 == 0) // NON-COMPLIANT + return; + + if (g2 == NULL) // NON-COMPLIANT + return; + + if (g1 != 0x0) // NON-COMPLIANT + return; + + if (f1) // NON-COMPLIANT - implicit comparison + return; + + if (g1) // NON-COMPLIANT - implicit comparison + return; +} + +void f3(void *p1) { + if (g1 == p1) // COMPLIANT - comparing to variable + return; + + if (g2 == g3) // COMPLIANT - comparing to variable + return; +} + +void f4(void) { + int (*l1)(void) = 0; + + if (f1 == f1) // COMPLIANT - comparing to constant value of same type + return; + + if (f1 == l1) // COMPLIANT - comparing to constant value of same type + return; + + if (f1 == (int (*)(void))0) // COMPLIANT - explicit cast + return; + + if (f1 == (int (*)(void))0) // COMPLIANT - explicit cast + return; + + if (f1 == (int (*)(int))0) // NON-COMPLIANT - explicit cast to wrong type + return; + + if (f1 == (int)0) // NON-COMPLIANT - cast to non-function pointer type + return; + + if (f1 == + (int)(int (*)(void)) + NULL) // NON-COMPLIANT - compliant cast subsumed by non-compliant cast + return; +} + +typedef void (*func_t)(void); +void f5(void) { + func_t l1 = g1; + l1 == 0; // NON-COMPLIANT + l1 == NULL; // NON-COMPLIANT + l1 == (func_t)0; // COMPLIANT - cast to function pointer type +} + +void f6(void) { + g1 + 0; // COMPLIANT - not a comparison + g1 == g2; // COMPLIANT - not comparing to constant + g1 ? 1 : 0; // NON-COMPLIANT - implicit comparison +} + +void f7(void) { + struct S s; + if (s.fp == NULL) // NON-COMPLIANT + f1(); + + if (s.fp() == NULL) // COMPLIANT + return; + + if (get_handler == 0) // NON-COMPLIANT - missing parentheses + return; + + if (get_handler() == 0) // NON-COMPLIANT + return; + + if (get_handler() == (handler_t)0) // COMPLIANT + return; + + if (get_handler()() == 0) // COMPLIANT + return; +} + +void f8(void) { + // Test instances of where the function pointer check is used to guard calls + // to that function. + + // Technically, this function may perhaps be set to NULL by the linker. But + // it is not a variable that should need to be null-checked at runtime. + if (f1 != 0) // NON-COMPLIANT + { + f1(); + } + + // Check guards a call, so it is compliant. + if (g1 != 0) // COMPLIANT + { + g1(); + } + + // Incorrect check, not compliant. + if (g1 != 0) // NON-COMPLIANT + { + f1(); + } + + // Incorrect check, not compliant. + if (g1 == 0) // NON-COMPLIANT + { + g1(); + } + + if (g1) // COMPLIANT + { + g1(); + } + + if (!g1) // NON-COMPLIANT + { + g1(); + } +} \ No newline at end of file diff --git a/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected b/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected index 3ea1a05fd7..034f7e9366 100644 --- a/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected +++ b/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected @@ -1 +1,25 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:28,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:28,59-67) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:35,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:35,59-67) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:44,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:44,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:44,53-61) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:47,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:47,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:56,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:56,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:63,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:63,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:75,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:75,55-63) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:28,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,7-20) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:35,7-20) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:47,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:56,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:63,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:75,5-18) | test.c:20:3:20:4 | call to f1 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.c:20:6:20:7 | call to f2 | call to f2 | test.c:20:12:20:13 | call to f3 | call to f3 | diff --git a/c/cert/test/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.expected b/c/cert/test/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.expected index f14ab4de4a..3fb10f3267 100644 --- a/c/cert/test/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.expected +++ b/c/cert/test/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.expected @@ -1,4 +1,4 @@ -| test.c:65:18:65:18 | a | Field access on $@ qualifier occurs after its temporary object lifetime. | test.c:65:9:65:14 | call to get_s1 | function call | -| test.c:67:18:67:19 | s1 | Field access on $@ qualifier occurs after its temporary object lifetime. | test.c:67:9:67:14 | call to get_s3 | function call | -| test.c:68:18:68:19 | i1 | Field access on $@ qualifier occurs after its temporary object lifetime. | test.c:68:9:68:14 | call to get_s3 | function call | -| test.c:69:18:69:21 | af12 | Field access on $@ qualifier occurs after its temporary object lifetime. | test.c:69:9:69:14 | call to get_s4 | function call | +| test.c:65:18:65:18 | a | Field access on $@ qualifier occurs after its temporary object lifetime. | test.c:65:9:65:14 | call to get_s1 | temporary object | +| test.c:67:18:67:19 | s1 | Field access on $@ qualifier occurs after its temporary object lifetime. | test.c:67:9:67:14 | call to get_s3 | temporary object | +| test.c:68:18:68:19 | i1 | Field access on $@ qualifier occurs after its temporary object lifetime. | test.c:68:9:68:14 | call to get_s3 | temporary object | +| test.c:69:18:69:21 | af12 | Field access on $@ qualifier occurs after its temporary object lifetime. | test.c:69:9:69:14 | call to get_s4 | temporary object | diff --git a/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected b/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected index a1c9a14fa2..eb7642ae28 100644 --- a/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected +++ b/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected @@ -1,67 +1,77 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:103,86-94) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:125,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:127,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:132,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:138,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:144,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:145,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:147,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:154,26-34) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:169,44-52) edges -| test.c:75:14:75:16 | & ... | test.c:76:11:76:12 | v1 | -| test.c:75:14:75:16 | & ... | test.c:77:12:77:13 | v1 | -| test.c:75:14:75:16 | & ... | test.c:78:10:78:11 | v1 | -| test.c:75:14:75:16 | & ... | test.c:79:12:79:13 | v1 | -| test.c:75:14:75:16 | & ... | test.c:80:11:80:12 | v1 | -| test.c:75:14:75:16 | & ... | test.c:81:13:81:14 | v1 | -| test.c:84:14:84:16 | & ... | test.c:85:11:85:12 | v2 | -| test.c:84:14:84:16 | & ... | test.c:86:12:86:13 | v2 | -| test.c:84:14:84:16 | & ... | test.c:87:10:87:11 | v2 | -| test.c:84:14:84:16 | & ... | test.c:88:12:88:13 | v2 | -| test.c:84:14:84:16 | & ... | test.c:89:11:89:12 | v2 | -| test.c:84:14:84:16 | & ... | test.c:90:13:90:14 | v2 | -| test.c:93:14:93:16 | & ... | test.c:94:11:94:12 | v3 | -| test.c:93:14:93:16 | & ... | test.c:95:12:95:13 | v3 | -| test.c:93:14:93:16 | & ... | test.c:96:10:96:11 | v3 | -| test.c:93:14:93:16 | & ... | test.c:97:12:97:13 | v3 | -| test.c:93:14:93:16 | & ... | test.c:98:11:98:12 | v3 | -| test.c:93:14:93:16 | & ... | test.c:99:13:99:14 | v3 | -| test.c:102:14:102:16 | & ... | test.c:103:11:103:12 | v4 | -| test.c:102:14:102:16 | & ... | test.c:104:12:104:13 | v4 | -| test.c:102:14:102:16 | & ... | test.c:105:10:105:11 | v4 | -| test.c:102:14:102:16 | & ... | test.c:106:12:106:13 | v4 | -| test.c:102:14:102:16 | & ... | test.c:107:11:107:12 | v4 | -| test.c:102:14:102:16 | & ... | test.c:108:13:108:14 | v4 | -| test.c:111:14:111:16 | & ... | test.c:112:11:112:12 | v5 | -| test.c:111:14:111:16 | & ... | test.c:113:12:113:13 | v5 | -| test.c:111:14:111:16 | & ... | test.c:114:10:114:11 | v5 | -| test.c:111:14:111:16 | & ... | test.c:115:12:115:13 | v5 | -| test.c:111:14:111:16 | & ... | test.c:116:11:116:12 | v5 | -| test.c:111:14:111:16 | & ... | test.c:117:13:117:14 | v5 | -| test.c:120:14:120:16 | & ... | test.c:121:11:121:12 | v6 | -| test.c:120:14:120:16 | & ... | test.c:122:12:122:13 | v6 | -| test.c:120:14:120:16 | & ... | test.c:123:10:123:11 | v6 | -| test.c:120:14:120:16 | & ... | test.c:124:12:124:13 | v6 | -| test.c:120:14:120:16 | & ... | test.c:125:11:125:12 | v6 | -| test.c:120:14:120:16 | & ... | test.c:126:13:126:14 | v6 | -| test.c:129:22:129:22 | v | test.c:130:17:130:17 | v | -| test.c:135:21:135:23 | & ... | test.c:129:22:129:22 | v | -| test.c:138:21:138:23 | & ... | test.c:129:22:129:22 | v | -| test.c:166:24:166:29 | call to malloc | test.c:167:13:167:15 | & ... | -| test.c:166:24:166:29 | call to malloc | test.c:168:16:168:17 | s1 | -| test.c:166:24:166:29 | call to malloc | test.c:169:13:169:14 | s1 | -| test.c:166:24:166:29 | call to malloc | test.c:169:13:169:14 | s1 | -| test.c:169:13:169:14 | s1 | test.c:129:22:129:22 | v | -| test.c:174:13:174:14 | s2 | test.c:129:22:129:22 | v | -| test.c:179:13:179:14 | s3 | test.c:129:22:129:22 | v | -| test.c:183:14:183:26 | call to aligned_alloc | test.c:184:11:184:12 | v1 | -| test.c:183:14:183:26 | call to aligned_alloc | test.c:185:10:185:11 | v1 | -| test.c:183:14:183:26 | call to aligned_alloc | test.c:186:13:186:14 | v1 | -| test.c:183:14:183:26 | call to aligned_alloc | test.c:187:13:187:14 | v1 | -| test.c:187:13:187:14 | v1 | test.c:129:22:129:22 | v | -| test.c:189:14:189:26 | call to aligned_alloc | test.c:190:13:190:14 | v2 | -| test.c:190:13:190:14 | v2 | test.c:129:22:129:22 | v | -| test.c:222:8:222:9 | p2 | test.c:223:11:223:12 | v1 | -| test.c:222:8:222:9 | p2 | test.c:224:12:224:13 | v1 | -| test.c:222:8:222:9 | p2 | test.c:225:10:225:11 | v1 | -| test.c:222:8:222:9 | p2 | test.c:226:12:226:13 | v1 | -| test.c:222:8:222:9 | p2 | test.c:227:11:227:12 | v1 | -| test.c:222:8:222:9 | p2 | test.c:228:13:228:14 | v1 | -| test.c:238:13:238:14 | & ... | test.c:244:12:244:13 | ip | -| test.c:241:15:241:18 | & ... | test.c:247:9:247:12 | & ... | -| test.c:252:16:252:18 | & ... | test.c:254:11:254:13 | ps1 | -| test.c:252:16:252:18 | & ... | test.c:256:10:256:12 | ps1 | +| test.c:75:14:75:16 | & ... | test.c:76:11:76:12 | v1 | provenance | | +| test.c:75:14:75:16 | & ... | test.c:77:12:77:13 | v1 | provenance | | +| test.c:75:14:75:16 | & ... | test.c:78:10:78:11 | v1 | provenance | | +| test.c:75:14:75:16 | & ... | test.c:79:12:79:13 | v1 | provenance | | +| test.c:75:14:75:16 | & ... | test.c:80:11:80:12 | v1 | provenance | | +| test.c:75:14:75:16 | & ... | test.c:81:13:81:14 | v1 | provenance | | +| test.c:84:14:84:16 | & ... | test.c:85:11:85:12 | v2 | provenance | | +| test.c:84:14:84:16 | & ... | test.c:86:12:86:13 | v2 | provenance | | +| test.c:84:14:84:16 | & ... | test.c:87:10:87:11 | v2 | provenance | | +| test.c:84:14:84:16 | & ... | test.c:88:12:88:13 | v2 | provenance | | +| test.c:84:14:84:16 | & ... | test.c:89:11:89:12 | v2 | provenance | | +| test.c:84:14:84:16 | & ... | test.c:90:13:90:14 | v2 | provenance | | +| test.c:93:14:93:16 | & ... | test.c:94:11:94:12 | v3 | provenance | | +| test.c:93:14:93:16 | & ... | test.c:95:12:95:13 | v3 | provenance | | +| test.c:93:14:93:16 | & ... | test.c:96:10:96:11 | v3 | provenance | | +| test.c:93:14:93:16 | & ... | test.c:97:12:97:13 | v3 | provenance | | +| test.c:93:14:93:16 | & ... | test.c:98:11:98:12 | v3 | provenance | | +| test.c:93:14:93:16 | & ... | test.c:99:13:99:14 | v3 | provenance | | +| test.c:102:14:102:16 | & ... | test.c:103:11:103:12 | v4 | provenance | | +| test.c:102:14:102:16 | & ... | test.c:104:12:104:13 | v4 | provenance | | +| test.c:102:14:102:16 | & ... | test.c:105:10:105:11 | v4 | provenance | | +| test.c:102:14:102:16 | & ... | test.c:106:12:106:13 | v4 | provenance | | +| test.c:102:14:102:16 | & ... | test.c:107:11:107:12 | v4 | provenance | | +| test.c:102:14:102:16 | & ... | test.c:108:13:108:14 | v4 | provenance | | +| test.c:111:14:111:16 | & ... | test.c:112:11:112:12 | v5 | provenance | | +| test.c:111:14:111:16 | & ... | test.c:113:12:113:13 | v5 | provenance | | +| test.c:111:14:111:16 | & ... | test.c:114:10:114:11 | v5 | provenance | | +| test.c:111:14:111:16 | & ... | test.c:115:12:115:13 | v5 | provenance | | +| test.c:111:14:111:16 | & ... | test.c:116:11:116:12 | v5 | provenance | | +| test.c:111:14:111:16 | & ... | test.c:117:13:117:14 | v5 | provenance | | +| test.c:120:14:120:16 | & ... | test.c:121:11:121:12 | v6 | provenance | | +| test.c:120:14:120:16 | & ... | test.c:122:12:122:13 | v6 | provenance | | +| test.c:120:14:120:16 | & ... | test.c:123:10:123:11 | v6 | provenance | | +| test.c:120:14:120:16 | & ... | test.c:124:12:124:13 | v6 | provenance | | +| test.c:120:14:120:16 | & ... | test.c:125:11:125:12 | v6 | provenance | | +| test.c:120:14:120:16 | & ... | test.c:126:13:126:14 | v6 | provenance | | +| test.c:129:22:129:22 | v | test.c:130:17:130:17 | v | provenance | | +| test.c:135:21:135:23 | & ... | test.c:129:22:129:22 | v | provenance | | +| test.c:138:21:138:23 | & ... | test.c:129:22:129:22 | v | provenance | | +| test.c:166:24:166:29 | call to malloc | test.c:167:13:167:15 | & ... | provenance | | +| test.c:166:24:166:29 | call to malloc | test.c:168:16:168:17 | s1 | provenance | | +| test.c:166:24:166:29 | call to malloc | test.c:169:13:169:14 | s1 | provenance | | +| test.c:166:24:166:29 | call to malloc | test.c:169:13:169:14 | s1 | provenance | | +| test.c:169:13:169:14 | s1 | test.c:129:22:129:22 | v | provenance | | +| test.c:174:13:174:14 | s2 | test.c:129:22:129:22 | v | provenance | | +| test.c:179:13:179:14 | s3 | test.c:129:22:129:22 | v | provenance | | +| test.c:183:14:183:26 | call to aligned_alloc | test.c:184:11:184:12 | v1 | provenance | | +| test.c:183:14:183:26 | call to aligned_alloc | test.c:185:10:185:11 | v1 | provenance | | +| test.c:183:14:183:26 | call to aligned_alloc | test.c:186:13:186:14 | v1 | provenance | | +| test.c:183:14:183:26 | call to aligned_alloc | test.c:187:13:187:14 | v1 | provenance | | +| test.c:187:13:187:14 | v1 | test.c:129:22:129:22 | v | provenance | | +| test.c:189:14:189:26 | call to aligned_alloc | test.c:190:13:190:14 | v2 | provenance | | +| test.c:190:13:190:14 | v2 | test.c:129:22:129:22 | v | provenance | | +| test.c:222:8:222:9 | p2 | test.c:223:11:223:12 | v1 | provenance | | +| test.c:222:8:222:9 | p2 | test.c:224:12:224:13 | v1 | provenance | | +| test.c:222:8:222:9 | p2 | test.c:225:10:225:11 | v1 | provenance | | +| test.c:222:8:222:9 | p2 | test.c:226:12:226:13 | v1 | provenance | | +| test.c:222:8:222:9 | p2 | test.c:227:11:227:12 | v1 | provenance | | +| test.c:222:8:222:9 | p2 | test.c:228:13:228:14 | v1 | provenance | | +| test.c:238:13:238:14 | & ... | test.c:244:12:244:13 | ip | provenance | | +| test.c:241:15:241:18 | & ... | test.c:247:9:247:12 | & ... | provenance | | +| test.c:252:16:252:18 | & ... | test.c:254:11:254:13 | ps1 | provenance | | +| test.c:252:16:252:18 | & ... | test.c:256:10:256:12 | ps1 | provenance | | nodes | test.c:7:11:7:13 | & ... | semmle.label | & ... | | test.c:8:12:8:14 | & ... | semmle.label | & ... | diff --git a/c/cert/test/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.expected b/c/cert/test/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.expected index 4c18bb2672..8daaf8361a 100644 --- a/c/cert/test/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.expected +++ b/c/cert/test/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.expected @@ -1,11 +1,15 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:45,54-62) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:46,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:50,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:55,43-51) edges -| test.c:48:68:48:70 | fns [f1] | test.c:49:3:49:5 | fns [f1] | -| test.c:49:3:49:5 | fns [f1] | test.c:49:8:49:9 | f1 | -| test.c:61:28:61:29 | f2 | test.c:62:3:62:11 | v1_called | -| test.c:73:3:73:5 | fns [post update] [f1] | test.c:75:45:75:48 | & ... [f1] | -| test.c:73:3:73:13 | ... = ... | test.c:73:3:73:5 | fns [post update] [f1] | -| test.c:73:12:73:13 | v2 | test.c:73:3:73:13 | ... = ... | -| test.c:75:45:75:48 | & ... [f1] | test.c:48:68:48:70 | fns [f1] | +| test.c:48:68:48:70 | fns [f1] | test.c:49:3:49:5 | fns [f1] | provenance | | +| test.c:49:3:49:5 | fns [f1] | test.c:49:8:49:9 | f1 | provenance | | +| test.c:61:28:61:29 | f2 | test.c:62:3:62:11 | v1_called | provenance | | +| test.c:73:3:73:5 | fns [post update] [f1] | test.c:75:45:75:48 | & ... [f1] | provenance | | +| test.c:73:3:73:13 | ... = ... | test.c:73:3:73:5 | fns [post update] [f1] | provenance | | +| test.c:73:12:73:13 | v2 | test.c:73:3:73:13 | ... = ... | provenance | | +| test.c:75:45:75:48 | & ... [f1] | test.c:48:68:48:70 | fns [f1] | provenance | | nodes | test.c:48:68:48:70 | fns [f1] | semmle.label | fns [f1] | | test.c:49:3:49:5 | fns [f1] | semmle.label | fns [f1] | diff --git a/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected b/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected index e42f003f0f..381e409d2a 100644 --- a/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected +++ b/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected @@ -1,15 +1,22 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:66,38-46) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:69,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:74,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:107,23-31) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:116,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:116,45-53) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:138,27-35) edges -| test.c:49:8:49:9 | s3 | test.c:50:8:50:9 | s1 | -| test.c:60:16:60:18 | E1A | test.c:61:16:61:17 | e1 | -| test.c:60:16:60:18 | E1A | test.c:65:10:65:12 | & ... | -| test.c:68:22:68:22 | v | test.c:68:41:68:41 | v | -| test.c:72:13:72:15 | & ... | test.c:68:22:68:22 | v | -| test.c:74:13:74:15 | & ... | test.c:68:22:68:22 | v | -| test.c:97:32:97:37 | call to malloc | test.c:98:40:98:41 | s2 | -| test.c:97:32:97:37 | call to malloc | test.c:98:40:98:41 | s2 | -| test.c:98:32:98:38 | call to realloc | test.c:99:3:99:4 | s3 | -| test.c:98:32:98:38 | call to realloc | test.c:100:10:100:11 | s3 | -| test.c:98:40:98:41 | s2 | test.c:98:32:98:38 | call to realloc | +| test.c:49:8:49:9 | s3 | test.c:50:8:50:9 | s1 | provenance | | +| test.c:60:16:60:18 | E1A | test.c:61:16:61:17 | e1 | provenance | | +| test.c:60:16:60:18 | E1A | test.c:65:10:65:12 | & ... | provenance | | +| test.c:68:22:68:22 | v | test.c:68:41:68:41 | v | provenance | | +| test.c:72:13:72:15 | & ... | test.c:68:22:68:22 | v | provenance | | +| test.c:74:13:74:15 | & ... | test.c:68:22:68:22 | v | provenance | | +| test.c:97:32:97:37 | call to malloc | test.c:98:40:98:41 | s2 | provenance | | +| test.c:97:32:97:37 | call to malloc | test.c:98:40:98:41 | s2 | provenance | | +| test.c:98:32:98:38 | call to realloc | test.c:99:3:99:4 | s3 | provenance | | +| test.c:98:32:98:38 | call to realloc | test.c:100:10:100:11 | s3 | provenance | | +| test.c:98:40:98:41 | s2 | test.c:98:32:98:38 | call to realloc | provenance | Config | nodes | test.c:6:19:6:20 | & ... | semmle.label | & ... | | test.c:11:10:11:11 | & ... | semmle.label | & ... | diff --git a/c/cert/test/rules/EXP40-C/DoNotModifyConstantObjects.expected b/c/cert/test/rules/EXP40-C/DoNotModifyConstantObjects.expected index 3211c4fab1..2ac874e770 100644 --- a/c/cert/test/rules/EXP40-C/DoNotModifyConstantObjects.expected +++ b/c/cert/test/rules/EXP40-C/DoNotModifyConstantObjects.expected @@ -1,11 +1,15 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:40,30-38) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:41,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:47,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:52,19-27) edges -| test.c:5:8:5:9 | & ... | test.c:6:4:6:5 | aa | -| test.c:26:15:26:15 | a | test.c:27:4:27:4 | a | -| test.c:34:13:34:14 | & ... | test.c:39:7:39:8 | p1 | -| test.c:39:7:39:8 | p1 | test.c:26:15:26:15 | a | -| test.c:40:7:40:9 | * ... | test.c:26:15:26:15 | a | -| test.c:59:7:59:8 | & ... | test.c:60:4:60:4 | p | -| test.c:79:11:79:16 | call to strchr | test.c:81:6:81:12 | ... ++ | +| test.c:5:8:5:9 | & ... | test.c:6:4:6:5 | aa | provenance | | +| test.c:26:15:26:15 | a | test.c:27:4:27:4 | a | provenance | | +| test.c:34:13:34:14 | & ... | test.c:39:7:39:8 | p1 | provenance | | +| test.c:39:7:39:8 | p1 | test.c:26:15:26:15 | a | provenance | | +| test.c:40:7:40:9 | * ... | test.c:26:15:26:15 | a | provenance | | +| test.c:59:7:59:8 | & ... | test.c:60:4:60:4 | p | provenance | | +| test.c:79:11:79:16 | call to strchr | test.c:81:6:81:12 | ... ++ | provenance | | nodes | test.c:5:8:5:9 | & ... | semmle.label | & ... | | test.c:6:4:6:5 | aa | semmle.label | aa | diff --git a/c/cert/test/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.qlref b/c/cert/test/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.qlref deleted file mode 100644 index 6121235f17..0000000000 --- a/c/cert/test/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.ql \ No newline at end of file diff --git a/c/cert/test/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.testref b/c/cert/test/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.testref new file mode 100644 index 0000000000..ef17bca58a --- /dev/null +++ b/c/cert/test/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.testref @@ -0,0 +1 @@ +c/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.ql \ No newline at end of file diff --git a/c/cert/test/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.expected b/c/cert/test/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.expected index 3746991c09..40009edc03 100644 --- a/c/cert/test/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.expected +++ b/c/cert/test/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.expected @@ -1,3 +1,10 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:47,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:48,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:52,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:58,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:61,58-66) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:77,64-72) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:78,64-72) | test.c:18:22:18:23 | i2 | Assignment to restrict-qualified pointer $@ results in pointers aliasing $@. | test.c:18:17:18:18 | i3 | i3 | test.c:18:22:18:23 | i2 | the object pointed to by i2 | | test.c:19:8:19:9 | g2 | Assignment to restrict-qualified pointer $@ results in pointers aliasing $@. | test.c:5:15:5:16 | g1 | g1 | test.c:19:8:19:9 | g2 | the object pointed to by g2 | | test.c:20:8:20:9 | i2 | Assignment to restrict-qualified pointer $@ results in pointers aliasing $@. | test.c:16:17:16:18 | i1 | i1 | test.c:20:8:20:9 | i2 | the object pointed to by i2 | diff --git a/c/cert/test/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.expected b/c/cert/test/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.expected index 06bf56cf8a..93d6de6b8a 100644 --- a/c/cert/test/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.expected +++ b/c/cert/test/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.expected @@ -1,12 +1,12 @@ edges -| test.c:20:15:20:23 | scanf output argument | test.c:21:8:21:16 | file_name indirection | -| test.c:45:15:45:23 | scanf output argument | test.c:46:29:46:37 | file_name indirection | +| test.c:20:15:20:23 | scanf output argument | test.c:21:8:21:16 | *file_name | provenance | | +| test.c:45:15:45:23 | scanf output argument | test.c:46:29:46:37 | *file_name | provenance | | nodes | test.c:20:15:20:23 | scanf output argument | semmle.label | scanf output argument | -| test.c:21:8:21:16 | file_name indirection | semmle.label | file_name indirection | +| test.c:21:8:21:16 | *file_name | semmle.label | *file_name | | test.c:45:15:45:23 | scanf output argument | semmle.label | scanf output argument | -| test.c:46:29:46:37 | file_name indirection | semmle.label | file_name indirection | +| test.c:46:29:46:37 | *file_name | semmle.label | *file_name | subpaths #select -| test.c:21:8:21:16 | file_name | test.c:20:15:20:23 | scanf output argument | test.c:21:8:21:16 | file_name indirection | This argument to a file access function is derived from $@ and then passed to func(file_name), which calls fopen((unnamed parameter 0)). | test.c:20:15:20:23 | scanf output argument | user input (value read by scanf) | -| test.c:46:29:46:37 | file_name | test.c:45:15:45:23 | scanf output argument | test.c:46:29:46:37 | file_name indirection | This argument to a file access function is derived from $@ and then passed to CreateFile(lpFileName). | test.c:45:15:45:23 | scanf output argument | user input (value read by scanf) | +| test.c:21:8:21:16 | file_name | test.c:20:15:20:23 | scanf output argument | test.c:21:8:21:16 | *file_name | This argument to a file access function is derived from $@ and then passed to func(file_name), which calls fopen((unnamed parameter 0)). | test.c:20:15:20:23 | scanf output argument | user input (value read by scanf) | +| test.c:46:29:46:37 | file_name | test.c:45:15:45:23 | scanf output argument | test.c:46:29:46:37 | *file_name | This argument to a file access function is derived from $@ and then passed to CreateFile(lpFileName). | test.c:45:15:45:23 | scanf output argument | user input (value read by scanf) | diff --git a/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected b/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected index 20c108cfa0..52cb85e5c4 100644 --- a/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected +++ b/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected @@ -1,3 +1,6 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:48,11-19) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:48,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:49,13-21) | test.c:20:10:20:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:15:7:15:11 | call to fgets | call to fgets | | test.c:57:10:57:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:52:7:52:11 | call to fgets | call to fgets | | test.c:66:18:66:20 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:61:7:61:11 | call to fgets | call to fgets | diff --git a/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected b/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected index 8074710738..ec05727161 100644 --- a/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected +++ b/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected @@ -1,2 +1,7 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:30,32-40) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:31,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:33,14-22) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:36,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:42,21-29) | test.c:7:24:7:30 | & ... | The position argument of a call to `fsetpos()` should be obtained from a call to `fgetpos()`. | | test.c:33:24:33:30 | & ... | The position argument of a call to `fsetpos()` should be obtained from a call to `fgetpos()`. | diff --git a/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.expected b/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.expected index 1b2923b780..a211aa4002 100644 --- a/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.expected +++ b/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.expected @@ -1,2 +1,3 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ToctouRaceConditionsWhileAccessingFiles.ql:32,35-43) | test.c:4:13:4:17 | call to fopen | This call is trying to prevent an existing file from being overwritten by $@. An attacker might be able to exploit the race window between the two calls. | test.c:11:9:11:13 | call to fopen | another call | | test.c:88:13:88:17 | call to fopen | This call is trying to prevent an existing file from being overwritten by $@. An attacker might be able to exploit the race window between the two calls. | test.c:95:9:95:13 | call to fopen | another call | diff --git a/c/cert/test/rules/INT30-C/UnsignedIntegerOperationsWrapAround.expected b/c/cert/test/rules/INT30-C/UnsignedIntegerOperationsWrapAround.expected deleted file mode 100644 index 76594d944b..0000000000 --- a/c/cert/test/rules/INT30-C/UnsignedIntegerOperationsWrapAround.expected +++ /dev/null @@ -1,4 +0,0 @@ -| test.c:4:3:4:9 | ... + ... | Operation + of type unsigned int may wrap. | -| test.c:5:3:5:10 | ... += ... | Operation += of type unsigned int may wrap. | -| test.c:58:3:58:9 | ... - ... | Operation - of type unsigned int may wrap. | -| test.c:59:3:59:10 | ... -= ... | Operation -= of type unsigned int may wrap. | diff --git a/c/cert/test/rules/INT30-C/UnsignedIntegerOperationsWrapAround.qlref b/c/cert/test/rules/INT30-C/UnsignedIntegerOperationsWrapAround.qlref deleted file mode 100644 index 045890904c..0000000000 --- a/c/cert/test/rules/INT30-C/UnsignedIntegerOperationsWrapAround.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/INT30-C/UnsignedIntegerOperationsWrapAround.ql \ No newline at end of file diff --git a/c/cert/test/rules/INT30-C/UnsignedIntegerOperationsWrapAround.testref b/c/cert/test/rules/INT30-C/UnsignedIntegerOperationsWrapAround.testref new file mode 100644 index 0000000000..c9bc9d9637 --- /dev/null +++ b/c/cert/test/rules/INT30-C/UnsignedIntegerOperationsWrapAround.testref @@ -0,0 +1 @@ +c/common/test/rules/unsignedoperationwithconstantoperandswraps/UnsignedOperationWithConstantOperandsWraps.ql \ No newline at end of file diff --git a/c/cert/test/rules/INT30-C/test.c b/c/cert/test/rules/INT30-C/test.c deleted file mode 100644 index 433cf534f4..0000000000 --- a/c/cert/test/rules/INT30-C/test.c +++ /dev/null @@ -1,80 +0,0 @@ -#include - -void test_add_simple(unsigned int i1, unsigned int i2) { - i1 + i2; // NON_COMPLIANT - not bounds checked - i1 += i2; // NON_COMPLIANT - not bounds checked -} - -void test_add_precheck(unsigned int i1, unsigned int i2) { - if (UINT_MAX - i1 < i2) { - // handle error - } else { - i1 + i2; // COMPLIANT - bounds checked - i1 += i2; // COMPLIANT - bounds checked - } -} - -void test_add_precheck_2(unsigned int i1, unsigned int i2) { - if (i1 + i2 < i1) { - // handle error - } else { - i1 + i2; // COMPLIANT - bounds checked - i1 += i2; // COMPLIANT - bounds checked - } -} - -void test_add_postcheck(unsigned int i1, unsigned int i2) { - unsigned int i3 = i1 + i2; // COMPLIANT - checked for overflow afterwards - if (i3 < i1) { - // handle error - } - i1 += i2; // COMPLIANT - checked for overflow afterwards - if (i1 < i2) { - // handle error - } -} - -void test_ex2(unsigned int i1, unsigned int i2) { - unsigned int ci1 = 2; - unsigned int ci2 = 3; - ci1 + ci2; // COMPLIANT, compile time constants - i1 + 0; // COMPLIANT - i1 += 0; // COMPLIANT - i1 - 0; // COMPLIANT - i1 -= 0; // COMPLIANT - UINT_MAX - i1; // COMPLIANT - cannot be smaller than 0 - i1 * 1; // COMPLIANT - i1 *= 1; // COMPLIANT - if (0 <= i1 && i1 < 32) { - UINT_MAX >> i1; // COMPLIANT - } -} - -void test_ex3(unsigned int i1, unsigned int i2) { - i1 << i2; // COMPLIANT - by EX3 -} - -void test_sub_simple(unsigned int i1, unsigned int i2) { - i1 - i2; // NON_COMPLIANT - not bounds checked - i1 -= i2; // NON_COMPLIANT - not bounds checked -} - -void test_sub_precheck(unsigned int i1, unsigned int i2) { - if (i1 < i2) { - // handle error - } else { - i1 - i2; // COMPLIANT - bounds checked - i1 -= i2; // COMPLIANT - bounds checked - } -} - -void test_sub_postcheck(unsigned int i1, unsigned int i2) { - unsigned int i3 = i1 - i2; // COMPLIANT - checked for wrap afterwards - if (i3 > i1) { - // handle error - } - i1 -= i2; // COMPLIANT - checked for wrap afterwards - if (i1 > i2) { - // handle error - } -} \ No newline at end of file diff --git a/c/cert/test/rules/MEM35-C/InsufficientMemoryAllocatedForObject.expected b/c/cert/test/rules/MEM35-C/InsufficientMemoryAllocatedForObject.expected index 30dece9299..86bdeedf5f 100644 --- a/c/cert/test/rules/MEM35-C/InsufficientMemoryAllocatedForObject.expected +++ b/c/cert/test/rules/MEM35-C/InsufficientMemoryAllocatedForObject.expected @@ -1,3 +1,5 @@ +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (InsufficientMemoryAllocatedForObject.ql:90,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (InsufficientMemoryAllocatedForObject.ql:148,5-18) | test.c:12:19:12:24 | call to malloc | Allocation size (32 bytes) is not a multiple of the size of 'S1' (36 bytes). | test.c:12:26:12:32 | 32 | | | test.c:15:19:15:24 | call to malloc | Allocation size calculated from the size of a different type ($@). | test.c:15:26:15:35 | sizeof() | sizeof(S1 *) | | test.c:20:19:20:24 | call to malloc | Allocation size (128 bytes) is not a multiple of the size of 'S1' (36 bytes). | test.c:20:26:20:36 | ... * ... | | diff --git a/c/cert/test/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.expected b/c/cert/test/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.expected index 0592cb038d..587ae786d1 100644 --- a/c/cert/test/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.expected +++ b/c/cert/test/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.expected @@ -1,9 +1,14 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:31,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:45,47-55) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:46,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:50,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:55,36-44) edges -| test.c:5:10:5:22 | call to aligned_alloc | test.c:15:8:15:28 | call to aligned_alloc_wrapper | -| test.c:8:29:8:31 | ptr | test.c:8:64:8:66 | ptr | -| test.c:15:8:15:28 | call to aligned_alloc_wrapper | test.c:16:24:16:25 | v1 | -| test.c:16:24:16:25 | v1 | test.c:8:29:8:31 | ptr | -| test.c:22:8:22:20 | call to aligned_alloc | test.c:23:16:23:17 | v3 | +| test.c:5:10:5:22 | call to aligned_alloc | test.c:15:8:15:28 | call to aligned_alloc_wrapper | provenance | | +| test.c:8:29:8:31 | ptr | test.c:8:64:8:66 | ptr | provenance | | +| test.c:15:8:15:28 | call to aligned_alloc_wrapper | test.c:16:24:16:25 | v1 | provenance | | +| test.c:16:24:16:25 | v1 | test.c:8:29:8:31 | ptr | provenance | | +| test.c:22:8:22:20 | call to aligned_alloc | test.c:23:16:23:17 | v3 | provenance | | nodes | test.c:5:10:5:22 | call to aligned_alloc | semmle.label | call to aligned_alloc | | test.c:8:29:8:31 | ptr | semmle.label | ptr | diff --git a/c/cert/test/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.testref b/c/cert/test/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.testref index 31cba60b74..726f27535d 100644 --- a/c/cert/test/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.testref +++ b/c/cert/test/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.testref @@ -1 +1 @@ -cpp/common/test/rules/donotuserandforgeneratingpseudorandomnumbers/DoNotUseRandForGeneratingPseudorandomNumbers.ql \ No newline at end of file +c/common/test/rules/donotuserandforgeneratingpseudorandomnumbers/DoNotUseRandForGeneratingPseudorandomNumbers.ql \ No newline at end of file diff --git a/c/cert/test/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.expected b/c/cert/test/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.expected index 70d60c528a..7ebeb7a8c1 100644 --- a/c/cert/test/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.expected +++ b/c/cert/test/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.expected @@ -1 +1,5 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:38,38-46) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:39,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:46,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:49,27-35) | test.c:6:24:6:30 | time_tm | The function `asctime` and `asctime_r` should be discouraged. Unsanitized input can overflow the output buffer. | diff --git a/c/cert/test/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.expected b/c/cert/test/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.expected index 2b7bb2bdbc..4e14eb2873 100644 --- a/c/cert/test/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.expected +++ b/c/cert/test/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.expected @@ -1,3 +1,10 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:43,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:44,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:49,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:52,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:73,10-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:74,29-37) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:75,29-37) | test.c:23:32:23:33 | ap | The value of ap is indeterminate after the $@. | test.c:17:7:17:19 | call to contains_zero | call to contains_zero | | test.c:26:10:26:11 | ap | The value of ap is indeterminate after the $@. | test.c:17:7:17:19 | call to contains_zero | call to contains_zero | | test.c:39:12:39:13 | ap | The value of ap is indeterminate after the $@. | test.c:35:7:35:19 | call to contains_zero | call to contains_zero | diff --git a/c/cert/test/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.expected b/c/cert/test/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.expected new file mode 100644 index 0000000000..f258d4adef --- /dev/null +++ b/c/cert/test/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.expected @@ -0,0 +1,6 @@ +| test.c:6:14:6:14 | i | Static local variable $@ declared in the extern inlined function $@. | test.c:6:14:6:14 | i | i | test.c:5:20:5:24 | test1 | test1 | +| test.c:7:3:7:4 | g1 | Identifier $@ with internal linkage referenced in the extern inlined function $@. | test.c:1:12:1:13 | g1 | g1 | test.c:5:20:5:24 | test1 | test1 | +| test.c:9:3:9:4 | g3 | Identifier $@ with internal linkage referenced in the extern inlined function $@. | test.c:3:11:3:12 | g3 | g3 | test.c:5:20:5:24 | test1 | test1 | +| test.c:27:14:27:14 | i | Static local variable $@ declared in the extern inlined function $@. | test.c:27:14:27:14 | i | i | test.c:26:13:26:17 | test4 | test4 | +| test.c:28:3:28:4 | g1 | Identifier $@ with internal linkage referenced in the extern inlined function $@. | test.c:1:12:1:13 | g1 | g1 | test.c:26:13:26:17 | test4 | test4 | +| test.c:30:3:30:4 | g3 | Identifier $@ with internal linkage referenced in the extern inlined function $@. | test.c:3:11:3:12 | g3 | g3 | test.c:26:13:26:17 | test4 | test4 | diff --git a/c/cert/test/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.qlref b/c/cert/test/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.qlref new file mode 100644 index 0000000000..f14d4270cc --- /dev/null +++ b/c/cert/test/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.qlref @@ -0,0 +1 @@ +rules/MSC40-C/DoNotViolateInLineLinkageConstraints.ql \ No newline at end of file diff --git a/c/cert/test/rules/MSC40-C/test.c b/c/cert/test/rules/MSC40-C/test.c new file mode 100644 index 0000000000..d892935d41 --- /dev/null +++ b/c/cert/test/rules/MSC40-C/test.c @@ -0,0 +1,31 @@ +static int g1 = 0; +extern int g2 = 1; +const int g3 = 1; // defaults to internal linkage + +extern inline void test1() { + static int i = 0; // NON_COMPLIANT + g1++; // NON_COMPLIANT + g2++; // COMPLIANT + g3; // NON_COMPLIANT +} + +extern void test2() { + static int i = 0; // COMPLIANT + g1++; // COMPLIANT + g2++; // COMPLIANT + g3; // COMPLIANT +} + +void test3() { + static int i = 0; // COMPLIANT + g1++; // COMPLIANT + g2++; // COMPLIANT + g3; // COMPLIANT +} + +inline void test4() { + static int i = 0; // NON_COMPLIANT + g1++; // NON_COMPLIANT + g2++; // COMPLIANT + g3; // NON_COMPLIANT +} \ No newline at end of file diff --git a/c/cert/test/rules/PRE32-C/MacroOrFunctionArgsContainHashToken.expected b/c/cert/test/rules/PRE32-C/MacroOrFunctionArgsContainHashToken.expected index f25c7ea0e0..efbf021972 100644 --- a/c/cert/test/rules/PRE32-C/MacroOrFunctionArgsContainHashToken.expected +++ b/c/cert/test/rules/PRE32-C/MacroOrFunctionArgsContainHashToken.expected @@ -4,5 +4,3 @@ | test.c:20:1:20:16 | #ifdef SOMEMACRO | Invocation of function memcpy includes a token "#ifdef SOMEMACRO" that could be confused for an argument preprocessor directive. | | test.c:22:1:22:5 | #else | Invocation of function memcpy includes a token "#else" that could be confused for an argument preprocessor directive. | | test.c:24:1:24:6 | #endif | Invocation of function memcpy includes a token "#endif" that could be confused for an argument preprocessor directive. | -| test.c:27:1:27:8 | #if TEST | Invocation of function memcpy includes a token "#if TEST" that could be confused for an argument preprocessor directive. | -| test.c:28:1:28:6 | #endif | Invocation of function memcpy includes a token "#endif" that could be confused for an argument preprocessor directive. | diff --git a/c/cert/test/rules/PRE32-C/test.c b/c/cert/test/rules/PRE32-C/test.c index af3606f24c..bf07beecb5 100644 --- a/c/cert/test/rules/PRE32-C/test.c +++ b/c/cert/test/rules/PRE32-C/test.c @@ -24,6 +24,6 @@ void func(const char *src) { #endif // NON_COMPLIANT ); -#if TEST // COMPLIANT[FALSE_POSITIVE] -#endif // COMPLIANT[FALSE_POSITIVE] -} \ No newline at end of file +#if TEST // COMPLIANT +#endif // COMPLIANT +} diff --git a/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected b/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected index a601fe63f4..ce13ee69a7 100644 --- a/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected +++ b/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected @@ -1,4 +1,7 @@ -| test.c:10:3:10:18 | call to log_local_unsafe | Asyncronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:16:7:16:12 | call to signal | signal handler | -| test.c:11:3:11:6 | call to free | Asyncronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:16:7:16:12 | call to signal | signal handler | -| test.c:46:3:46:9 | call to longjmp | Asyncronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:50:7:50:12 | call to signal | signal handler | -| test.c:76:7:76:11 | call to raise | Asyncronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:91:7:91:12 | call to signal | signal handler | +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:110,11-19) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:110,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:111,9-17) +| test.c:10:3:10:18 | call to log_local_unsafe | Asynchronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:16:7:16:12 | call to signal | signal handler | +| test.c:11:3:11:6 | call to free | Asynchronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:16:7:16:12 | call to signal | signal handler | +| test.c:46:3:46:9 | call to longjmp | Asynchronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:50:7:50:12 | call to signal | signal handler | +| test.c:76:7:76:11 | call to raise | Asynchronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:91:7:91:12 | call to signal | signal handler | diff --git a/c/cert/test/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.expected b/c/cert/test/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.expected index 31412c466a..fb78049d25 100644 --- a/c/cert/test/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.expected +++ b/c/cert/test/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.expected @@ -1 +1,2 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotReturnFromAComputationalExceptionHandler.ql:44,5-13) | test.c:10:1:10:1 | return ... | Do not return from a $@ signal handler. | test.c:13:10:13:15 | SIGFPE | computational exception | diff --git a/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected b/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected index 27ef66bc7a..d95b48e1c3 100644 --- a/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected +++ b/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected @@ -1,3 +1,18 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:47,65-73) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:48,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:69,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:82,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:106,11-19) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:106,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:106,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:111,11-19) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:111,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:111,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:144,11-19) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:144,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:144,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:155,53-61) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:156,5-13) | test.c:7:3:7:3 | a | This operation may write to a string that may be a string literal that was $@. | test.c:6:13:6:20 | codeql | created here | | test.c:30:3:30:3 | a | This operation may write to a string that may be a string literal that was $@. | test.c:29:13:29:18 | call to strchr | created here | | test.c:36:3:36:3 | b | This operation may write to a string that may be a string literal that was $@. | test.c:35:13:35:18 | call to strchr | created here | diff --git a/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected b/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected index 71e713d120..9a87a6775b 100644 --- a/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected +++ b/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected @@ -1,3 +1,9 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:62,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:62,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:68,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:68,54-62) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:62,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:68,5-18) | test.c:10:20:10:24 | Cod | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | | test.c:16:3:16:9 | call to strncpy | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | | test.c:26:3:26:10 | call to snprintf | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | diff --git a/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected b/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected index 8409d95628..f537cc72ac 100644 --- a/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected +++ b/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected @@ -1,3 +1,13 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:69,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:71,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:79,39-47) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:80,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:86,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:88,34-42) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:88,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:128,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:128,26-34) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:125,17-30) | test.c:20:3:20:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:8:20:8:24 | Cod | this expression | | test.c:21:3:21:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:8:20:8:24 | Cod | this expression | | test.c:23:3:23:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:14:3:14:9 | call to strncpy | this expression | diff --git a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected b/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected deleted file mode 100644 index 1c6424dc0c..0000000000 --- a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected +++ /dev/null @@ -1,21 +0,0 @@ -| test.c:7:7:7:14 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:28:11:28:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:29:3:29:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:29:11:29:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:31:11:31:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:32:11:32:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:33:3:33:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:33:11:33:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:34:3:34:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:34:11:34:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:35:3:35:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:35:11:35:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:36:3:36:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:36:11:36:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:37:11:37:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:38:11:38:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:39:3:39:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:39:11:39:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:40:12:40:13 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:42:11:42:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:43:11:43:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | diff --git a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qlref b/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qlref deleted file mode 100644 index 379d3b3f68..0000000000 --- a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql \ No newline at end of file diff --git a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.testref b/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.testref new file mode 100644 index 0000000000..0e13e05dc3 --- /dev/null +++ b/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.testref @@ -0,0 +1 @@ +c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.ql \ No newline at end of file diff --git a/c/cert/test/rules/STR34-C/test.c b/c/cert/test/rules/STR34-C/test.c deleted file mode 100644 index d4bd825c8e..0000000000 --- a/c/cert/test/rules/STR34-C/test.c +++ /dev/null @@ -1,109 +0,0 @@ -#include -#include - -int f1() { - char *c_str; - int c; - c = *c_str++; // NON_COMPLIANT - return (c); -} - -int f2() { - unsigned char *c_str; - int c; - c = *c_str++; // COMPLIANT - return (c); -} - -int f3(void) { - char *c_str; - int c; - c = (unsigned char)*c_str++; // COMPLIANT - return (c); -} - -void f4() { - char *t; - - isalnum(*t); // NON_COMPLIANT - isalpha(*t); // NON_COMPLIANT - // isascii(*t); // Not part of the C Standard - isblank(*t); // NON_COMPLIANT - iscntrl(*t); // NON_COMPLIANT - isdigit(*t); // NON_COMPLIANT - isgraph(*t); // NON_COMPLIANT - islower(*t); // NON_COMPLIANT - isprint(*t); // NON_COMPLIANT - ispunct(*t); // NON_COMPLIANT - isspace(*t); // NON_COMPLIANT - isupper(*t); // NON_COMPLIANT - isxdigit(*t); // NON_COMPLIANT - // toascii(i); // Not part of the C Standard - toupper(*t); // NON_COMPLIANT - tolower(*t); // NON_COMPLIANT -} - -void f5() { - unsigned char *t; - - isalnum(*t); // COMPLIANT - isalpha(*t); // COMPLIANT - // isascii(*t); // Not part of the C Standard - isblank(*t); // COMPLIANT - iscntrl(*t); // COMPLIANT - isdigit(*t); // COMPLIANT - isgraph(*t); // COMPLIANT - islower(*t); // COMPLIANT - isprint(*t); // COMPLIANT - ispunct(*t); // COMPLIANT - isspace(*t); // COMPLIANT - isupper(*t); // COMPLIANT - isxdigit(*t); // COMPLIANT - // toascii(i); // Not part of the C Standard - toupper(*t); // COMPLIANT - tolower(*t); // COMPLIANT -} - -void f6() { - char *t; - - isalnum((unsigned char)*t); // COMPLIANT - isalpha((unsigned char)*t); // COMPLIANT - // isascii((unsigned char*)*t); // Not part of the C Standard - isblank((unsigned char)*t); // COMPLIANT - iscntrl((unsigned char)*t); // COMPLIANT - isdigit((unsigned char)*t); // COMPLIANT - isgraph((unsigned char)*t); // COMPLIANT - islower((unsigned char)*t); // COMPLIANT - isprint((unsigned char)*t); // COMPLIANT - ispunct((unsigned char)*t); // COMPLIANT - isspace((unsigned char)*t); // COMPLIANT - isupper((unsigned char)*t); // COMPLIANT - isxdigit((unsigned char)*t); // COMPLIANT - // toascii((unsigned int) i); // Not part of the C Standard - toupper((unsigned char)*t); // COMPLIANT - tolower((unsigned char)*t); // COMPLIANT -} - -void f7() { - int t; - - // Note these are all NON_COMPLIANT under STR37-C - - isalnum(t); // COMPLIANT - isalpha(t); // COMPLIANT - // isascii(t); // Not part of the C Standard - isblank(t); // COMPLIANT - iscntrl(t); // COMPLIANT - isdigit(t); // COMPLIANT - isgraph(t); // COMPLIANT - islower(t); // COMPLIANT - isprint(t); // COMPLIANT - ispunct(t); // COMPLIANT - isspace(t); // COMPLIANT - isupper(t); // COMPLIANT - isxdigit(t); // COMPLIANT - // toascii(i); // Not part of the C Standard - toupper(t); // COMPLIANT - tolower(t); // COMPLIANT -} diff --git a/c/common/src/codeql-pack.lock.yml b/c/common/src/codeql-pack.lock.yml index 514e6963d0..a45ea8f438 100644 --- a/c/common/src/codeql-pack.lock.yml +++ b/c/common/src/codeql-pack.lock.yml @@ -2,13 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.9.3 + version: 4.0.3 codeql/dataflow: - version: 0.0.4 + version: 2.0.3 + codeql/mad: + version: 1.0.19 + codeql/rangeanalysis: + version: 1.0.19 codeql/ssa: - version: 0.1.5 + version: 1.0.19 codeql/tutorial: - version: 0.1.5 + version: 1.0.19 + codeql/typeflow: + version: 1.0.19 + codeql/typetracking: + version: 2.0.3 codeql/util: - version: 0.1.5 + version: 2.0.6 + codeql/xml: + version: 1.0.19 compiled: false diff --git a/c/common/src/codingstandards/c/Errno.qll b/c/common/src/codingstandards/c/Errno.qll index 86ecabe8f1..768927f505 100644 --- a/c/common/src/codingstandards/c/Errno.qll +++ b/c/common/src/codingstandards/c/Errno.qll @@ -1,7 +1,6 @@ /** Provides a library for errno-setting functions. */ import cpp -import codingstandards.cpp.dataflow.DataFlow /** * An errno-setting function diff --git a/c/common/src/codingstandards/c/Extensions.qll b/c/common/src/codingstandards/c/Extensions.qll index 018359586e..4f16a1f09a 100644 --- a/c/common/src/codingstandards/c/Extensions.qll +++ b/c/common/src/codingstandards/c/Extensions.qll @@ -4,21 +4,28 @@ import codingstandards.cpp.Extensions /** * Common base class for modeling compiler extensions. */ -abstract class CCompilerExtension extends CompilerExtension { } +abstract class CCompilerExtension extends CompilerExtension { + abstract string getMessage(); +} // Reference: https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#Other-Builtins abstract class CConditionalDefineExtension extends CCompilerExtension, PreprocessorIfdef { + string feature; + CConditionalDefineExtension() { - exists(toString().indexOf("__has_builtin")) or - exists(toString().indexOf("__has_constexpr_builtin")) or - exists(toString().indexOf("__has_feature")) or - exists(toString().indexOf("__has_extension")) or - exists(toString().indexOf("__has_attribute")) or - exists(toString().indexOf("__has_declspec_attribute")) or - exists(toString().indexOf("__is_identifier")) or - exists(toString().indexOf("__has_include")) or - exists(toString().indexOf("__has_include_next")) or - exists(toString().indexOf("__has_warning")) + feature = + [ + "__has_builtin", "__has_constexpr_builtin", "__has_feature", "__has_extension", + "__has_attribute", "__has_declspec_attribute", "__is_identifier", "__has_include", + "__has_include_next", "__has_warning" + ] and + exists(toString().indexOf(feature)) + } + + override string getMessage() { + result = + "Call to builtin function '" + feature + + "' is a compiler extension and is not portable to other compilers." } } @@ -31,6 +38,12 @@ class CMacroBasedExtension extends CCompilerExtension, Macro { "__clang_version__", "__clang_literal_encoding__", "__clang_wide_literal_encoding__" ] } + + override string getMessage() { + result = + "Use of builtin macro '" + getBody() + + "' is a compiler extension and is not portable to other compilers." + } } // Reference: https://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html#Variable-Attributes @@ -41,6 +54,12 @@ class CAttributeExtension extends CCompilerExtension, Attribute { "fallthrough", "read_only", "alias" ] } + + override string getMessage() { + result = + "Use of attribute '" + getName() + + "' is a compiler extension and is not portable to other compilers." + } } // Reference: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html#g_t_005f_005fsync-Builtins @@ -61,21 +80,41 @@ class CFunctionExtension extends CCompilerExtension, FunctionCall { // the built-in extensions getTarget().getName().indexOf("__builtin_") = 0 } + + override string getMessage() { + result = + "Call to builtin function '" + getTarget().getName() + + "' is a compiler extension and is not portable to other compilers." + } } // Reference: https://gcc.gnu.org/onlinedocs/gcc/Alignment.html#Alignment class CFunctionLikeExtension extends CCompilerExtension, AlignofExprOperator { CFunctionLikeExtension() { exists(getValueText().indexOf("__alignof__")) } + + override string getMessage() { + result = "'__alignof__' is a compiler extension and is not portable to other compilers." + } } // Reference: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs -class CStmtExprExtension extends CCompilerExtension, StmtExpr { } +class CStmtExprExtension extends CCompilerExtension, StmtExpr { + override string getMessage() { + result = + "Statement expressions are a compiler extension and are not portable to other compilers." + } +} // Use of ternary like the following: `int a = 0 ?: 0;` where the // one of the branches is omitted // Reference: https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html#Conditionals class CTerseTernaryExtension extends CCompilerExtension, ConditionalExpr { CTerseTernaryExtension() { getCondition() = getElse() or getCondition() = getThen() } + + override string getMessage() { + result = + "Ternaries with omitted middle operands are a compiler extension and is not portable to other compilers." + } } // Reference: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html#g_t_005f_005fint128 @@ -87,31 +126,63 @@ class CRealTypeExtensionExtension extends CCompilerExtension, DeclarationEntry { getType() instanceof Decimal64Type or getType() instanceof Float128Type } + + override string getMessage() { + result = "Decimal floats are a compiler extension and are not portable to other compilers." + } } // Reference: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html#g_t_005f_005fint128 class CIntegerTypeExtension extends CCompilerExtension, DeclarationEntry { CIntegerTypeExtension() { getType() instanceof Int128Type } + + override string getMessage() { + result = "128-bit integers are a compiler extension and are not portable to other compilers." + } } // Reference: https://gcc.gnu.org/onlinedocs/gcc/Long-Long.html#Long-Long class CLongLongType extends CCompilerExtension, DeclarationEntry { CLongLongType() { getType() instanceof LongLongType } + + override string getMessage() { + result = + "Double-Word integers are a compiler extension and are not portable to other compilers." + } } class CZeroLengthArraysExtension extends CCompilerExtension, DeclarationEntry { CZeroLengthArraysExtension() { getType().(ArrayType).getArraySize() = 0 } + + override string getMessage() { + result = "Zero length arrays are a compiler extension and are not portable to other compilers." + } } // Reference: https://gcc.gnu.org/onlinedocs/gcc/Empty-Structures.html#Empty-Structures class CEmptyStructExtension extends CCompilerExtension, Struct { CEmptyStructExtension() { not exists(getAMember(_)) } + + override string getMessage() { + result = "Empty structures are a compiler extension and are not portable to other compilers." + } } // Reference: https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html#Variable-Length -class CVariableLengthArraysExtension extends CCompilerExtension, DeclarationEntry { +class CVariableLengthArraysExtension extends CCompilerExtension, Field { CVariableLengthArraysExtension() { getType() instanceof ArrayType and - not getType().(ArrayType).hasArraySize() + not getType().(ArrayType).hasArraySize() and + // Not the final member of the struct, which is allowed to be variably sized + not exists(int lastIndex, Class declaringStruct | + declaringStruct = getDeclaringType() and + lastIndex = count(declaringStruct.getACanonicalMember()) - 1 and + this = declaringStruct.getCanonicalMember(lastIndex) + ) + } + + override string getMessage() { + result = + "Variable length arrays are a compiler extension and are not portable to other compilers." } } diff --git a/c/common/src/codingstandards/c/Generic.qll b/c/common/src/codingstandards/c/Generic.qll new file mode 100644 index 0000000000..19d5aad443 --- /dev/null +++ b/c/common/src/codingstandards/c/Generic.qll @@ -0,0 +1,150 @@ +import cpp +import codingstandards.cpp.Macro +import codingstandards.cpp.MatchingParenthesis + +string genericRegexp() { result = "\\b_Generic\\s*\\(\\s*(.+),.*" } + +bindingset[input] +string deparenthesize(string input) { + input = "(" + result + ")" and + result = input.substring(1, input.length() - 1) +} + +class GenericMacro extends Macro { + string ctrlExpr; + + GenericMacro() { ctrlExpr = getBody().regexpCapture(genericRegexp(), 1).trim() } + + string getAParameter() { result = this.(FunctionLikeMacro).getAParameter() } + + string getControllingExprString() { + if exists(string s | s = deparenthesize(ctrlExpr)) + then result = deparenthesize(ctrlExpr).trim() + else result = ctrlExpr + } + + /** + * Whether the controlling expression of the `_Generic` expr in this macro's controlling + * expression refers to one of this macro's parameters. + */ + predicate hasControllingExprFromMacroParameter() { + getControllingExprString().matches(getAParameter()) + } +} + +class GenericMacroString extends string { + GenericMacroString() { this = any(Macro m).getBody() and this.matches("%_Generic%") } +} + +import MatchingParenthesis + +class ParsedGenericMacro extends Macro { + ParsedRoot macroBody; + Parsed genericBody; + string beforeGenericBody; + string afterGenericBody; + + ParsedGenericMacro() { + macroBody.getInputString() = this.getBody() and + exists(ParsedText genericText | + genericText.getText().matches("%_Generic%") and + genericBody = genericText.getParent().getChild(genericText.getChildIdx() + 1) and + genericBody.getRoot() = macroBody + ) and + beforeGenericBody = + textFrom(macroBody.getStartToken(), genericBody.getStartToken().getPrevious()) and + ( + if exists(genericBody.getEndToken().getNext()) + then afterGenericBody = textFrom(genericBody.getEndToken().getNext(), macroBody.getEndToken()) + else afterGenericBody = "" + ) + } + + string getAParameter() { result = this.(FunctionLikeMacro).getAParameter() } + + int getAParsedGenericCommaSeparatorOffset() { + exists(ParsedText text | + text.getParent() = genericBody and + result = text.getStartToken().getStartPos() + text.getText().indexOf(",") + ) + } + + int getAParsedGenericColonSeparatorOffset() { + exists(ParsedText text | + text.getParent() = genericBody and + result = text.getStartToken().getStartPos() + text.getText().indexOf(":") + ) + } + + int getParsedGenericCommaSeparatorOffset(int i) { + result = rank[i](int index | index = getAParsedGenericCommaSeparatorOffset()) + } + + bindingset[start, end] + int getParsedGenericColon(int start, int end) { + result = + min(int offset | + offset = getAParsedGenericColonSeparatorOffset() and + offset >= start and + offset <= end + ) + } + + predicate hasParsedFullSelectionRange(int idx, int start, int end) { + idx = 1 and + start = genericBody.getStartToken().getEndPos() and + end = getParsedGenericCommaSeparatorOffset(idx) + or + not exists(getParsedGenericCommaSeparatorOffset(idx)) and + start = getParsedGenericCommaSeparatorOffset(idx - 1) and + end = genericBody.getEndToken().getStartPos() + or + start = getParsedGenericCommaSeparatorOffset(idx - 1) and + end = getParsedGenericCommaSeparatorOffset(idx) + } + + string getSelectionString(int idx) { + exists(int start, int rawStart, int end | + hasParsedFullSelectionRange(idx, rawStart, end) and + ( + if exists(getParsedGenericColon(rawStart, end)) + then start = getParsedGenericColon(rawStart, end) + else start = rawStart + ) and + result = genericBody.getInputString().substring(start, end) + ) + } + + string getControllingExprString() { result = getSelectionString(1).trim() } + + bindingset[str, word] + private int countWordInString(string word, string str) { + result = + max(int occurrence | + exists(str.regexpFind("\\b" + word + "\\b", occurrence, _)) or occurrence = -1 + | + occurrence + 1 + ) + } + + int expansionsOutsideExpr(string parameter) { + parameter = getAParameter() and + result = + countWordInString(parameter, beforeGenericBody) + + countWordInString(parameter, afterGenericBody) + } + + int expansionsInsideSelection(string parameter, int idx) { + parameter = getAParameter() and + result = countWordInString(parameter, getSelectionString(idx)) + } + + int expansionsInsideControllingExpr(string parameter) { + result = expansionsInsideSelection(parameter, 1) + } + + int expansionsInsideAssociation(string parameter, int idx) { + not idx = 0 and + result = expansionsInsideSelection(parameter, idx + 1) + } +} diff --git a/c/common/src/codingstandards/c/IdentifierLinkage.qll b/c/common/src/codingstandards/c/IdentifierLinkage.qll new file mode 100644 index 0000000000..085ebf5a7b --- /dev/null +++ b/c/common/src/codingstandards/c/IdentifierLinkage.qll @@ -0,0 +1,47 @@ +import cpp + +newtype TIdentifierLinkage = + TIdentifierLinkageExternal() or + TIdentifierLinkageInternal() or + TIdentifierLinkageNone() + +/** + * In C, identifiers have internal linkage, or external linkage, or no linkage (6.2.2.1). + * + * The linkage of an identifier is used to, among other things, determine the storage duration + * and/or lifetime of that identifier. Storage durations and lifetimes are often used to define + * rules in the various coding standards. + */ +class IdentifierLinkage extends TIdentifierLinkage { + predicate isExternal() { this = TIdentifierLinkageExternal() } + + predicate isInternal() { this = TIdentifierLinkageInternal() } + + predicate isNone() { this = TIdentifierLinkageNone() } + + string toString() { + this.isExternal() and result = "external linkage" + or + this.isInternal() and result = "internal linkage" + or + this.isNone() and result = "no linkage" + } +} + +/** + * Determine the linkage of a variable: external, or static, or none. + * + * The linkage of a variable is determined by its scope and storage class. Note that other types of + * identifiers (e.g. functions) may also have linkage, but that behavior is not covered in this + * predicate. + */ +IdentifierLinkage linkageOfVariable(Variable v) { + // 6.2.2.3, file scope identifiers marked static have internal linkage. + v.isTopLevel() and v.isStatic() and result.isInternal() + or + // 6.2.2.4 describes generally non-static file scope identifiers, which have external linkage. + v.isTopLevel() and not v.isStatic() and result.isExternal() + or + // Note: Not all identifiers have linkage, see 6.2.2.6 + not v.isTopLevel() and result.isNone() +} diff --git a/c/common/src/codingstandards/c/Literals.qll b/c/common/src/codingstandards/c/Literals.qll deleted file mode 100644 index beeeccb8cc..0000000000 --- a/c/common/src/codingstandards/c/Literals.qll +++ /dev/null @@ -1,4 +0,0 @@ -// Reuse the `IntegerLiteral` class -import codingstandards.cpp.Cpp14Literal - -class IntegerLiteral = Cpp14Literal::IntegerLiteral; diff --git a/c/common/src/codingstandards/c/Objects.qll b/c/common/src/codingstandards/c/Objects.qll new file mode 100644 index 0000000000..9a0206771b --- /dev/null +++ b/c/common/src/codingstandards/c/Objects.qll @@ -0,0 +1,398 @@ +import cpp +import codingstandards.c.StorageDuration +import codingstandards.c.IdentifierLinkage +import semmle.code.cpp.valuenumbering.HashCons +import codingstandards.cpp.Clvalues + +/** + * A libary for handling "Objects" in C. + * + * Objects may be stored in registers or memory, they have an address, a type, a storage duration, + * and a lifetime (which is different than storage duration). Objects which are structs or arrays + * have subobjects, which share the storage duration and lifetime of the parent object. + * + * Note: lifetime analysis is not performed in this library, but is available in + * the module `codingstandards.cpp.lifetimes.LifetimeProfile`. In the future, these libraries could + * be merged for more complete analysis. + * + * To get objects in a project, use the `ObjectIdentity` class which finds the following types of + * objects: + * - global variables + * - local variables + * - literals + * - malloc calls + * - certain temporary object expressions + * + * And direct references to these objects can be found via the member predicate `getAnAccess()`. + * However, much of a project's code will not refer to these objects directly, but rather, refer to + * their subobjects. The class `ObjectIdentity` exposes several member predicates for finding when + * these subobjects are used: + * - `getASubobjectType()` + * - `getASubobjectAccess()` + * - `getASubobjectAddressExpr()` + * + * These methods do not use flow analysis, and will not return a conclusive list of accesses. To + * get better results here, this library should be integrated with flow analysis or the library + * `LifetimeProfile.qll`. + * + * Additionally, subobjects are currently not tracked individually. In the future subobjects could + * be tracked as a root object and an access chain to refer to them. For now, however, finding *any* + * subobject access is sufficient for many analyses. + * + * To get the storage duration, `ObjectIdentity` exposes the member predicate + * `getStorageDuration()` with the following options: + * - `obj.getStorageDuration().isAutomatic()`: Stack objects + * - `obj.getStorageDuration().isStatic()`: Global objects + * - `obj.getStorageDuration().isThread()`: Threadlocal objects + * - `obj.getStorageDuration().isAllocated()`: Dynamic objects + * + * Note that lifetimes are not storage durations. The only lifetime tracking currently implemented + * is `hasTemporaryLifetime()`, which is a subset of automatic storage duration objects, and may + * be filtered out, or selected directly with `TemporaryObjectIdentity`. + */ +final class ObjectIdentity = ObjectIdentityBase; + +/** + * A base class for objects in C, along with the source location where the object can be identified + * in the project code (thus, this class extends `Element`), which may be variable, or may be an + * expression such as a literal or a malloc call. + * + * Extend this class to define a new type of object identity. To create a class which filters the + * set of object identities, users of this library should extend the final subclass + * `ObjectIdentity` instead. + */ +abstract class ObjectIdentityBase extends Element { + /** + * The type of this object. + * + * Note that for allocated objects, this is inferred from the sizeof() statement or the variable + * it is assigned to. + */ + abstract Type getType(); + + /* The storage duration of this object: static, thread, automatic, or allocated. */ + abstract StorageDuration getStorageDuration(); + + /** + * Get the nested objects within this object (members, array element types). + * + * Note that if a struct has a pointer member, the pointer itself is a subobject, but the value + * it points to is not. Therefore `struct { int* x; }` has a subobject of type `int*`, but not + * `int`. + */ + Type getASubObjectType() { result = getADirectSubobjectType*(getType()) } + + /** + * Get expressions which trivially access this object. Does not perform flow analysis. + * + * For dynamically allocated objects, this is a dereference of the malloc call. + */ + abstract Expr getAnAccess(); + + /** + * Get expressions which trivially access this object or a subobject of this object. Does not + * perform flow analysis. + * + * For dynamically allocated objects, this is a dereference of the malloc call or direct access + * of the result of dereferencing the malloc call. + */ + Expr getASubobjectAccess() { result = getASubobjectAccessOf(getAnAccess()) } + + /** + * Get expressions which trivially take the address of this object or a subobject of this object. + * Does not perform flow analysis. + */ + Expr getASubobjectAddressExpr() { + exists(Expr subobject | + subobject = getASubobjectAccess() and + ( + // Holds for address-of expressions. + result = any(AddressOfExpr e | e.getOperand() = subobject) + or + // Holds for array-to-pointer conversions, which evaluate to a usable subobject address. + exists(ArrayToPointerConversion c | c.getExpr() = subobject) and + // Note that `arr[x]` has an array-to-pointer conversion, and returns the `x`th item by + // value, not the address of the `x`th item. Therefore, exclude `arr` if `arr` is part of + // an expression `arr[x]`. + not exists(ArrayExpr a | a.getArrayBase() = subobject) and + result = subobject + ) + ) + } + + /** + * Holds if the object has temporary lifetime. This is not a storage duration, but only objects + * with automatic storage duration have temporary lifetime. + */ + abstract predicate hasTemporaryLifetime(); +} + +/** + * Finds expressions `e.x` or `e[x]` for expression `e`, recursively. Does not resolve pointers. + * + * Note that this does not hold for `e->x` or `e[x]` where `e` is a pointer. + */ +private Expr getASubobjectAccessOf(Expr e) { + result = e + or + result.(DotFieldAccess).getQualifier() = getASubobjectAccessOf(e) + or + result.(ArrayExpr).getArrayBase() = getASubobjectAccessOf(e) and + not result.(ArrayExpr).getArrayBase().getUnspecifiedType() instanceof PointerType +} + +/** + * Find the object types that are embedded within the current type. + * + * For example, a block of memory with type `T[]` has subobjects of type `T`, and a struct with a + * member of `T member;` has a subobject of type `T`. + * + * Note that subobjects may be pointers, but the value they point to is not a subobject. For + * instance, `struct { int* x; }` has a subobject of type `int*`, but not `int`. + */ +Type getADirectSubobjectType(Type type) { + result = type.stripTopLevelSpecifiers().(Struct).getAMember().getADeclarationEntry().getType() + or + result = type.stripTopLevelSpecifiers().(ArrayType).getBaseType() +} + +/** + * An object in memory which may be identified by the variable that holds it. + * + * This may be a local variable, a global variable, or a parameter, etc. However, it cannot be a + * member of a struct or union, as these do not have storage duration. + */ +class VariableObjectIdentity extends Variable, ObjectIdentityBase { + VariableObjectIdentity() { + // Exclude members; member definitions does not allocate storage and thus do not have a storage + // duration. They are therefore not objects. To get the storage duration of members, use one of + // the predicates related to sub objects, e.g. `getASubObjectType()`. + not isMember() + } + + override StorageDuration getStorageDuration() { + // 6.2.4.4, objects declared _Thread_local have thread storage duration. + isThreadLocal() and result.isThread() + or + // 6.2.4.3, Non _ThreadLocal objects with internal or external linkage or declared static have + // static storage duration. + not isThreadLocal() and + (hasLinkage() or isStatic()) and + result.isStatic() + or + // 6.2.4.3, Non _ThreadLocal objects no linkage that are not static have automatic storage + // duration. + not isThreadLocal() and + not hasLinkage() and + not isStatic() and + result.isAutomatic() + } + + override Type getType() { + // Caution here: If we use `Variable.super.getType()` then override resolution is skipped, and + // it uses the base predicate defined as `none()`. By casting this to `Variable` and calling + // `getType()`, all overrides (harmlessly, *including this one*...) are considered, which means + // we defer to the subclasses such as `GlobalVariable` overrides of `getType()`, which is what + // we want. + result = this.(Variable).getType() + } + + /* The storage duration of a variable depends on its linkage. */ + IdentifierLinkage getLinkage() { result = linkageOfVariable(this) } + + predicate hasLinkage() { not getLinkage().isNone() } + + override VariableAccess getAnAccess() { result = Variable.super.getAnAccess() } + + override predicate hasTemporaryLifetime() { + none() // Objects identified by a variable do not have temporary lifetime. + } +} + +/** + * A string literal is an object with static storage duration. + * + * 6.4.5.6, multibyte character sequences initialize an array of static storage duration. + */ +class LiteralObjectIdentity extends Literal, ObjectIdentityBase { + override StorageDuration getStorageDuration() { result.isStatic() } + + override Type getType() { result = Literal.super.getType() } + + override Expr getAnAccess() { result = this } + + override predicate hasTemporaryLifetime() { + none() // String literal objects do not have temporary lifetime. + } +} + +/** + * An object identifiable as a struct or array literal, which is an lvalue that may have static or + * automatic storage duration depending on context. + * + * 6.5.2.5.5, compound literals outside of a function have static storage duration, while literals + * inside a function have automatic storage duration. + */ +class AggregateLiteralObjectIdentity extends AggregateLiteral, ObjectIdentityBase { + override StorageDuration getStorageDuration() { + if exists(getEnclosingFunction()) then result.isAutomatic() else result.isStatic() + } + + override Type getType() { result = AggregateLiteral.super.getType() } + + override Expr getAnAccess() { result = this } + + override predicate hasTemporaryLifetime() { + // Confusing; a struct literal is an lvalue, and therefore does not have temporary lifetime. + none() + } +} + +/** + * An object identified by a call to `malloc`. + * + * 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 + * itself. + * + * Note that the predicates for tracking accesses, subobject accesses, and address expresisons may + * be less reliable as dynamic memory is fundamentally more difficult to track. However, this class + * attempts to give reasonable results. In the future, this could be improved by integrating with + * LifetimeProfile.qll or by integrating flow analysis. + * + * Additionally, the type of this object is inferred based on its size and use. + */ +class AllocatedObjectIdentity extends AllocationExpr, ObjectIdentityBase { + AllocatedObjectIdentity() { + this.(FunctionCall).getTarget().(AllocationFunction).requiresDealloc() + } + + override StorageDuration getStorageDuration() { result.isAllocated() } + + /** Attempt to infer the type of the allocated memory */ + override Type getType() { result = this.getAllocatedElementType() } + + /** Find dereferences of direct aliases of this pointer result. */ + override Expr getAnAccess() { result.(PointerDereferenceExpr).getOperand() = getAnAlias() } + + /** + * Find the following subobject accesses, given a pointer alias `x`: + * - `(*x)` + * - `(*x).y` + * - `(*x)[i]` + * - `x->y` + * - `x[i]` + * - `x->y.z` + * - `x[i].y` + * - all direct accesses (`foo.x`, `foo[i]`) of the above + */ + override Expr getASubobjectAccess() { + result = getASubobjectAccessOf(getAnAccess()) + or + exists(PointerFieldAccess pfa | + pfa.getQualifier() = getASubobjectAddressExpr() and + result = getASubobjectAccessOf(pfa) + ) + or + exists(ArrayExpr arrayExpr | + arrayExpr.getArrayBase() = getASubobjectAddressExpr() and + result = getASubobjectAccessOf(arrayExpr) + ) + } + + /** + * Given a pointer alias `x`, finds `x` itself. Additionally, defers to the default class + * behavior, which finds address-of (`&`) and array-to-pointer conversions of all subobject + * accesses. (See `AllocatedObjectIdentity.getASubobjectAccess()`.) + */ + override Expr getASubobjectAddressExpr() { + result = getAnAlias() + or + result = super.getASubobjectAddressExpr() + } + + /** + * Find an obvious direct reference to the result of a `malloc()` function call. This includes + * the function call itself, but additionally: + * - For `T* x = malloc(...)`, accesses to variable `x` are likely aliases of the malloc result + * - For `(expr) = malloc(...)` future lexically identical uses of `expr` are likely aliases of + * the malloc result. + * + * This is used so that member predicates such as `getAnAccess()`, `getASubobjectAccess()` can + * find cases such as: + * + * ```c + * int *x = malloc(sizeof(int)); + * return *x; // accesses the malloc result + * ``` + */ + Expr getAnAlias() { + result = this + or + exists(AssignExpr assignExpr | + assignExpr.getRValue() = this and + hashCons(result) = hashCons(assignExpr.getLValue()) + ) + or + exists(Variable v | + v.getInitializer().getExpr() = this and + result = v.getAnAccess() + ) + } + + override predicate hasTemporaryLifetime() { + none() // Allocated objects do not have "temporary lifetime." + } +} + +/** + * A struct or union type that contains an array type, used to find objects with temporary + * lifetime. + */ +private class StructOrUnionTypeWithArrayField extends Struct { + StructOrUnionTypeWithArrayField() { + this.getAField().getUnspecifiedType() instanceof ArrayType + or + // nested struct or union containing an array type + this.getAField().getUnspecifiedType().(Struct) instanceof StructOrUnionTypeWithArrayField + } +} + +/** + * 6.2.4.7, A non-lvalue expression with struct or or union type that has a field member of array + * type, refers to an object with automatic storage duration (and has temporary lifetime). + * + * The spec uses the lanugage "refers to." This is likely intended to mean that the expression + * `foo().x` does not create a new temporary object, but rather "refers to" the temporary object + * storing the value of the expression `foo()`. + * + * Separate this predicate to avoid non-monotonic recursion (`C() { not exists(C c | ... ) }`). + */ +private class TemporaryObjectIdentityExpr extends Expr { + TemporaryObjectIdentityExpr() { + getType() instanceof StructOrUnionTypeWithArrayField and + not isCLValue(this) + } +} + +/** + * 6.2.4.7, A non-lvalue expression with struct or or union type that has a field member of array + * type, is an object with automatic storage duration (and has temporary lifetime). + */ +class TemporaryObjectIdentity extends ObjectIdentityBase instanceof TemporaryObjectIdentityExpr { + TemporaryObjectIdentity() { + // See comment in `TemporaryObjectIdentityExpr` for why we check `getASubobjectAccess()` here. + not exists(TemporaryObjectIdentityExpr parent | + this = getASubobjectAccessOf(parent) and + not this = parent + ) + } + + override StorageDuration getStorageDuration() { result.isAutomatic() } + + override Type getType() { result = this.(Expr).getType() } + + override Expr getAnAccess() { result = this } + + override predicate hasTemporaryLifetime() { any() } +} diff --git a/c/common/src/codingstandards/c/OutOfBounds.qll b/c/common/src/codingstandards/c/OutOfBounds.qll index 87c7c17870..1f1680f56c 100644 --- a/c/common/src/codingstandards/c/OutOfBounds.qll +++ b/c/common/src/codingstandards/c/OutOfBounds.qll @@ -5,13 +5,13 @@ */ import cpp -import codingstandards.c.Pointers +import codingstandards.cpp.types.Pointers import codingstandards.c.Variable import codingstandards.cpp.Allocations import codingstandards.cpp.Overflow import codingstandards.cpp.PossiblyUnsafeStringOperation import codingstandards.cpp.SimpleRangeAnalysisCustomizations -import codingstandards.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.valuenumbering.GlobalValueNumbering module OOB { diff --git a/c/common/src/codingstandards/c/Signal.qll b/c/common/src/codingstandards/c/Signal.qll index 35286be4d9..2a570b654f 100644 --- a/c/common/src/codingstandards/c/Signal.qll +++ b/c/common/src/codingstandards/c/Signal.qll @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow /** * A signal corresponding to a computational exception diff --git a/c/common/src/codingstandards/c/StorageDuration.qll b/c/common/src/codingstandards/c/StorageDuration.qll new file mode 100644 index 0000000000..4669d467bb --- /dev/null +++ b/c/common/src/codingstandards/c/StorageDuration.qll @@ -0,0 +1,31 @@ +import cpp + +class DeclarationWithStorageDuration extends Declaration { } + +newtype TStorageDuration = + StorageDurationStatic() or + StorageDurationAutomatic() or + StorageDurationThread() or + StorageDurationAllocated() + +class StorageDuration extends TStorageDuration { + predicate isStatic() { this = StorageDurationStatic() } + + predicate isAutomatic() { this = StorageDurationAutomatic() } + + predicate isThread() { this = StorageDurationThread() } + + predicate isAllocated() { this = StorageDurationAllocated() } + + string toString() { result = getStorageTypeName() + " storage duration" } + + string getStorageTypeName() { + isStatic() and result = "static" + or + isAutomatic() and result = "automatic" + or + isThread() and result = "thread" + or + isAllocated() and result = "allocated" + } +} diff --git a/c/common/src/codingstandards/c/SubObjects.qll b/c/common/src/codingstandards/c/SubObjects.qll new file mode 100644 index 0000000000..66f15cd18c --- /dev/null +++ b/c/common/src/codingstandards/c/SubObjects.qll @@ -0,0 +1,125 @@ +/** + * A library that expands upon the `Objects.qll` library, to support nested "Objects" such as + * `x.y.z` or `x[i][j]` within an object `x`. + * + * Objects in C are values in memory, that have a type and a storage duration. In the case of + * array objects and struct objects, the object will contain other objects. The these subobjects + * will share properties of the root object such as storage duration. This library can be used to, + * for instance, find all usages of a struct member to ensure that member is initialized before it + * is used. + * + * To use this library, select `SubObject` and find its usages in the AST via `getAnAccess()` (to + * find usages of the subobject by value) or `getAnAddressOfExpr()` (to find usages of the object + * by address). + * + * Note that a struct or array object may contain a pointer. In this case, the pointer itself is + * a subobject of the struct or array object, but the object that the pointer points to is not. + * This is because the pointed-to object does not necessarily have the same storage duration, + * lifetime, or linkage as the pointer and the object containing the pointer. + * + * Note as well that `getAnAccess()` on an array subobject will return all accesses to the array, + * not just accesses to a particular index. For this reason, `SubObject` exposes the predicate + * `isPrecise()`. If a subobject is precise, that means all results of `getAnAccess()` will + * definitely refer to the same object in memory. If it is not precise, the different accesses + * may refer to the same or different objects in memory. For instance, `x[i].y` and `x[j].y` are + * the same object if `i` and `j` are the same, but they are different objects if `i` and `j` are + * different. + */ + +import codingstandards.c.Objects + +newtype TSubObject = + TObjectRoot(ObjectIdentity i) or + TObjectMember(SubObject struct, MemberVariable m) { + m = struct.getType().(Struct).getAMemberVariable() + } or + TObjectIndex(SubObject array) { array.getType() instanceof ArrayType } + +class SubObject extends TSubObject { + string toString() { + exists(ObjectIdentity i | + this = TObjectRoot(i) and + result = i.toString() + ) + or + exists(SubObject struct, Variable m | + this = TObjectMember(struct, m) and + result = struct.toString() + "." + m.getName() + ) + or + exists(SubObject array | + this = TObjectIndex(array) and + result = array.toString() + ) + } + + Type getType() { + exists(ObjectIdentity i | + this = TObjectRoot(i) and + result = i.getType() + ) + or + exists(Variable m | + this = TObjectMember(_, m) and + result = m.getType() + ) + or + exists(SubObject array | + this = TObjectIndex(array) and + result = array.getType().(ArrayType).getBaseType() + ) + } + + /** + * Holds for object roots and for member accesses on that root, not for array accesses. + * + * This is useful for cases where we do not wish to treat `x[y]` and `x[z]` as the same object. + */ + predicate isPrecise() { not getParent*() = TObjectIndex(_) } + + SubObject getParent() { + exists(SubObject struct, MemberVariable m | + this = TObjectMember(struct, m) and + result = struct + ) + or + exists(SubObject array | + this = TObjectIndex(array) and + result = array + ) + } + + Expr getAnAccess() { + exists(ObjectIdentity i | + this = TObjectRoot(i) and + result = i.getAnAccess() + ) + or + exists(MemberVariable m | + this = TObjectMember(_, m) and + result = m.getAnAccess() and + // Only consider `DotFieldAccess`es, not `PointerFieldAccess`es, as the latter + // are not subobjects of the root object: + result.(DotFieldAccess).getQualifier() = getParent().getAnAccess() + ) + or + this = TObjectIndex(_) and + result.(ArrayExpr).getArrayBase() = getParent().getAnAccess() + } + + AddressOfExpr getAnAddressOfExpr() { result.getOperand() = this.getAnAccess() } + + /** + * Get the "root" object identity to which this subobject belongs. For instance, in the + * expression `x.y.z`, the root object is `x`. This subobject will share properties with the root + * object such as storage duration, lifetime, and linkage. + */ + ObjectIdentity getRootIdentity() { + exists(ObjectIdentity i | + this = TObjectRoot(i) and + result = i + ) + or + result = getParent().getRootIdentity() + } +} diff --git a/c/common/src/codingstandards/c/TgMath.qll b/c/common/src/codingstandards/c/TgMath.qll new file mode 100644 index 0000000000..8d68cd2574 --- /dev/null +++ b/c/common/src/codingstandards/c/TgMath.qll @@ -0,0 +1,102 @@ +import cpp + +private string getATgMathMacroName(boolean allowComplex, int numberOfParameters) { + allowComplex = true and + numberOfParameters = 1 and + result = + [ + "acos", "acosh", "asin", "asinh", "atan", "atanh", "carg", "cimag", "conj", "cos", "cosh", + "cproj", "creal", "exp", "fabs", "log", "sin", "sinh", "sqrt", "tan", "tanh" + ] + or + allowComplex = true and + numberOfParameters = 2 and + result = "pow" + or + allowComplex = false and + numberOfParameters = 1 and + result = + [ + "cbrt", "ceil", "erf", "erfc", "exp2", "expm1", "floor", "ilogb", "lgamma", "llrint", + "llround", "log10", "log1p", "log2", "logb", "lrint", "lround", "nearbyint", "rint", "round", + "tgamma", "trunc", + ] + or + allowComplex = false and + numberOfParameters = 2 and + result = + [ + "atan2", "copysign", "fdim", "fmax", "fmin", "fmod", "frexp", "hypot", "ldexp", "nextafter", + "nexttoward", "remainder", "scalbn", "scalbln" + ] + or + allowComplex = false and + numberOfParameters = 3 and + result = ["fma", "remquo"] +} + +private predicate hasOutputArgument(string macroName, int index) { + macroName = "frexp" and index = 1 + or + macroName = "remquo" and index = 2 +} + +class TgMathInvocation extends MacroInvocation { + Call call; + boolean allowComplex; + int numberOfParameters; + + TgMathInvocation() { + this.getMacro().getName() = getATgMathMacroName(allowComplex, numberOfParameters) and + call = getBestCallInExpansion(this) + } + + /** Account for extra parameters added by gcc */ + private int getParameterOffset() { + // Gcc calls look something like: `__builtin_tgmath(cosf, cosd, cosl, arg)`, in this example + // there is a parameter offset of 3, so `getOperandArgument(0)` is equivalent to + // `call.getArgument(3)`. + result = call.getNumberOfArguments() - numberOfParameters + } + + Expr getOperandArgument(int i) { + i >= 0 and + result = call.getArgument(i + getParameterOffset()) and + //i in [0..numberOfParameters - 1] and + not hasOutputArgument(getMacro().getName(), i) + } + + /** Get all explicit conversions, except those added by clang in the macro body */ + Expr getExplicitlyConvertedOperandArgument(int i) { + exists(Expr explicitConv | + explicitConv = getOperandArgument(i).getExplicitlyConverted() and + // clang explicitly casts most arguments, but not some integer arguments such as in `scalbn`. + if call.getTarget().getName().matches("__tg_%") and explicitConv instanceof Conversion + then result = explicitConv.(Conversion).getExpr() + else result = explicitConv + ) + } + + int getNumberOfOperandArguments() { + result = numberOfParameters - count(int i | hasOutputArgument(getMacroName(), i)) + } + + Expr getAnOperandArgument() { result = getOperandArgument(_) } + + predicate allowsComplex() { allowComplex = true } +} + +private Call getACallInExpansion(MacroInvocation mi) { result = mi.getAnExpandedElement() } + +private Call getNameMatchedCallInExpansion(MacroInvocation mi) { + result = getACallInExpansion(mi) and result.getTarget().getName() = mi.getMacroName() +} + +private Call getBestCallInExpansion(MacroInvocation mi) { + count(getACallInExpansion(mi)) = 1 and result = getACallInExpansion(mi) + or + count(getNameMatchedCallInExpansion(mi)) = 1 and result = getNameMatchedCallInExpansion(mi) + or + count(getNameMatchedCallInExpansion(mi)) > 1 and + result = rank[1](Call c | c = getACallInExpansion(mi) | c order by c.getTarget().getName()) +} diff --git a/c/common/src/codingstandards/c/UndefinedBehavior.qll b/c/common/src/codingstandards/c/UndefinedBehavior.qll index 5c9dc230d8..47461aa613 100644 --- a/c/common/src/codingstandards/c/UndefinedBehavior.qll +++ b/c/common/src/codingstandards/c/UndefinedBehavior.qll @@ -1,4 +1,5 @@ import cpp +import codingstandards.cpp.types.Pointers import codingstandards.cpp.UndefinedBehavior /** @@ -6,28 +7,38 @@ import codingstandards.cpp.UndefinedBehavior */ abstract class CUndefinedBehavior extends UndefinedBehavior { } +/** + * A function which has the signature - but not the name - of a main function. + */ class C99MainFunction extends Function { C99MainFunction() { this.getNumberOfParameters() = 2 and - this.getType() instanceof IntType and - this.getParameter(0).getType() instanceof IntType and - this.getParameter(1).getType().(PointerType).getBaseType().(PointerType).getBaseType() - instanceof CharType + this.getType().getUnderlyingType() instanceof IntType and + this.getParameter(0).getType().getUnderlyingType() instanceof IntType and + this.getParameter(1) + .getType() + .getUnderlyingType() + .(UnspecifiedPointerOrArrayType) + .getBaseType() + .(UnspecifiedPointerOrArrayType) + .getBaseType() instanceof CharType or this.getNumberOfParameters() = 0 and - this.getType() instanceof VoidType + // Must be explicitly declared as `int main(void)`. + this.getADeclarationEntry().hasVoidParamList() and + this.getType().getUnderlyingType() instanceof IntType } } class CUndefinedMainDefinition extends CUndefinedBehavior, Function { CUndefinedMainDefinition() { // for testing purposes, we use the prefix ____codeql_coding_standards` - (this.getName() = "main" or this.getName().indexOf("____codeql_coding_standards") = 0) and + (this.getName() = "main" or this.getName().indexOf("____codeql_coding_standards_main") = 0) and not this instanceof C99MainFunction } override string getReason() { result = - "The behavior of the program is undefined because the main function is not defined according to the C standard." + "main function may trigger undefined behavior because it is not in one of the formats specified by the C standard." } } diff --git a/c/common/src/codingstandards/c/Variable.qll b/c/common/src/codingstandards/c/Variable.qll index adf2f08ad9..09d86e0e25 100644 --- a/c/common/src/codingstandards/c/Variable.qll +++ b/c/common/src/codingstandards/c/Variable.qll @@ -39,20 +39,6 @@ class FlexibleArrayMemberCandidate extends MemberVariable { } } -/** - * Returns the target variable of a `VariableAccess`. - * If the access is a field access, then the target is the `Variable` of the qualifier. - * If the access is an array access, then the target is the array base. - */ -Variable getAddressOfExprTargetBase(AddressOfExpr expr) { - result = expr.getOperand().(ValueFieldAccess).getQualifier().(VariableAccess).getTarget() - or - not expr.getOperand() instanceof ValueFieldAccess and - result = expr.getOperand().(VariableAccess).getTarget() - or - result = expr.getOperand().(ArrayExpr).getArrayBase().(VariableAccess).getTarget() -} - /** * A struct that contains a flexible array member */ diff --git a/c/common/src/codingstandards/c/initialization/GlobalInitializationAnalysis.qll b/c/common/src/codingstandards/c/initialization/GlobalInitializationAnalysis.qll new file mode 100644 index 0000000000..2906883ae9 --- /dev/null +++ b/c/common/src/codingstandards/c/initialization/GlobalInitializationAnalysis.qll @@ -0,0 +1,95 @@ +import cpp +import codingstandards.c.Objects +import codingstandards.cpp.Concurrency +import codingstandards.cpp.Type + +signature module GlobalInitializationAnalysisConfigSig { + /** A function which is not called or started as a thread */ + default predicate isRootFunction(Function f) { + not exists(Function f2 | f2.calls(f)) and + not f instanceof ThreadedFunction and + // Exclude functions which are used as function pointers. + not exists(FunctionAccess access | f = access.getTarget()) + } + + ObjectIdentity getAnInitializedObject(Expr e); + + ObjectIdentity getAUsedObject(Expr e); +} + +module GlobalInitalizationAnalysis { + final class FinalFunction = Function; + + final class FinalExpr = Expr; + + class RootFunction extends FinalFunction { + RootFunction() { Config::isRootFunction(this) } + } + + /** A function call which initializes a mutex or a condition */ + class ObjectInit extends FinalExpr { + ObjectIdentity owningObject; + + ObjectInit() { owningObject = Config::getAnInitializedObject(this) } + + ObjectIdentity getOwningObject() { result = owningObject } + } + + /** + * A function argument where that argument is used as a mutex or condition object. + */ + class ObjectUse extends FinalExpr { + ObjectIdentity owningObject; + + ObjectUse() { owningObject = Config::getAUsedObject(this) } + + ObjectIdentity getOwningObject() { result = owningObject } + } + + predicate requiresInitializedMutexObject( + Function func, ObjectUse mutexUse, ObjectIdentity owningObject + ) { + mutexUse.getEnclosingFunction() = func and + owningObject = mutexUse.getOwningObject() and + not exists(ObjectInit init | + init.getEnclosingFunction() = func and + init.getOwningObject() = owningObject and + mutexUse.getAPredecessor+() = init + ) + or + exists(FunctionCall call | + func = call.getEnclosingFunction() and + requiresInitializedMutexObject(call.getTarget(), mutexUse, owningObject) and + not exists(ObjectInit init | + call.getAPredecessor*() = init and + init.getOwningObject() = owningObject + ) + ) + or + exists(C11ThreadCreateCall call | + func = call.getEnclosingFunction() and + not owningObject.getStorageDuration().isThread() and + requiresInitializedMutexObject(call.getFunction(), mutexUse, owningObject) and + not exists(ObjectInit init | + call.getAPredecessor*() = init and + init.getOwningObject() = owningObject + ) + ) + } + + predicate uninitializedFrom(Expr e, ObjectIdentity obj, Function callRoot) { + exists(ObjectUse use | use = e | + obj = use.getOwningObject() and + requiresInitializedMutexObject(callRoot, use, obj) and + ( + if obj.getStorageDuration().isAutomatic() + then obj.getEnclosingElement+() = callRoot + else ( + obj.getStorageDuration().isThread() and callRoot instanceof ThreadedFunction + or + callRoot instanceof RootFunction + ) + ) + ) + } +} diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index 153e4620f3..d71ab0dd02 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,6 +1,6 @@ name: codeql/common-c-coding-standards -version: 2.32.0-dev +version: 2.52.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' - codeql/cpp-all: 0.9.3 + codeql/cpp-all: 4.0.3 diff --git a/c/common/test/codeql-pack.lock.yml b/c/common/test/codeql-pack.lock.yml index 514e6963d0..a45ea8f438 100644 --- a/c/common/test/codeql-pack.lock.yml +++ b/c/common/test/codeql-pack.lock.yml @@ -2,13 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.9.3 + version: 4.0.3 codeql/dataflow: - version: 0.0.4 + version: 2.0.3 + codeql/mad: + version: 1.0.19 + codeql/rangeanalysis: + version: 1.0.19 codeql/ssa: - version: 0.1.5 + version: 1.0.19 codeql/tutorial: - version: 0.1.5 + version: 1.0.19 + codeql/typeflow: + version: 1.0.19 + codeql/typetracking: + version: 2.0.3 codeql/util: - version: 0.1.5 + version: 2.0.6 + codeql/xml: + version: 1.0.19 compiled: false diff --git a/c/common/test/includes/standard-library/stdatomic.h b/c/common/test/includes/standard-library/stdatomic.h index 66b74ae61a..21e4f995f4 100644 --- a/c/common/test/includes/standard-library/stdatomic.h +++ b/c/common/test/includes/standard-library/stdatomic.h @@ -1,9 +1,70 @@ -#define atomic_compare_exchange_weak(a, b, c) 0 -#define atomic_compare_exchange_weak_explicit(a, b, c, d, e) 0 -#define atomic_load(a) 0 -#define atomic_load_explicit(a, b) -#define atomic_store(a, b) 0 -#define atomic_store_explicit(a, b, c) 0 #define ATOMIC_VAR_INIT(value) (value) +#define atomic_init __c11_atomic_init #define atomic_is_lock_free(obj) __c11_atomic_is_lock_free(sizeof(*(obj))) -typedef _Atomic(int) atomic_int; \ No newline at end of file +typedef _Atomic(int) atomic_int; + +#define __ATOMIC_RELAXED 0 +#define __ATOMIC_CONSUME 1 +#define __ATOMIC_ACQUIRE 2 +#define __ATOMIC_RELEASE 3 +#define __ATOMIC_ACQ_REL 4 +#define __ATOMIC_SEQ_CST 5 + +typedef enum memory_order { + memory_order_relaxed = __ATOMIC_RELAXED, + memory_order_consume = __ATOMIC_CONSUME, + memory_order_acquire = __ATOMIC_ACQUIRE, + memory_order_release = __ATOMIC_RELEASE, + memory_order_acq_rel = __ATOMIC_ACQ_REL, + memory_order_seq_cst = __ATOMIC_SEQ_CST +} memory_order; + +void atomic_thread_fence(memory_order); +void atomic_signal_fence(memory_order); + +#define atomic_thread_fence(order) __c11_atomic_thread_fence(order) +#define atomic_signal_fence(order) __c11_atomic_signal_fence(order) + +#define atomic_store(object, desired) __c11_atomic_store(object, desired, __ATOMIC_SEQ_CST) +#define atomic_store_explicit __c11_atomic_store + +#define atomic_load(object) __c11_atomic_load(object, __ATOMIC_SEQ_CST) +#define atomic_load_explicit __c11_atomic_load + +#define atomic_exchange(object, desired) __c11_atomic_exchange(object, desired, __ATOMIC_SEQ_CST) +#define atomic_exchange_explicit __c11_atomic_exchange + +#define atomic_compare_exchange_strong(object, expected, desired) __c11_atomic_compare_exchange_strong(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_strong_explicit __c11_atomic_compare_exchange_strong + +#define atomic_compare_exchange_weak(object, expected, desired) __c11_atomic_compare_exchange_weak(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_weak_explicit __c11_atomic_compare_exchange_weak + +#define atomic_fetch_add(object, operand) __c11_atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_add_explicit __c11_atomic_fetch_add + +#define atomic_fetch_sub(object, operand) __c11_atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_sub_explicit __c11_atomic_fetch_sub + +#define atomic_fetch_or(object, operand) __c11_atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_or_explicit __c11_atomic_fetch_or + +#define atomic_fetch_xor(object, operand) __c11_atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_xor_explicit __c11_atomic_fetch_xor + +#define atomic_fetch_and(object, operand) __c11_atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_and_explicit __c11_atomic_fetch_and + +typedef struct atomic_flag { _Atomic(_Bool) _Value; } atomic_flag; + +_Bool atomic_flag_test_and_set(volatile atomic_flag *); +_Bool atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order); + +void atomic_flag_clear(volatile atomic_flag *); +void atomic_flag_clear_explicit(volatile atomic_flag *, memory_order); + +#define atomic_flag_test_and_set(object) __c11_atomic_exchange(&(object)->_Value, 1, __ATOMIC_SEQ_CST) +#define atomic_flag_test_and_set_explicit(object, order) __c11_atomic_exchange(&(object)->_Value, 1, order) + +#define atomic_flag_clear(object) __c11_atomic_store(&(object)->_Value, 0, __ATOMIC_SEQ_CST) +#define atomic_flag_clear_explicit(object, order) __c11_atomic_store(&(object)->_Value, 0, order) \ No newline at end of file diff --git a/c/common/test/includes/standard-library/stdlib.h b/c/common/test/includes/standard-library/stdlib.h index b54a051fe9..1af95223d1 100644 --- a/c/common/test/includes/standard-library/stdlib.h +++ b/c/common/test/includes/standard-library/stdlib.h @@ -49,6 +49,7 @@ int at_quick_exit (void (*) (void)); _Noreturn void quick_exit (int); char *getenv (const char *); +char *getenv_s (size_t *restrict len, char *restrict value, size_t valuesz, const char *restrict name); int system (const char *); diff --git a/c/common/test/library/identifierlinkage/IdentifierLinkage.expected b/c/common/test/library/identifierlinkage/IdentifierLinkage.expected new file mode 100644 index 0000000000..c3f1bc39ef --- /dev/null +++ b/c/common/test/library/identifierlinkage/IdentifierLinkage.expected @@ -0,0 +1,10 @@ +| identifierlinkage.c:2:5:2:10 | g_ext1 | external linkage | +| identifierlinkage.c:3:12:3:17 | g_ext2 | external linkage | +| identifierlinkage.c:6:12:6:17 | g_int1 | internal linkage | +| identifierlinkage.c:9:5:9:10 | g_ext3 | external linkage | +| identifierlinkage.c:12:12:12:17 | g_int2 | internal linkage | +| identifierlinkage.c:15:12:15:12 | p | no linkage | +| identifierlinkage.c:16:7:16:13 | l_none1 | no linkage | +| identifierlinkage.c:17:14:17:20 | l_none2 | no linkage | +| identifierlinkage.c:18:14:18:19 | l_ext1 | external linkage | +| identifierlinkage.c:24:7:24:7 | m | no linkage | diff --git a/c/common/test/library/identifierlinkage/IdentifierLinkage.ql b/c/common/test/library/identifierlinkage/IdentifierLinkage.ql new file mode 100644 index 0000000000..37e5b4cd58 --- /dev/null +++ b/c/common/test/library/identifierlinkage/IdentifierLinkage.ql @@ -0,0 +1,5 @@ +import codingstandards.c.IdentifierLinkage + +from Variable v +where not v.getLocation().toString() = "file://:0:0:0:0" +select v, linkageOfVariable(v) diff --git a/c/common/test/library/identifierlinkage/identifierlinkage.c b/c/common/test/library/identifierlinkage/identifierlinkage.c new file mode 100644 index 0000000000..25265aa144 --- /dev/null +++ b/c/common/test/library/identifierlinkage/identifierlinkage.c @@ -0,0 +1,28 @@ +// Simple external linkage +int g_ext1; +extern int g_ext2; + +// Simple internal linkage +static int g_int1; + +// Redefined maintaining linkage +int g_ext3; +extern int g_ext3; + +static int g_int2; +extern int g_int2; + +void f(int p) { + int l_none1; + static int l_none2; + extern int l_ext1; +} + +// Structs are not variables +struct s { + // Struct members are variables with no linkage. + int m; +}; + +// Enums and enum constants are not variables and have no linkage. +enum e { E1 }; \ No newline at end of file diff --git a/c/common/test/library/objects/ObjectIdentity.expected b/c/common/test/library/objects/ObjectIdentity.expected new file mode 100644 index 0000000000..34be1974f5 --- /dev/null +++ b/c/common/test/library/objects/ObjectIdentity.expected @@ -0,0 +1,21 @@ +| objectidentity.c:3:5:3:14 | g_statstg1 | static storage duration | file://:0:0:0:0 | int | +| objectidentity.c:4:12:4:21 | g_statstg2 | static storage duration | file://:0:0:0:0 | int | +| objectidentity.c:5:12:5:21 | g_statstg3 | static storage duration | file://:0:0:0:0 | int | +| objectidentity.c:8:13:8:22 | p_autostg1 | automatic storage duration | file://:0:0:0:0 | int | +| objectidentity.c:8:31:8:40 | l_autostg2 | automatic storage duration | file://:0:0:0:0 | int | +| objectidentity.c:12:14:12:23 | l_statstg1 | static storage duration | file://:0:0:0:0 | int | +| objectidentity.c:13:14:13:23 | l_statstg2 | static storage duration | file://:0:0:0:0 | int | +| objectidentity.c:17:15:17:24 | g_thrdstg1 | thread storage duration | file://:0:0:0:0 | int | +| objectidentity.c:18:22:18:31 | g_thrdstg2 | thread storage duration | file://:0:0:0:0 | int | +| objectidentity.c:19:22:19:31 | g_thrdstg3 | thread storage duration | file://:0:0:0:0 | int | +| objectidentity.c:21:24:21:33 | l_statstg3 | thread storage duration | file://:0:0:0:0 | int | +| objectidentity.c:22:24:22:33 | l_statstg4 | thread storage duration | file://:0:0:0:0 | int | +| objectidentity.c:35:11:35:20 | g_statstg4 | static storage duration | file://:0:0:0:0 | s * | +| objectidentity.c:35:35:35:37 | {...} | static storage duration | objectidentity.c:27:8:27:8 | s | +| objectidentity.c:35:36:35:36 | 0 | static storage duration | file://:0:0:0:0 | int | +| objectidentity.c:36:7:36:16 | g_statstg5 | static storage duration | file://:0:0:0:0 | char * | +| objectidentity.c:36:20:36:26 | hello | static storage duration | file://:0:0:0:0 | char[6] | +| objectidentity.c:38:3:38:3 | 1 | static storage duration | file://:0:0:0:0 | int | +| objectidentity.c:39:3:39:9 | hello | static storage duration | file://:0:0:0:0 | char[6] | +| objectidentity.c:40:3:40:15 | {...} | automatic storage duration | objectidentity.c:27:8:27:8 | s | +| objectidentity.c:40:14:40:14 | 1 | static storage duration | file://:0:0:0:0 | int | diff --git a/c/common/test/library/objects/ObjectIdentity.ql b/c/common/test/library/objects/ObjectIdentity.ql new file mode 100644 index 0000000000..0e92e588ba --- /dev/null +++ b/c/common/test/library/objects/ObjectIdentity.ql @@ -0,0 +1,5 @@ +import codingstandards.c.Objects + +from ObjectIdentity obj +where obj.getFile().getBaseName() = "objectidentity.c" +select obj, obj.getStorageDuration(), obj.getType() diff --git a/c/common/test/library/objects/objectidentity.c b/c/common/test/library/objects/objectidentity.c new file mode 100644 index 0000000000..066f68b1fd --- /dev/null +++ b/c/common/test/library/objects/objectidentity.c @@ -0,0 +1,41 @@ +#include "threads.h" +// Basic static storage duration +int g_statstg1; +extern int g_statstg2; +static int g_statstg3; + +// Basic automatic storage duration +void f1(int p_autostg1) { int l_autostg2; } + +// Block identifiers with static storage duration +void f2(void) { + extern int l_statstg1; + static int l_statstg2; +} + +// Thread storage duration +_Thread_local g_thrdstg1; +extern _Thread_local g_thrdstg2; +static _Thread_local g_thrdstg3; +void f3() { + extern _Thread_local l_statstg3; + static _Thread_local l_statstg4; +} + +// Struct declarations do not allocate storage, and do not have a storage +// duration. +struct s { + int m; +}; + +// Enums and enum constants are not variables and have no linkage. +enum e { E1 }; + +// Various literals: +struct s *g_statstg4 = &(struct s){0}; +char *g_statstg5 = "hello"; +void f4(void) { + 1; + "hello"; + (struct s){1}; +} \ No newline at end of file diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index 71afef5e70..28785ce465 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.32.0-dev +version: 2.52.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/common/test/rules/amixedusemacroargumentsubjecttoexpansion/AMixedUseMacroArgumentSubjectToExpansion.expected b/c/common/test/rules/amixedusemacroargumentsubjecttoexpansion/AMixedUseMacroArgumentSubjectToExpansion.expected new file mode 100644 index 0000000000..d5f6f296d9 --- /dev/null +++ b/c/common/test/rules/amixedusemacroargumentsubjecttoexpansion/AMixedUseMacroArgumentSubjectToExpansion.expected @@ -0,0 +1,2 @@ +| test.c:5:1:5:41 | #define BAD_MACRO_WITH_ARG(x) (x) + wow ## x | Macro BAD_MACRO_WITH_ARG contains use of parameter x used in multiple contexts. | +| test.c:6:1:6:48 | #define BAD_MACRO_WITH_ARG_TWO(x,y) (x) + wow ## x | Macro BAD_MACRO_WITH_ARG_TWO contains use of parameter x used in multiple contexts. | diff --git a/c/common/test/rules/amixedusemacroargumentsubjecttoexpansion/AMixedUseMacroArgumentSubjectToExpansion.ql b/c/common/test/rules/amixedusemacroargumentsubjecttoexpansion/AMixedUseMacroArgumentSubjectToExpansion.ql new file mode 100644 index 0000000000..5aa514e86d --- /dev/null +++ b/c/common/test/rules/amixedusemacroargumentsubjecttoexpansion/AMixedUseMacroArgumentSubjectToExpansion.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.amixedusemacroargumentsubjecttoexpansion.AMixedUseMacroArgumentSubjectToExpansion + +class TestFileQuery extends AMixedUseMacroArgumentSubjectToExpansionSharedQuery, TestQuery { } diff --git a/c/common/test/rules/amixedusemacroargumentsubjecttoexpansion/test.c b/c/common/test/rules/amixedusemacroargumentsubjecttoexpansion/test.c new file mode 100644 index 0000000000..7eb5e204c7 --- /dev/null +++ b/c/common/test/rules/amixedusemacroargumentsubjecttoexpansion/test.c @@ -0,0 +1,26 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +#define GOOD_MACRO_WITH_ARG(X) ((X)*X##_scale) // COMPLIANT +#define MACRO 1 +#define BAD_MACRO_WITH_ARG(x) (x) + wow##x // NON_COMPLIANT +#define BAD_MACRO_WITH_ARG_TWO(x, y) (x) + wow##x // NON_COMPLIANT +#define MACROONE(x) #x // COMPLIANT +#define MACROTWO(x) x *x // COMPLIANT +#define MACROTHREE(x) "##\"\"'" + (x) // COMPLIANT +#define FOO(x) #x MACROONE(x) // COMPLIANT - no further arg expansion + +void f() { + + int x; + int x_scale; + int y; + int wowMACRO = 0; + + y = GOOD_MACRO_WITH_ARG(x); + wowMACRO = BAD_MACRO_WITH_ARG(MACRO); + wowMACRO = BAD_MACRO_WITH_ARG_TWO(MACRO, 1); + char s[] = MACROONE(MACRO); + y = MACROTWO(MACRO); + MACROTHREE(MACRO); + FOO(x); +} \ No newline at end of file diff --git a/c/common/test/rules/atofatoiatolandatollused/AtofAtoiAtolAndAtollUsed.expected b/c/common/test/rules/atofatoiatolandatollused/AtofAtoiAtolAndAtollUsed.expected new file mode 100644 index 0000000000..489a990582 --- /dev/null +++ b/c/common/test/rules/atofatoiatolandatollused/AtofAtoiAtolAndAtollUsed.expected @@ -0,0 +1,4 @@ +| test.c:8:14:8:17 | call to atof | Call to banned function atof. | +| test.c:9:12:9:15 | call to atoi | Call to banned function atoi. | +| test.c:10:13:10:16 | call to atol | Call to banned function atol. | +| test.c:11:18:11:22 | call to atoll | Call to banned function atoll. | diff --git a/c/common/test/rules/atofatoiatolandatollused/AtofAtoiAtolAndAtollUsed.ql b/c/common/test/rules/atofatoiatolandatollused/AtofAtoiAtolAndAtollUsed.ql new file mode 100644 index 0000000000..6da5fe6097 --- /dev/null +++ b/c/common/test/rules/atofatoiatolandatollused/AtofAtoiAtolAndAtollUsed.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.atofatoiatolandatollused.AtofAtoiAtolAndAtollUsed + +class TestFileQuery extends AtofAtoiAtolAndAtollUsedSharedQuery, TestQuery { } diff --git a/c/common/test/rules/atofatoiatolandatollused/test.c b/c/common/test/rules/atofatoiatolandatollused/test.c new file mode 100644 index 0000000000..f8140af79a --- /dev/null +++ b/c/common/test/rules/atofatoiatolandatollused/test.c @@ -0,0 +1,13 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +#include +#include +void f2(); +void f1() { + char l1[5] = "abcd"; + float l2 = atof(l1); // NON_COMLIANT + int l3 = atoi(l1); // NON_COMPLIANT + long l4 = atol(l1); // NON_COMPLIANT + long long l5 = atoll(l1); // NON_COMPLIANT + f2(); // COMPLIANT +} diff --git a/c/common/test/rules/bitfieldshallhaveanappropriatetype/BitFieldShallHaveAnAppropriateType.expected b/c/common/test/rules/bitfieldshallhaveanappropriatetype/BitFieldShallHaveAnAppropriateType.expected new file mode 100644 index 0000000000..f04b1b6ce9 --- /dev/null +++ b/c/common/test/rules/bitfieldshallhaveanappropriatetype/BitFieldShallHaveAnAppropriateType.expected @@ -0,0 +1,4 @@ +| test.c:8:7:8:8 | x1 | Bit-field 'x1' is declared on type 'int'. | +| test.c:12:15:12:16 | x5 | Bit-field 'x5' is declared on type 'signed long'. | +| test.c:14:15:14:16 | x6 | Bit-field 'x6' is declared on type 'signed char'. | +| test.c:16:14:16:15 | x7 | Bit-field 'x7' is declared on type 'Color'. | diff --git a/c/common/test/rules/bitfieldshallhaveanappropriatetype/BitFieldShallHaveAnAppropriateType.ql b/c/common/test/rules/bitfieldshallhaveanappropriatetype/BitFieldShallHaveAnAppropriateType.ql new file mode 100644 index 0000000000..a3e1ecc76c --- /dev/null +++ b/c/common/test/rules/bitfieldshallhaveanappropriatetype/BitFieldShallHaveAnAppropriateType.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.bitfieldshallhaveanappropriatetype.BitFieldShallHaveAnAppropriateType + +class TestFileQuery extends BitFieldShallHaveAnAppropriateTypeSharedQuery, TestQuery { } diff --git a/c/common/test/rules/bitfieldshallhaveanappropriatetype/test.c b/c/common/test/rules/bitfieldshallhaveanappropriatetype/test.c new file mode 100644 index 0000000000..c418e0e4fc --- /dev/null +++ b/c/common/test/rules/bitfieldshallhaveanappropriatetype/test.c @@ -0,0 +1,17 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +typedef unsigned int UINT16; + +enum Color { R, G, B }; + +struct SampleStruct { + int x1 : 2; // NON_COMPLIANT - not explicitly signed or unsigned + unsigned int x2 : 2; // COMPLIANT - explicitly unsigned + signed int x3 : 2; // COMPLIANT - explicitly signed + UINT16 x4 : 2; // COMPLIANT - type alias resolves to a compliant type + signed long x5 : 2; // NON_COMPLIANT - cannot declare bit field for long, even + // if it's signed + signed char x6 : 2; // NON_COMPLIANT - cannot declare bit field for char, even + // if it's signed + enum Color x7 : 3; // NON_COMPLIANT - cannot declare bit field for enum +} sample_struct; diff --git a/c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected b/c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected new file mode 100644 index 0000000000..c318f791e9 --- /dev/null +++ b/c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected @@ -0,0 +1,21 @@ +| test.c:9:7:9:14 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:30:11:30:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:31:3:31:13 | (unsigned int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:31:11:31:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:33:11:33:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:34:11:34:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:35:3:35:13 | (unsigned int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:35:11:35:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:36:3:36:13 | (unsigned int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:36:11:36:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:37:3:37:13 | (unsigned int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:37:11:37:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:38:3:38:13 | (unsigned int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:38:11:38:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:39:11:39:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:40:11:40:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:41:3:41:13 | (unsigned int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:41:11:41:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:42:12:42:13 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:44:11:44:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:45:11:45:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | diff --git a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.clang b/c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected.clang similarity index 75% rename from c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.clang rename to c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected.clang index 1cf143a196..0378c8a6b5 100644 --- a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.clang +++ b/c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected.clang @@ -1,8 +1,6 @@ -| test.c:7:7:7:14 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:28:3:28:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:29:3:29:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:9:7:9:14 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:30:3:30:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:31:3:31:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:32:3:32:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:33:3:33:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:34:3:34:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:35:3:35:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | @@ -10,6 +8,8 @@ | test.c:37:3:37:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:38:3:38:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:39:3:39:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:40:3:40:14 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:42:11:42:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:43:11:43:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:40:3:40:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:41:3:41:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:42:3:42:14 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:44:11:44:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:45:11:45:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | diff --git a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.gcc b/c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected.gcc similarity index 78% rename from c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.gcc rename to c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected.gcc index 1cf143a196..f729c9e42d 100644 --- a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.gcc +++ b/c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected.gcc @@ -1,8 +1,6 @@ -| test.c:7:7:7:14 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:28:3:28:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:29:3:29:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:9:7:9:14 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:30:3:30:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:31:3:31:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:32:3:32:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:33:3:33:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:34:3:34:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:35:3:35:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | @@ -10,6 +8,8 @@ | test.c:37:3:37:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:38:3:38:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:39:3:39:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:40:3:40:14 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:42:11:42:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:40:3:40:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:41:3:41:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:42:3:42:14 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:43:11:43:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:44:11:44:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | diff --git a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.qcc b/c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected.qcc similarity index 75% rename from c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.qcc rename to c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected.qcc index fec6522014..551423495c 100644 --- a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.qcc +++ b/c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected.qcc @@ -1,8 +1,6 @@ -| test.c:7:7:7:14 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:28:3:28:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:29:3:29:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:9:7:9:14 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:30:3:30:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:31:3:31:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:32:3:32:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:33:3:33:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:34:3:34:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:35:3:35:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | @@ -10,6 +8,8 @@ | test.c:37:3:37:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:38:3:38:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:39:3:39:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:40:3:40:14 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:42:3:42:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:43:3:43:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:40:3:40:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:41:3:41:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:42:3:42:14 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:44:3:44:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:45:3:45:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | diff --git a/c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.ql b/c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.ql new file mode 100644 index 0000000000..2a1e49774f --- /dev/null +++ b/c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.castcharbeforeconvertingtolargersizes.CastCharBeforeConvertingToLargerSizes + +class TestFileQuery extends CastCharBeforeConvertingToLargerSizesSharedQuery, TestQuery { } diff --git a/c/common/test/rules/castcharbeforeconvertingtolargersizes/test.c b/c/common/test/rules/castcharbeforeconvertingtolargersizes/test.c new file mode 100644 index 0000000000..8865e477fb --- /dev/null +++ b/c/common/test/rules/castcharbeforeconvertingtolargersizes/test.c @@ -0,0 +1,111 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +#include +#include + +int f1() { + char *c_str; + int c; + c = *c_str++; // NON_COMPLIANT + return (c); +} + +int f2() { + unsigned char *c_str; + int c; + c = *c_str++; // COMPLIANT + return (c); +} + +int f3(void) { + char *c_str; + int c; + c = (unsigned char)*c_str++; // COMPLIANT + return (c); +} + +void f4() { + char *t; + + isalnum(*t); // NON_COMPLIANT + isalpha(*t); // NON_COMPLIANT + // isascii(*t); // Not part of the C Standard + isblank(*t); // NON_COMPLIANT + iscntrl(*t); // NON_COMPLIANT + isdigit(*t); // NON_COMPLIANT + isgraph(*t); // NON_COMPLIANT + islower(*t); // NON_COMPLIANT + isprint(*t); // NON_COMPLIANT + ispunct(*t); // NON_COMPLIANT + isspace(*t); // NON_COMPLIANT + isupper(*t); // NON_COMPLIANT + isxdigit(*t); // NON_COMPLIANT + // toascii(i); // Not part of the C Standard + toupper(*t); // NON_COMPLIANT + tolower(*t); // NON_COMPLIANT +} + +void f5() { + unsigned char *t; + + isalnum(*t); // COMPLIANT + isalpha(*t); // COMPLIANT + // isascii(*t); // Not part of the C Standard + isblank(*t); // COMPLIANT + iscntrl(*t); // COMPLIANT + isdigit(*t); // COMPLIANT + isgraph(*t); // COMPLIANT + islower(*t); // COMPLIANT + isprint(*t); // COMPLIANT + ispunct(*t); // COMPLIANT + isspace(*t); // COMPLIANT + isupper(*t); // COMPLIANT + isxdigit(*t); // COMPLIANT + // toascii(i); // Not part of the C Standard + toupper(*t); // COMPLIANT + tolower(*t); // COMPLIANT +} + +void f6() { + char *t; + + isalnum((unsigned char)*t); // COMPLIANT + isalpha((unsigned char)*t); // COMPLIANT + // isascii((unsigned char*)*t); // Not part of the C Standard + isblank((unsigned char)*t); // COMPLIANT + iscntrl((unsigned char)*t); // COMPLIANT + isdigit((unsigned char)*t); // COMPLIANT + isgraph((unsigned char)*t); // COMPLIANT + islower((unsigned char)*t); // COMPLIANT + isprint((unsigned char)*t); // COMPLIANT + ispunct((unsigned char)*t); // COMPLIANT + isspace((unsigned char)*t); // COMPLIANT + isupper((unsigned char)*t); // COMPLIANT + isxdigit((unsigned char)*t); // COMPLIANT + // toascii((unsigned int) i); // Not part of the C Standard + toupper((unsigned char)*t); // COMPLIANT + tolower((unsigned char)*t); // COMPLIANT +} + +void f7() { + int t; + + // Note these are all NON_COMPLIANT under STR37-C + + isalnum(t); // COMPLIANT + isalpha(t); // COMPLIANT + // isascii(t); // Not part of the C Standard + isblank(t); // COMPLIANT + iscntrl(t); // COMPLIANT + isdigit(t); // COMPLIANT + isgraph(t); // COMPLIANT + islower(t); // COMPLIANT + isprint(t); // COMPLIANT + ispunct(t); // COMPLIANT + isspace(t); // COMPLIANT + isupper(t); // COMPLIANT + isxdigit(t); // COMPLIANT + // toascii(i); // Not part of the C Standard + toupper(t); // COMPLIANT + tolower(t); // COMPLIANT +} diff --git a/c/common/test/rules/constlikereturnvalue/ConstLikeReturnValue.expected b/c/common/test/rules/constlikereturnvalue/ConstLikeReturnValue.expected index 94e63062c5..d7dfc6c13f 100644 --- a/c/common/test/rules/constlikereturnvalue/ConstLikeReturnValue.expected +++ b/c/common/test/rules/constlikereturnvalue/ConstLikeReturnValue.expected @@ -1,20 +1,20 @@ problems -| test.c:8:8:8:12 | c_str | test.c:15:16:15:21 | call to getenv | test.c:8:8:8:12 | c_str | The object returned by the function getenv should not be modified. | -| test.c:64:5:64:9 | conv4 | test.c:61:11:61:20 | call to localeconv | test.c:64:5:64:9 | conv4 | The object returned by the function localeconv should not be modified. | -| test.c:73:5:73:8 | conv | test.c:69:25:69:34 | call to localeconv | test.c:73:5:73:8 | conv | The object returned by the function localeconv should not be modified. | +| test.c:11:8:11:12 | c_str | test.c:18:16:18:21 | call to getenv | test.c:11:8:11:12 | c_str | The object returned by the function getenv should not be modified. | +| test.c:67:5:67:9 | conv4 | test.c:64:11:64:20 | call to localeconv | test.c:67:5:67:9 | conv4 | The object returned by the function localeconv should not be modified. | +| test.c:76:5:76:8 | conv | test.c:72:25:72:34 | call to localeconv | test.c:76:5:76:8 | conv | The object returned by the function localeconv should not be modified. | edges -| test.c:5:18:5:22 | c_str | test.c:8:8:8:12 | c_str | -| test.c:15:16:15:21 | call to getenv | test.c:21:9:21:12 | env1 | -| test.c:21:9:21:12 | env1 | test.c:5:18:5:22 | c_str | -| test.c:61:11:61:20 | call to localeconv | test.c:64:5:64:9 | conv4 | -| test.c:69:25:69:34 | call to localeconv | test.c:73:5:73:8 | conv | +| test.c:8:18:8:22 | c_str | test.c:11:8:11:12 | c_str | provenance | | +| test.c:18:16:18:21 | call to getenv | test.c:24:9:24:12 | env1 | provenance | | +| test.c:24:9:24:12 | env1 | test.c:8:18:8:22 | c_str | provenance | | +| test.c:64:11:64:20 | call to localeconv | test.c:67:5:67:9 | conv4 | provenance | | +| test.c:72:25:72:34 | call to localeconv | test.c:76:5:76:8 | conv | provenance | | nodes -| test.c:5:18:5:22 | c_str | semmle.label | c_str | -| test.c:8:8:8:12 | c_str | semmle.label | c_str | -| test.c:15:16:15:21 | call to getenv | semmle.label | call to getenv | -| test.c:21:9:21:12 | env1 | semmle.label | env1 | -| test.c:61:11:61:20 | call to localeconv | semmle.label | call to localeconv | -| test.c:64:5:64:9 | conv4 | semmle.label | conv4 | -| test.c:69:25:69:34 | call to localeconv | semmle.label | call to localeconv | -| test.c:73:5:73:8 | conv | semmle.label | conv | +| test.c:8:18:8:22 | c_str | semmle.label | c_str | +| test.c:11:8:11:12 | c_str | semmle.label | c_str | +| test.c:18:16:18:21 | call to getenv | semmle.label | call to getenv | +| test.c:24:9:24:12 | env1 | semmle.label | env1 | +| test.c:64:11:64:20 | call to localeconv | semmle.label | call to localeconv | +| test.c:67:5:67:9 | conv4 | semmle.label | conv4 | +| test.c:72:25:72:34 | call to localeconv | semmle.label | call to localeconv | +| test.c:76:5:76:8 | conv | semmle.label | conv | subpaths diff --git a/c/common/test/rules/constlikereturnvalue/test.c b/c/common/test/rules/constlikereturnvalue/test.c index cd7c101898..e28c05961f 100644 --- a/c/common/test/rules/constlikereturnvalue/test.c +++ b/c/common/test/rules/constlikereturnvalue/test.c @@ -1,4 +1,7 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. #include +#include #include #include diff --git a/c/cert/test/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.expected b/c/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.expected similarity index 100% rename from c/cert/test/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.expected rename to c/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.expected diff --git a/c/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.ql b/c/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.ql new file mode 100644 index 0000000000..dc3a521edf --- /dev/null +++ b/c/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.ql @@ -0,0 +1,6 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.donotpassaliasedpointertorestrictqualifiedparamshared.DoNotPassAliasedPointerToRestrictQualifiedParamShared + +class TestFileQuery extends DoNotPassAliasedPointerToRestrictQualifiedParamSharedSharedQuery, + TestQuery +{ } diff --git a/c/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/test.c b/c/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/test.c new file mode 100644 index 0000000000..3bf7cfa490 --- /dev/null +++ b/c/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/test.c @@ -0,0 +1,100 @@ +#include +#include +#include + +int *restrict g1; +int *restrict g2; +int *restrict g1_1; +int *g2_1; + +struct s1 { + int x, y, z; +}; +struct s1 v1; + +void test_global_local() { + int *restrict i1 = g1; // COMPLIANT + int *restrict i2 = g2; // COMPLIANT + int *restrict i3 = i2; // NON_COMPLIANT + g1 = g2; // NON_COMPLIANT + i1 = i2; // NON_COMPLIANT + { + int *restrict i4; + int *restrict i5; + int *restrict i6; + i4 = g1; // COMPLIANT + i4 = (void *)0; // COMPLIANT + i5 = g1; // NON_COMPLIANT - block rather than statement scope matters + i4 = g1; // NON_COMPLIANT + i6 = g2; // COMPLIANT + } +} + +void test_global_local_1() { + g1_1 = g2_1; // COMPLIANT +} + +void test_structs() { + struct s1 *restrict p1 = &v1; + int *restrict px = &v1.x; // NON_COMPLIANT + { + int *restrict py; + int *restrict pz; + py = &v1.y; // COMPLIANT + py = (int *)0; + pz = &v1.z; // NON_COMPLIANT - block rather than statement scope matters + py = &v1.y; // NON_COMPLIANT + } +} + +void copy(int *restrict p1, int *restrict p2, size_t s) { + for (size_t i = 0; i < s; ++i) { + p2[i] = p1[i]; + } +} + +void test_restrict_params() { + int i1 = 1; + int i2 = 2; + copy(&i1, &i1, 1); // NON_COMPLIANT + copy(&i1, &i2, 1); // COMPLIANT + + int x[10]; + int *px = &x[0]; + copy(&x[0], &x[1], 1); // COMPLIANT - non overlapping + copy(&x[0], &x[1], 2); // NON_COMPLIANT - overlapping + copy(&x[0], (int *)x[0], 1); // COMPLIANT - non overlapping + copy(&x[0], px, 1); // NON_COMPLIANT - overlapping +} + +void test_strcpy() { + char s1[] = "my test string"; + char s2[] = "my other string"; + strcpy(&s1, &s1 + 3); // NON_COMPLIANT + strcpy(&s2, &s1); // COMPLIANT +} + +void test_memcpy() { + char s1[] = "my test string"; + char s2[] = "my other string"; + memcpy(&s1, &s1 + 3, 5); // NON_COMPLIANT + memcpy(&s2, &s1 + 3, 5); // COMPLIANT +} + +void test_memmove() { + char s1[] = "my test string"; + char s2[] = "my other string"; + memmove(&s1, &s1 + 3, 5); // COMPLIANT - memmove is allowed to overlap + memmove(&s2, &s1 + 3, 5); // COMPLIANT +} + +void test_scanf() { + char s1[200] = "%10s"; + scanf(&s1, &s1 + 4); // NON_COMPLIANT +} + +// TODO also consider the following: +// strncpy(), strncpy_s() +// strcat(), strcat_s() +// strncat(), strncat_s() +// strtok_s() \ No newline at end of file diff --git a/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected b/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected index d0ba3bdb5c..75866b8503 100644 --- a/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected +++ b/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected @@ -4,14 +4,14 @@ problems | test.c:13:10:13:11 | p4 | test.c:5:14:5:15 | l2 | test.c:13:10:13:11 | p4 | Subtraction between left operand pointing to array $@ and other operand pointing to array $@. | test.c:3:7:3:8 | l2 | l2 | test.c:2:7:2:8 | l1 | l1 | | test.c:13:15:13:16 | l1 | test.c:13:15:13:16 | l1 | test.c:13:15:13:16 | l1 | Subtraction between right operand pointing to array $@ and other operand pointing to array $@. | test.c:2:7:2:8 | l1 | l1 | test.c:3:7:3:8 | l2 | l2 | edges -| test.c:4:14:4:15 | l1 | test.c:4:14:4:18 | access to array | -| test.c:4:14:4:18 | access to array | test.c:10:10:10:11 | p1 | -| test.c:4:14:4:18 | access to array | test.c:12:10:12:11 | p1 | -| test.c:5:14:5:15 | l2 | test.c:5:14:5:19 | access to array | -| test.c:5:14:5:19 | access to array | test.c:11:10:11:11 | p2 | -| test.c:5:14:5:19 | access to array | test.c:12:15:12:16 | p2 | -| test.c:5:14:5:19 | access to array | test.c:13:10:13:11 | p4 | -| test.c:5:14:5:19 | access to array | test.c:14:10:14:11 | p4 | +| test.c:4:14:4:15 | l1 | test.c:4:14:4:18 | access to array | provenance | Config | +| test.c:4:14:4:18 | access to array | test.c:10:10:10:11 | p1 | provenance | | +| test.c:4:14:4:18 | access to array | test.c:12:10:12:11 | p1 | provenance | | +| test.c:5:14:5:15 | l2 | test.c:5:14:5:19 | access to array | provenance | Config | +| test.c:5:14:5:19 | access to array | test.c:11:10:11:11 | p2 | provenance | | +| test.c:5:14:5:19 | access to array | test.c:12:15:12:16 | p2 | provenance | | +| test.c:5:14:5:19 | access to array | test.c:13:10:13:11 | p4 | provenance | | +| test.c:5:14:5:19 | access to array | test.c:14:10:14:11 | p4 | provenance | | nodes | test.c:4:14:4:15 | l1 | semmle.label | l1 | | test.c:4:14:4:18 | access to array | semmle.label | access to array | diff --git a/c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected b/c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected index 1d487765df..bc471c0dc4 100644 --- a/c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected +++ b/c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected @@ -1,5 +1,5 @@ -| test.c:4:13:4:18 | ... + ... | Array pointer p2 points 1 element passed the end of $@. | test.c:2:7:2:8 | l1 | l1 | -| test.c:5:13:5:18 | ... + ... | Array pointer p3 points 1 element passed the end of $@. | test.c:2:7:2:8 | l1 | l1 | -| test.c:6:13:6:18 | & ... | Array pointer p4 points 1 element passed the end of $@. | test.c:2:7:2:8 | l1 | l1 | -| test.c:11:8:11:11 | ... -- | Array pointer p7 points 1 element passed the end of $@. | test.c:2:7:2:8 | l1 | l1 | -| test.c:12:8:12:9 | p3 | Array pointer p8 points 1 element passed the end of $@. | test.c:2:7:2:8 | l1 | l1 | +| test.c:4:13:4:18 | ... + ... | Array pointer p2 points 1 element past the end of $@. | test.c:2:7:2:8 | l1 | l1 | +| test.c:5:13:5:18 | ... + ... | Array pointer p3 points 1 element past the end of $@. | test.c:2:7:2:8 | l1 | l1 | +| test.c:6:13:6:18 | & ... | Array pointer p4 points 1 element past the end of $@. | test.c:2:7:2:8 | l1 | l1 | +| test.c:11:8:11:11 | ... -- | Array pointer p7 points 1 element past the end of $@. | test.c:2:7:2:8 | l1 | l1 | +| test.c:12:8:12:9 | p3 | Array pointer p8 points 1 element past the end of $@. | test.c:2:7:2:8 | l1 | l1 | diff --git a/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected b/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected index 8db569a98d..bda6c7ad05 100644 --- a/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected +++ b/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected @@ -10,19 +10,19 @@ problems | test.c:25:7:25:14 | ... >= ... | test.c:7:14:7:15 | l1 | test.c:25:7:25:8 | p1 | Compare operation >= comparing left operand pointing to array $@ and other operand pointing to array $@. | test.c:2:7:2:8 | l1 | l1 | test.c:4:7:4:8 | l3 | l3 | | test.c:25:7:25:14 | ... >= ... | test.c:25:13:25:14 | l3 | test.c:25:13:25:14 | l3 | Compare operation >= comparing right operand pointing to array $@ and other operand pointing to array $@. | test.c:4:7:4:8 | l3 | l3 | test.c:2:7:2:8 | l1 | l1 | edges -| test.c:6:13:6:14 | l1 | test.c:13:12:13:13 | p0 | -| test.c:7:14:7:15 | l1 | test.c:7:14:7:18 | access to array | -| test.c:7:14:7:18 | access to array | test.c:11:7:11:8 | p1 | -| test.c:7:14:7:18 | access to array | test.c:13:7:13:8 | p1 | -| test.c:7:14:7:18 | access to array | test.c:15:13:15:14 | p1 | -| test.c:7:14:7:18 | access to array | test.c:17:7:17:8 | p1 | -| test.c:7:14:7:18 | access to array | test.c:23:13:23:14 | p1 | -| test.c:7:14:7:18 | access to array | test.c:25:7:25:8 | p1 | -| test.c:8:14:8:15 | l1 | test.c:8:14:8:18 | access to array | -| test.c:8:14:8:18 | access to array | test.c:11:12:11:13 | p2 | -| test.c:8:14:8:18 | access to array | test.c:21:7:21:8 | p2 | -| test.c:9:14:9:15 | l2 | test.c:9:14:9:18 | access to array | -| test.c:9:14:9:18 | access to array | test.c:21:12:21:13 | p3 | +| test.c:6:13:6:14 | l1 | test.c:13:12:13:13 | p0 | provenance | | +| test.c:7:14:7:15 | l1 | test.c:7:14:7:18 | access to array | provenance | Config | +| test.c:7:14:7:18 | access to array | test.c:11:7:11:8 | p1 | provenance | | +| test.c:7:14:7:18 | access to array | test.c:13:7:13:8 | p1 | provenance | | +| test.c:7:14:7:18 | access to array | test.c:15:13:15:14 | p1 | provenance | | +| test.c:7:14:7:18 | access to array | test.c:17:7:17:8 | p1 | provenance | | +| test.c:7:14:7:18 | access to array | test.c:23:13:23:14 | p1 | provenance | | +| test.c:7:14:7:18 | access to array | test.c:25:7:25:8 | p1 | provenance | | +| test.c:8:14:8:15 | l1 | test.c:8:14:8:18 | access to array | provenance | Config | +| test.c:8:14:8:18 | access to array | test.c:11:12:11:13 | p2 | provenance | | +| test.c:8:14:8:18 | access to array | test.c:21:7:21:8 | p2 | provenance | | +| test.c:9:14:9:15 | l2 | test.c:9:14:9:18 | access to array | provenance | Config | +| test.c:9:14:9:18 | access to array | test.c:21:12:21:13 | p3 | provenance | | nodes | test.c:6:13:6:14 | l1 | semmle.label | l1 | | test.c:7:14:7:15 | l1 | semmle.label | l1 | diff --git a/c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected b/c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected new file mode 100644 index 0000000000..dc72201a8a --- /dev/null +++ b/c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected @@ -0,0 +1 @@ +| test.c:16:3:16:8 | call to remove | Return value from remove is not tested for errors. | diff --git a/c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.ql b/c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.ql new file mode 100644 index 0000000000..12c2196efd --- /dev/null +++ b/c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.functionerroneousreturnvaluenottested.FunctionErroneousReturnValueNotTested + +class TestFileQuery extends FunctionErroneousReturnValueNotTestedSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/M0-3-2/test.cpp b/c/common/test/rules/functionerroneousreturnvaluenottested/test.c similarity index 100% rename from cpp/autosar/test/rules/M0-3-2/test.cpp rename to c/common/test/rules/functionerroneousreturnvaluenottested/test.c diff --git a/c/common/test/rules/functionlikemacrosdefined/FunctionLikeMacrosDefined.expected b/c/common/test/rules/functionlikemacrosdefined/FunctionLikeMacrosDefined.expected new file mode 100644 index 0000000000..c9a9eb0d48 --- /dev/null +++ b/c/common/test/rules/functionlikemacrosdefined/FunctionLikeMacrosDefined.expected @@ -0,0 +1,2 @@ +| test.c:8:1:8:25 | #define MACRO4(x) (x + 1) | Macro used instead of a function. | +| test.c:13:1:13:48 | #define MACRO9() printf_custom("output = %d", 7) | Macro used instead of a function. | diff --git a/c/common/test/rules/functionlikemacrosdefined/FunctionLikeMacrosDefined.ql b/c/common/test/rules/functionlikemacrosdefined/FunctionLikeMacrosDefined.ql new file mode 100644 index 0000000000..29088c4458 --- /dev/null +++ b/c/common/test/rules/functionlikemacrosdefined/FunctionLikeMacrosDefined.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.functionlikemacrosdefined.FunctionLikeMacrosDefined + +class TestFileQuery extends FunctionLikeMacrosDefinedSharedQuery, TestQuery { } diff --git a/c/common/test/rules/functionlikemacrosdefined/test.c b/c/common/test/rules/functionlikemacrosdefined/test.c new file mode 100644 index 0000000000..ee36549b8d --- /dev/null +++ b/c/common/test/rules/functionlikemacrosdefined/test.c @@ -0,0 +1,42 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +#include + +#define MACRO(OP, L, R) ((L)OP(R)) // COMPLIANT +#define MACRO2(L, R) (L + R) // COMPLIANT +#define MACRO3(L, R) (L " " R " " L) // COMPLIANT +#define MACRO4(x) (x + 1) // NON_COMPLIANT +#define MACRO5(L, LR) (LR + 1) // COMPLIANT +#define MACRO6(x) printf_custom("output = %d", test##x) // COMPLIANT +#define MACRO7(x) #x // COMPLIANT +#define MACRO8(x) "NOP" // COMPLIANT +#define MACRO9() printf_custom("output = %d", 7) // NON_COMPLIANT +#define MACRO10(x) // COMPLIANT +#define MY_ASSERT(X) assert(X) // NON_COMPLIANT[FALSE_NEGATIVE] + +char a1[MACRO2(1, 1) + 6]; +extern int printf_custom(char *, int); +int test1; + +void f() { + int i = MACRO(+, 1, 1); + int i2 = MACRO2(7, 10); + + static int i3 = MACRO2(1, 1); + + char *i4 = MACRO3("prefix", "suffix"); + + int i5 = MACRO4(1); + + int i6 = MACRO4(MACRO2(1, 1)); + + int i7 = MACRO5(1, 1); + + MACRO6(1); + + char *i10 = MACRO7("prefix"); + + asm(MACRO8(1)); + + MY_ASSERT(1); +} \ No newline at end of file diff --git a/c/common/test/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.expected b/c/common/test/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.expected new file mode 100644 index 0000000000..5aede0a5ba --- /dev/null +++ b/c/common/test/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.expected @@ -0,0 +1,3 @@ +| test.c:9:16:9:31 | test_noreturn_f2 | The function test_noreturn_f2 declared with attribute _Noreturn returns a value. | +| test.c:34:16:34:31 | test_noreturn_f5 | The function test_noreturn_f5 declared with attribute _Noreturn returns a value. | +| test.c:49:32:49:47 | test_noreturn_f7 | The function test_noreturn_f7 declared with attribute _Noreturn returns a value. | diff --git a/c/common/test/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.ql b/c/common/test/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.ql new file mode 100644 index 0000000000..4af4aeceaf --- /dev/null +++ b/c/common/test/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.functionnoreturnattributecondition.FunctionNoReturnAttributeCondition + +class TestFileQuery extends FunctionNoReturnAttributeConditionSharedQuery, TestQuery { } diff --git a/c/common/test/rules/functionnoreturnattributecondition/test.c b/c/common/test/rules/functionnoreturnattributecondition/test.c new file mode 100644 index 0000000000..c13654a8e0 --- /dev/null +++ b/c/common/test/rules/functionnoreturnattributecondition/test.c @@ -0,0 +1,88 @@ +#include "setjmp.h" +#include "stdlib.h" +#include "threads.h" + +_Noreturn void test_noreturn_f1(int i) { // COMPLIANT + abort(); +} + +_Noreturn void test_noreturn_f2(int i) { // NON_COMPLIANT + if (i > 0) { + abort(); + } + if (i < 0) { + abort(); + } +} + +_Noreturn void test_noreturn_f3(int i) { // COMPLIANT + if (i > 0) { + abort(); + } + exit(1); +} + +void test_noreturn_f4(int i) { // COMPLIANT + if (i > 0) { + abort(); + } + if (i < 0) { + abort(); + } +} + +_Noreturn void test_noreturn_f5(int i) { // NON_COMPLIANT + if (i > 0) { + abort(); + } +} + +_Noreturn void test_noreturn_f6(int i) { // COMPLIANT + if (i > 0) { + abort(); + } + while (1) { + i = 5; + } +} + +__attribute__((noreturn)) void test_noreturn_f7(int i) { // NON_COMPLIANT + if (i > 0) { + abort(); + } +} + +__attribute__((noreturn)) void test_noreturn_f8(int i) { // COMPLIANT + abort(); +} + +_Noreturn void test_noreturn_f9(int i) { // COMPLIANT + test_noreturn_f1(i); +} + +_Noreturn void test_noreturn_f10(int i) { // COMPLIANT + switch (i) { + case 0: + abort(); + break; + case 1: + exit(0); + break; + case 2: + _Exit(0); + break; + case 3: + quick_exit(0); + break; + case 4: + thrd_exit(0); + break; + default:; + jmp_buf jb; + longjmp(jb, 0); + } +} + +_Noreturn void test_noreturn_f11(int i) { // COMPLIANT + return test_noreturn_f11(i); +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected b/c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.expected similarity index 100% rename from c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected rename to c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.expected diff --git a/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected.clang b/c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.expected.clang similarity index 100% rename from c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected.clang rename to c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.expected.clang diff --git a/c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.ql b/c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.ql new file mode 100644 index 0000000000..25d273354d --- /dev/null +++ b/c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.functiontypesnotinprototypeformshared.FunctionTypesNotInPrototypeFormShared + +class TestFileQuery extends FunctionTypesNotInPrototypeFormSharedSharedQuery, TestQuery { } diff --git a/c/misra/test/rules/RULE-8-2/test.c b/c/common/test/rules/functiontypesnotinprototypeformshared/test.c similarity index 100% rename from c/misra/test/rules/RULE-8-2/test.c rename to c/common/test/rules/functiontypesnotinprototypeformshared/test.c diff --git a/c/misra/test/rules/RULE-8-2/test.c.clang b/c/common/test/rules/functiontypesnotinprototypeformshared/test.c.clang similarity index 100% rename from c/misra/test/rules/RULE-8-2/test.c.clang rename to c/common/test/rules/functiontypesnotinprototypeformshared/test.c.clang diff --git a/c/common/test/rules/gotoreferencealabelinsurroundingblock/GotoReferenceALabelInSurroundingBlock.expected b/c/common/test/rules/gotoreferencealabelinsurroundingblock/GotoReferenceALabelInSurroundingBlock.expected new file mode 100644 index 0000000000..7fd94b47f3 --- /dev/null +++ b/c/common/test/rules/gotoreferencealabelinsurroundingblock/GotoReferenceALabelInSurroundingBlock.expected @@ -0,0 +1,3 @@ +| test.c:4:3:4:10 | goto ... | The goto statement and its $@ are not declared or enclosed in the same block. | test.c:6:3:6:5 | label ...: | label | +| test.c:42:3:42:10 | goto ... | The goto statement and its $@ are not declared or enclosed in the same block. | test.c:46:3:46:5 | label ...: | label | +| test.c:57:5:57:12 | goto ... | The goto statement and its $@ are not declared or enclosed in the same block. | test.c:60:3:60:5 | label ...: | label | diff --git a/c/common/test/rules/gotoreferencealabelinsurroundingblock/GotoReferenceALabelInSurroundingBlock.ql b/c/common/test/rules/gotoreferencealabelinsurroundingblock/GotoReferenceALabelInSurroundingBlock.ql new file mode 100644 index 0000000000..f553135683 --- /dev/null +++ b/c/common/test/rules/gotoreferencealabelinsurroundingblock/GotoReferenceALabelInSurroundingBlock.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.gotoreferencealabelinsurroundingblock.GotoReferenceALabelInSurroundingBlock + +class TestFileQuery extends GotoReferenceALabelInSurroundingBlockSharedQuery, TestQuery { } diff --git a/c/common/test/rules/gotoreferencealabelinsurroundingblock/test.c b/c/common/test/rules/gotoreferencealabelinsurroundingblock/test.c new file mode 100644 index 0000000000..083e0fe57b --- /dev/null +++ b/c/common/test/rules/gotoreferencealabelinsurroundingblock/test.c @@ -0,0 +1,87 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +void f1() { + goto L1; + for (int i = 0; i < 100; i++) { + L1: // NON_COMPLIANT + break; + } +} + +void f2() { + int i = 0; + if (i >= 0) { + for (int j = 0; j < 10; j++) { + goto L2; + } + } +L2: // COMPLIANT + return; +} + +void f3() { + int i = 0; + if (i >= 0) { + for (int j = 0; j < 10; j++) { + goto L3; + L3: // COMPLIANT + break; + } + } +} + +void f4() { + int i = 0; +L4: // COMPLIANT + if (i >= 0) { + goto L4; + } +} + +void f5(int p) { + goto L1; + + switch (p) { + case 0: + L1:; // NON_COMPLIANT + break; + default: + break; + } +} + +void f6(int p) { + + switch (p) { + case 0: + goto L1; + break; + default: + L1: // NON_COMPLIANT + break; + } +} + +void f7(int p) { +L1: // COMPLIANT + switch (p) { + case 0: + goto L1; + break; + default: + break; + } +} + +void f8(int p) { + + switch (p) { + case 0: + goto L1; + ; + L1:; // COMPLIANT + break; + default: + break; + } +} diff --git a/c/common/test/rules/gotostatementcondition/GotoStatementCondition.expected b/c/common/test/rules/gotostatementcondition/GotoStatementCondition.expected index e522289c7b..c42642c343 100644 --- a/c/common/test/rules/gotostatementcondition/GotoStatementCondition.expected +++ b/c/common/test/rules/gotostatementcondition/GotoStatementCondition.expected @@ -1,3 +1,4 @@ -| test.c:5:3:5:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.c:5:3:5:10 | goto ... | L1 | test.c:2:1:2:3 | label ...: | label ...: | -| test.c:14:3:14:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.c:14:3:14:10 | goto ... | L2 | test.c:12:1:12:3 | label ...: | label ...: | -| test.c:16:3:16:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.c:16:3:16:10 | goto ... | L1 | test.c:11:1:11:3 | label ...: | label ...: | +| test.c:9:3:9:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.c:9:3:9:10 | goto ... | l1 | test.c:5:1:5:3 | label ...: | label ...: | +| test.c:21:3:21:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.c:21:3:21:10 | goto ... | l2 | test.c:17:1:17:3 | label ...: | label ...: | +| test.c:23:3:23:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.c:23:3:23:10 | goto ... | l1 | test.c:16:1:16:3 | label ...: | label ...: | +| test.c:28:3:28:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.c:28:3:28:10 | goto ... | l1 | test.c:27:1:27:3 | label ...: | label ...: | diff --git a/c/common/test/rules/gotostatementcondition/test.c b/c/common/test/rules/gotostatementcondition/test.c index 2c189cd433..48426261fe 100644 --- a/c/common/test/rules/gotostatementcondition/test.c +++ b/c/common/test/rules/gotostatementcondition/test.c @@ -1,17 +1,29 @@ -void f1() { -L1:; - goto L2; // COMPLIANT - ; - goto L1; // NON_COMPLIANT +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +void f1(int p1) { -L2:; +l1: + if (p1) { + goto l2; // COMPLIANT + } + goto l1; // NON_COMPLIANT + +l2:; } -void f2() { -L1:; -L2: - goto L3; // COMPLIANT - goto L2; // NON_COMPLIANT -L3: - goto L1; // NON_COMPLIANT +void f2(int p1) { + +l1:; +l2: + if (p1) { + goto l3; // COMPLIANT + } + goto l2; // NON_COMPLIANT +l3: + goto l1; // NON_COMPLIANT } + +void f3() { +l1: + goto l1; // NON_COMPLIANT +} \ No newline at end of file diff --git a/c/common/test/rules/gotostatementshouldnotbeused/GotoStatementShouldNotBeUsed.expected b/c/common/test/rules/gotostatementshouldnotbeused/GotoStatementShouldNotBeUsed.expected new file mode 100644 index 0000000000..15dc49ee37 --- /dev/null +++ b/c/common/test/rules/gotostatementshouldnotbeused/GotoStatementShouldNotBeUsed.expected @@ -0,0 +1 @@ +| test.c:6:3:6:14 | goto ... | Use of goto. | diff --git a/c/common/test/rules/gotostatementshouldnotbeused/GotoStatementShouldNotBeUsed.ql b/c/common/test/rules/gotostatementshouldnotbeused/GotoStatementShouldNotBeUsed.ql new file mode 100644 index 0000000000..1a117d5ddd --- /dev/null +++ b/c/common/test/rules/gotostatementshouldnotbeused/GotoStatementShouldNotBeUsed.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.gotostatementshouldnotbeused.GotoStatementShouldNotBeUsed + +class TestFileQuery extends GotoStatementShouldNotBeUsedSharedQuery, TestQuery { } diff --git a/c/common/test/rules/gotostatementshouldnotbeused/test.c b/c/common/test/rules/gotostatementshouldnotbeused/test.c new file mode 100644 index 0000000000..4ecc1789c7 --- /dev/null +++ b/c/common/test/rules/gotostatementshouldnotbeused/test.c @@ -0,0 +1,11 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +void test_goto() { + int x = 1; + + goto label1; // NON_COMPLIANT + +label1: + + x = 2; +} \ No newline at end of file diff --git a/c/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected b/c/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected index c52544450f..26a84ecd8a 100644 --- a/c/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected +++ b/c/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected @@ -1,6 +1,6 @@ -| test.c:19:14:19:19 | tmpvar | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.c:11:12:11:17 | call to getenv | call to getenv | test.c:15:13:15:18 | call to getenv | call to getenv | -| test.c:132:14:132:17 | temp | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.c:128:12:128:17 | call to getenv | call to getenv | test.c:129:11:129:16 | call to getenv | call to getenv | -| test.c:132:20:132:22 | tmp | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.c:129:11:129:16 | call to getenv | call to getenv | test.c:128:12:128:17 | call to getenv | call to getenv | -| test.c:163:14:163:26 | tmpvar_global | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.c:155:19:155:24 | call to getenv | call to getenv | test.c:159:20:159:25 | call to getenv | call to getenv | -| test.c:186:18:186:18 | r | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.c:183:7:183:15 | call to setlocale | call to setlocale | test.c:185:8:185:17 | call to localeconv | call to localeconv | -| test.c:206:10:206:15 | tmpvar | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.c:200:12:200:17 | call to getenv | call to getenv | test.c:204:3:204:8 | call to f11fun | call to f11fun | +| test.c:21:14:21:19 | tmpvar | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.c:13:12:13:17 | call to getenv | call to getenv | test.c:17:13:17:18 | call to getenv | call to getenv | +| test.c:134:14:134:17 | temp | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.c:130:12:130:17 | call to getenv | call to getenv | test.c:131:11:131:16 | call to getenv | call to getenv | +| test.c:134:20:134:22 | tmp | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.c:131:11:131:16 | call to getenv | call to getenv | test.c:130:12:130:17 | call to getenv | call to getenv | +| test.c:165:14:165:26 | tmpvar_global | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.c:157:19:157:24 | call to getenv | call to getenv | test.c:161:20:161:25 | call to getenv | call to getenv | +| test.c:188:18:188:18 | r | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.c:185:7:185:15 | call to setlocale | call to setlocale | test.c:187:8:187:17 | call to localeconv | call to localeconv | +| test.c:208:10:208:15 | tmpvar | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.c:202:12:202:17 | call to getenv | call to getenv | test.c:206:3:206:8 | call to f11fun | call to f11fun | diff --git a/c/common/test/rules/invalidatedenvstringpointers/test.c b/c/common/test/rules/invalidatedenvstringpointers/test.c index 59c9593d21..183a4891c1 100644 --- a/c/common/test/rules/invalidatedenvstringpointers/test.c +++ b/c/common/test/rules/invalidatedenvstringpointers/test.c @@ -1,3 +1,5 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. #include #include #include diff --git a/c/common/test/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.expected b/c/common/test/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.expected index 556a3fe4a8..628a4f99d6 100644 --- a/c/common/test/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.expected +++ b/c/common/test/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.expected @@ -1,2 +1,2 @@ -| test.c:13:19:13:24 | call to getenv | The value of variable $@ might become invalid after a subsequent call to function `getenv`. | test.c:10:7:10:19 | tmpvar_global | tmpvar_global | -| test.c:16:20:16:25 | call to getenv | The value of variable $@ might become invalid after a subsequent call to function `getenv`. | test.c:7:9:7:20 | tmpvar_field | tmpvar_field | +| test.c:15:19:15:24 | call to getenv | The value of variable $@ might become invalid after a subsequent call to function `getenv`. | test.c:12:7:12:19 | tmpvar_global | tmpvar_global | +| test.c:18:20:18:25 | call to getenv | The value of variable $@ might become invalid after a subsequent call to function `getenv`. | test.c:9:9:9:20 | tmpvar_field | tmpvar_field | diff --git a/c/common/test/rules/invalidatedenvstringpointerswarn/test.c b/c/common/test/rules/invalidatedenvstringpointerswarn/test.c index 2b678df6ac..6d4cec1d8d 100644 --- a/c/common/test/rules/invalidatedenvstringpointerswarn/test.c +++ b/c/common/test/rules/invalidatedenvstringpointerswarn/test.c @@ -1,3 +1,5 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. #include #include #include diff --git a/c/cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.expected b/c/common/test/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.expected similarity index 100% rename from c/cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.expected rename to c/common/test/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.expected diff --git a/c/common/test/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.ql b/c/common/test/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.ql new file mode 100644 index 0000000000..87188403af --- /dev/null +++ b/c/common/test/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.joinordetachthreadonlyonce.JoinOrDetachThreadOnlyOnce + +class TestFileQuery extends JoinOrDetachThreadOnlyOnceSharedQuery, TestQuery { } diff --git a/c/cert/test/rules/CON39-C/test.c b/c/common/test/rules/joinordetachthreadonlyonce/test.c similarity index 100% rename from c/cert/test/rules/CON39-C/test.c rename to c/common/test/rules/joinordetachthreadonlyonce/test.c diff --git a/c/common/test/rules/lowercaselstartsinliteralsuffix/LowercaseLStartsInLiteralSuffix.expected b/c/common/test/rules/lowercaselstartsinliteralsuffix/LowercaseLStartsInLiteralSuffix.expected new file mode 100644 index 0000000000..a381fdb7e8 --- /dev/null +++ b/c/common/test/rules/lowercaselstartsinliteralsuffix/LowercaseLStartsInLiteralSuffix.expected @@ -0,0 +1,16 @@ +| test.c:5:10:5:11 | 0 | Lowercase 'l' used as a literal suffix. | +| test.c:6:10:6:12 | 0 | Lowercase 'l' used as a literal suffix. | +| test.c:9:10:9:12 | 0 | Lowercase 'l' used as a literal suffix. | +| test.c:10:10:10:12 | 0 | Lowercase 'l' used as a literal suffix. | +| test.c:15:11:15:12 | 0 | Lowercase 'l' used as a literal suffix. | +| test.c:16:11:16:13 | 0 | Lowercase 'l' used as a literal suffix. | +| test.c:19:11:19:13 | 0 | Lowercase 'l' used as a literal suffix. | +| test.c:20:11:20:13 | 0 | Lowercase 'l' used as a literal suffix. | +| test.c:25:10:25:14 | 1 | Lowercase 'l' used as a literal suffix. | +| test.c:26:10:26:15 | 1 | Lowercase 'l' used as a literal suffix. | +| test.c:29:10:29:15 | 1 | Lowercase 'l' used as a literal suffix. | +| test.c:30:10:30:15 | 1 | Lowercase 'l' used as a literal suffix. | +| test.c:35:11:35:14 | 1 | Lowercase 'l' used as a literal suffix. | +| test.c:36:11:36:15 | 1 | Lowercase 'l' used as a literal suffix. | +| test.c:39:11:39:15 | 1 | Lowercase 'l' used as a literal suffix. | +| test.c:40:11:40:15 | 1 | Lowercase 'l' used as a literal suffix. | diff --git a/c/common/test/rules/lowercaselstartsinliteralsuffix/LowercaseLStartsInLiteralSuffix.ql b/c/common/test/rules/lowercaselstartsinliteralsuffix/LowercaseLStartsInLiteralSuffix.ql new file mode 100644 index 0000000000..ab353ca8a9 --- /dev/null +++ b/c/common/test/rules/lowercaselstartsinliteralsuffix/LowercaseLStartsInLiteralSuffix.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.lowercaselstartsinliteralsuffix.LowercaseLStartsInLiteralSuffix + +class TestFileQuery extends LowercaseLStartsInLiteralSuffixSharedQuery, TestQuery { } diff --git a/c/common/test/rules/lowercaselstartsinliteralsuffix/test.c b/c/common/test/rules/lowercaselstartsinliteralsuffix/test.c new file mode 100644 index 0000000000..549e90bd7d --- /dev/null +++ b/c/common/test/rules/lowercaselstartsinliteralsuffix/test.c @@ -0,0 +1,46 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +// int x = false; // COMPLIANT - reported as C++ FP in #319 +int a1 = 0L; // COMPLIANT +int a2 = 0l; // NON_COMPLIANT +int a3 = 0ll; // NON_COMPLIANT +int a4 = 0LL; // COMPLIANT +int a5 = 0uL; // COMPLIANT +int a6 = 0ul; // NON_COMPLIANT +int a7 = 0lu; // NON_COMPLIANT +int a8 = 0Lu; // COMPLIANT +int a9 = 0LU; // COMPLIANT + +long b1 = 0L; // COMPLIANT +long b2 = 0l; // NON_COMPLIANT +long b3 = 0ll; // NON_COMPLIANT +long b4 = 0LL; // COMPLIANT +long b5 = 0uL; // COMPLIANT +long b6 = 0ul; // NON_COMPLIANT +long b7 = 0lu; // NON_COMPLIANT +long b8 = 0Lu; // COMPLIANT +long b9 = 0LU; // COMPLIANT + +int c1 = 0x01L; // COMPLIANT +int c2 = 0x01l; // NON_COMPLIANT +int c3 = 0x01ll; // NON_COMPLIANT +int c4 = 0x01LL; // COMPLIANT +int c5 = 0x01uL; // COMPLIANT +int c6 = 0x01ul; // NON_COMPLIANT +int c7 = 0x01lu; // NON_COMPLIANT +int c8 = 0x01Lu; // COMPLIANT +int c9 = 0x01LU; // COMPLIANT + +long d1 = 001L; // COMPLIANT +long d2 = 001l; // NON_COMPLIANT +long d3 = 001ll; // NON_COMPLIANT +long d4 = 001LL; // COMPLIANT +long d5 = 001uL; // COMPLIANT +long d6 = 001ul; // NON_COMPLIANT +long d7 = 001lu; // NON_COMPLIANT +long d8 = 001Lu; // COMPLIANT +long d9 = 001LU; // COMPLIANT + +char *e1 = ""; +char *e2 = "ul"; +char *e3 = "UL"; \ No newline at end of file diff --git a/c/common/test/rules/macroparameterfollowinghash/MacroParameterFollowingHash.expected b/c/common/test/rules/macroparameterfollowinghash/MacroParameterFollowingHash.expected new file mode 100644 index 0000000000..715bbe781d --- /dev/null +++ b/c/common/test/rules/macroparameterfollowinghash/MacroParameterFollowingHash.expected @@ -0,0 +1 @@ +| test.c:27:1:27:29 | #define MACROTHIRTEEN(X) #X ## X | Macro definition uses an # operator followed by a ## operator. | diff --git a/c/common/test/rules/macroparameterfollowinghash/MacroParameterFollowingHash.ql b/c/common/test/rules/macroparameterfollowinghash/MacroParameterFollowingHash.ql new file mode 100644 index 0000000000..f753b75463 --- /dev/null +++ b/c/common/test/rules/macroparameterfollowinghash/MacroParameterFollowingHash.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.macroparameterfollowinghash.MacroParameterFollowingHash + +class TestFileQuery extends MacroParameterFollowingHashSharedQuery, TestQuery { } diff --git a/c/common/test/rules/macroparameterfollowinghash/test.c b/c/common/test/rules/macroparameterfollowinghash/test.c new file mode 100644 index 0000000000..d998ce8106 --- /dev/null +++ b/c/common/test/rules/macroparameterfollowinghash/test.c @@ -0,0 +1,29 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +#define MACROONE 1 // COMPLIANT + +#define MACROTWO '#\'-#' + '#' // COMPLIANT + +#define MACROTHREE "##" // COMPLIANT + +#define MACROFOUR "##" + "#" // COMPLIANT + +#define MACROFIVE(X) #X // COMPLIANT + +#define MACROSIX(X, Y) X##Y // COMPLIANT + +#define MACROSEVEN "##'" #"#" // COMPLIANT + +#define MACROEIGHT '##' #"#" // COMPLIANT + +#define MACRONINE "##\"\"" + "#" // COMPLIANT + +#define MACROTEN "##\"\"'" + "#" // COMPLIANT + +#define MACROELEVEN(X) X #X #X // COMPLIANT + +#define MACROTWELVE(X) X##X##X // COMPLIANT + +#define MACROTHIRTEEN(X) #X##X // NON_COMPLIANT + +#define MACROFOURTEEN '#\'-#' + 1 #1 #1 + '#' // COMPLIANT \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.expected b/c/common/test/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.expected similarity index 100% rename from c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.expected rename to c/common/test/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.expected diff --git a/c/common/test/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.ql b/c/common/test/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.ql new file mode 100644 index 0000000000..3d6d2019fb --- /dev/null +++ b/c/common/test/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.ql @@ -0,0 +1,5 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.missingstaticspecifierobjectredeclarationshared.MissingStaticSpecifierObjectRedeclarationShared + +class TestFileQuery extends MissingStaticSpecifierObjectRedeclarationSharedSharedQuery, TestQuery { +} diff --git a/c/misra/test/rules/RULE-8-8/test.c b/c/common/test/rules/missingstaticspecifierobjectredeclarationshared/test.c similarity index 100% rename from c/misra/test/rules/RULE-8-8/test.c rename to c/common/test/rules/missingstaticspecifierobjectredeclarationshared/test.c diff --git a/c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected b/c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected new file mode 100644 index 0000000000..f3b94b6095 --- /dev/null +++ b/c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected @@ -0,0 +1,113 @@ +problems +| test.c:12:8:12:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:12:8:12:9 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:13:8:13:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:13:8:13:9 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:18:8:18:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:18:3:18:9 | l2 | Possibly infinite float value $@ flows to cast to integer. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:19:8:19:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:19:3:19:9 | l3 | Possibly infinite float value $@ flows to cast to integer. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:27:19:27:20 | l2 | test.c:8:14:8:20 | ... / ... | test.c:27:19:27:20 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:28:19:28:20 | l3 | test.c:8:14:8:20 | ... / ... | test.c:28:19:28:20 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | Possibly infinite float value $@ flows to cast to integer. | test.c:31:14:32:15 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:61:11:61:17 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:66:11:66:19 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:72:20:72:28 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:75:24:75:32 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:79:10:79:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:79:5:79:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:87:10:87:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:87:5:87:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:91:10:91:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:91:5:91:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:93:10:93:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:93:5:93:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:99:10:99:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:99:5:99:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:105:10:105:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:105:5:105:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:111:10:111:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:111:5:111:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:114:21:114:23 | l12 | test.c:77:15:77:21 | ... / ... | test.c:114:16:114:23 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:117:28:117:30 | l12 | test.c:77:15:77:21 | ... / ... | test.c:117:23:117:30 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:120:25:120:27 | l12 | test.c:77:15:77:21 | ... / ... | test.c:120:20:120:27 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:163:9:164:15 | ... / ... | test.c:163:3:164:16 | ... / ... | test.c:163:3:164:16 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:163:9:164:15 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:175:32:175:32 | p | test.c:189:51:189:59 | ... / ... | test.c:175:27:175:32 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:189:51:189:59 | ... / ... | from division by zero | test.c:189:6:189:24 | addInfThenCastToInt | addInfThenCastToInt | +| test.c:175:32:175:32 | p | test.c:193:13:194:15 | ... / ... | test.c:175:27:175:32 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:193:13:194:15 | ... / ... | from division by zero | test.c:192:6:192:7 | f2 | f2 | +| test.c:175:32:175:32 | p | test.c:204:19:204:27 | ... / ... | test.c:175:27:175:32 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:204:19:204:27 | ... / ... | from division by zero | test.c:192:6:192:7 | f2 | f2 | +| test.c:185:18:185:18 | p | test.c:200:25:200:33 | ... / ... | test.c:185:13:185:18 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:200:25:200:33 | ... / ... | from division by zero | test.c:192:6:192:7 | f2 | f2 | +edges +| test.c:8:14:8:20 | ... / ... | test.c:8:14:8:20 | ... / ... | provenance | | +| test.c:8:14:8:20 | ... / ... | test.c:9:14:9:16 | - ... | provenance | Config | +| test.c:8:14:8:20 | ... / ... | test.c:12:8:12:9 | l2 | provenance | | +| test.c:8:14:8:20 | ... / ... | test.c:18:3:18:9 | l2 | provenance | | +| test.c:8:14:8:20 | ... / ... | test.c:27:19:27:20 | l2 | provenance | | +| test.c:9:14:9:16 | - ... | test.c:9:14:9:16 | - ... | provenance | | +| test.c:9:14:9:16 | - ... | test.c:13:8:13:9 | l3 | provenance | | +| test.c:9:14:9:16 | - ... | test.c:19:3:19:9 | l3 | provenance | | +| test.c:9:14:9:16 | - ... | test.c:28:19:28:20 | l3 | provenance | | +| test.c:31:14:32:15 | ... / ... | test.c:31:14:32:15 | ... / ... | provenance | | +| test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:77:15:77:21 | ... / ... | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:79:5:79:12 | l12 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:87:5:87:12 | l12 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:91:5:91:12 | l12 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:93:5:93:12 | l12 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:99:5:99:12 | l12 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:105:5:105:12 | l12 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:111:5:111:12 | l12 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:114:16:114:23 | l12 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:117:23:117:30 | l12 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:120:20:120:27 | l12 | provenance | | +| test.c:175:22:175:22 | p | test.c:175:27:175:32 | p | provenance | | +| test.c:183:34:183:34 | p | test.c:185:13:185:18 | p | provenance | | +| test.c:189:32:189:32 | p | test.c:189:47:189:59 | ... + ... | provenance | Config | +| test.c:189:47:189:59 | ... + ... | test.c:175:22:175:22 | p | provenance | | +| test.c:189:47:189:59 | ... + ... | test.c:175:22:175:22 | p | provenance | | +| test.c:189:51:189:59 | ... / ... | test.c:189:47:189:59 | ... + ... | provenance | Config | +| test.c:193:13:194:15 | ... / ... | test.c:175:22:175:22 | p | provenance | | +| test.c:200:25:200:33 | ... / ... | test.c:183:34:183:34 | p | provenance | | +| test.c:204:19:204:27 | ... / ... | test.c:204:19:204:27 | ... / ... | provenance | | +| test.c:204:19:204:27 | ... / ... | test.c:206:21:206:31 | ... + ... | provenance | Config | +| test.c:206:21:206:31 | ... + ... | test.c:206:21:206:31 | ... + ... | provenance | | +| test.c:206:21:206:31 | ... + ... | test.c:208:13:208:21 | middleInf | provenance | | +| test.c:206:21:206:31 | ... + ... | test.c:210:23:210:31 | middleInf | provenance | | +| test.c:208:13:208:21 | middleInf | test.c:175:22:175:22 | p | provenance | | +| test.c:210:23:210:31 | middleInf | test.c:189:32:189:32 | p | provenance | | +nodes +| test.c:8:14:8:20 | ... / ... | semmle.label | ... / ... | +| test.c:8:14:8:20 | ... / ... | semmle.label | ... / ... | +| test.c:9:14:9:16 | - ... | semmle.label | - ... | +| test.c:9:14:9:16 | - ... | semmle.label | - ... | +| test.c:12:8:12:9 | l2 | semmle.label | l2 | +| test.c:13:8:13:9 | l3 | semmle.label | l3 | +| test.c:18:3:18:9 | l2 | semmle.label | l2 | +| test.c:19:3:19:9 | l3 | semmle.label | l3 | +| test.c:27:19:27:20 | l2 | semmle.label | l2 | +| test.c:28:19:28:20 | l3 | semmle.label | l3 | +| test.c:31:14:32:15 | ... / ... | semmle.label | ... / ... | +| test.c:31:14:32:15 | ... / ... | semmle.label | ... / ... | +| test.c:38:3:38:9 | l7 | semmle.label | l7 | +| test.c:61:5:61:18 | ... / ... | semmle.label | ... / ... | +| test.c:66:5:66:20 | ... / ... | semmle.label | ... / ... | +| test.c:72:14:72:29 | ... / ... | semmle.label | ... / ... | +| test.c:75:18:75:33 | ... / ... | semmle.label | ... / ... | +| test.c:77:15:77:21 | ... / ... | semmle.label | ... / ... | +| test.c:77:15:77:21 | ... / ... | semmle.label | ... / ... | +| test.c:79:5:79:12 | l12 | semmle.label | l12 | +| test.c:87:5:87:12 | l12 | semmle.label | l12 | +| test.c:91:5:91:12 | l12 | semmle.label | l12 | +| test.c:93:5:93:12 | l12 | semmle.label | l12 | +| test.c:99:5:99:12 | l12 | semmle.label | l12 | +| test.c:105:5:105:12 | l12 | semmle.label | l12 | +| test.c:111:5:111:12 | l12 | semmle.label | l12 | +| test.c:114:16:114:23 | l12 | semmle.label | l12 | +| test.c:117:23:117:30 | l12 | semmle.label | l12 | +| test.c:120:20:120:27 | l12 | semmle.label | l12 | +| test.c:163:3:164:16 | ... / ... | semmle.label | ... / ... | +| test.c:175:22:175:22 | p | semmle.label | p | +| test.c:175:27:175:32 | p | semmle.label | p | +| test.c:183:34:183:34 | p | semmle.label | p | +| test.c:185:13:185:18 | p | semmle.label | p | +| test.c:189:32:189:32 | p | semmle.label | p | +| test.c:189:47:189:59 | ... + ... | semmle.label | ... + ... | +| test.c:189:47:189:59 | ... + ... | semmle.label | ... + ... | +| test.c:189:51:189:59 | ... / ... | semmle.label | ... / ... | +| test.c:193:13:194:15 | ... / ... | semmle.label | ... / ... | +| test.c:200:25:200:33 | ... / ... | semmle.label | ... / ... | +| test.c:204:19:204:27 | ... / ... | semmle.label | ... / ... | +| test.c:204:19:204:27 | ... / ... | semmle.label | ... / ... | +| test.c:206:21:206:31 | ... + ... | semmle.label | ... + ... | +| test.c:206:21:206:31 | ... + ... | semmle.label | ... + ... | +| test.c:208:13:208:21 | middleInf | semmle.label | middleInf | +| test.c:210:23:210:31 | middleInf | semmle.label | middleInf | +subpaths \ No newline at end of file diff --git a/c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql b/c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql new file mode 100644 index 0000000000..f0d160a650 --- /dev/null +++ b/c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.misuseofinfinitefloatingpointvalue.MisuseOfInfiniteFloatingPointValue + +class TestFileQuery extends MisuseOfInfiniteFloatingPointValueSharedQuery, TestQuery { } diff --git a/c/common/test/rules/misuseofinfinitefloatingpointvalue/test.c b/c/common/test/rules/misuseofinfinitefloatingpointvalue/test.c new file mode 100644 index 0000000000..6a4ebd94b9 --- /dev/null +++ b/c/common/test/rules/misuseofinfinitefloatingpointvalue/test.c @@ -0,0 +1,212 @@ +#include "math.h" + +float getFloat() { return 1.0; } + +// Parameter could be infinity +void f1(float p1) { + float l1 = 1; + float l2 = 1.0 / 0; + float l3 = -l2; + + 10 / l1; // COMPLIANT + 10 / l2; // NON_COMPLIANT: Underflows to zero + 10 / l3; // NON_COMPLIANT: Underflow to negative zero + 10 / p1; // COMPLIANT: Reduce false positives by assuming not infinity + 10 / getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + (int)l1; // COMPLIANT + (int)l2; // NON_COMPLIANT + (int)l3; // NON_COMPLIANT + (int)p1; // COMPLIANT: Reduce false positives by assuming not infinity + (int)getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + // Not NaN: + float l4 = l1 / l1; // COMPLIANT + + // NaN because of infinity divided by itself: + float l5 = l2 / l2; // NON_COMPLIANT: Division by infinity not allowed. + float l6 = l3 / l3; // NON_COMPLIANT: Division by infinity not allowed. + + // NaN because of zero divided by itself: + float l7 = getFloat() / + p1; // COMPLIANT: Reduce false positives by assuming not infinity + float l8 = 0.0 / 0.0; + + (int)l4; // COMPLIANT + (int)l5; // COMPLIANT: Casting NaN to int + (int)l6; // COMPLIANT: Casting NaN to int + (int)l7; // NON_COMPLIANT: Casting Infinity to int + (int)l8; // COMPLIANT: Casting NaN to int + + l4 == 0; // COMPLIANT + l4 != 0; // COMPLIANT + l4 <= 0; // COMPLIANT + l4 < 0; // COMPLIANT + l4 >= 0; // COMPLIANT + l5 == 0; // NON_COMPLIANT: Comparison with NaN always false + l5 != 0; // NON_COMPLIANT: Comparison with NaN always false + l5 < 0; // NON_COMPLIANT: Comparison with NaN always false + l5 <= 0; // NON_COMPLIANT: Comparison with NaN always false + l5 > 0; // NON_COMPLIANT: Comparison with NaN always false + l5 >= 0; // NON_COMPLIANT: Comparison with NaN always false + l6 == 0; // NON_COMPLIANT: Comparison with NaN always false + l7 == 0; // NON_COMPLIANT: Comparison with NaN always false + l8 == 0; // NON_COMPLIANT: Comparison with NaN always false + + // Guards + float l9 = 0; + if (l9 != 0) { + (int)(l9 / l9); // COMPLIANT: l9 is not zero + } else { + (int)(l9 / l9); // NON_COMPLIANT[False positive]: Guarded to not be NaN + } + + float l10 = 0; + if (l10 == 0) { + (int)(l10 / l10); // NON_COMPLIANT[False positive]: Casting NaN to integer + } else { + (int)(l10 / l10); // COMPLIANT: Guarded to not be NaN + } + + float l11 = 0; + l11 == 0 ? (int)(l11 / l11) : 0; // NON_COMPLIANT[False positive] + l11 == 0 ? 0 : (int)(l11 / l11); // COMPLIANT + l11 != 0 ? (int)(l11 / l11) : 0; // COMPLIANT + l11 != 0 ? 0 : (int)(l11 / l11); // NON_COMPLIANT[False positive] + + float l12 = 1.0 / 0; + if (isinf(l12)) { + (int)l12; // NON_COMPLIANT: Casting Infinity to integer + } else { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } + + if (!isinf(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // NON_COMPLIANT: Casting Infinity to integer + } + + if (isinf(l12) == 1) { + (int)l12; // NON_COMPLIANT: Must be +Infinity + } else { + (int)l12; // NON_COMPLIANT: May be -Infinity + } + + if (isfinite(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // NON_COMPLIANT: Casting Infinity to integer + } + + if (isnormal(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // NON_COMPLIANT: Casting Infinity to integer + } + + if (isnan(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // NON_COMPLIANT: Casting Infinity to integer + } + + isinf(l12) ? (int)l12 : 0; // NON_COMPLIANT: Check on wrong branch + isinf(l12) ? 0 : (int)l12; // COMPLIANT: Checked not infinite before use + isfinite(l12) ? (int)l12 : 0; // COMPLIANT: Checked finite before use + isfinite(l12) ? 0 : (int)l12; // NON_COMPLIANT: Checked on wrong branch + isnan(l12) ? (int)l12 + : 0; // COMPLIANT: Checked NaN, therefore not infinite, before use + isnan(l12) ? 0 : (int)l12; // NON_COMPLIANT: Check on wrong branch + + float l13 = 0.0 / 0; + if (isinf(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // COMPLIANT: Casting NaN to integer + } + + if (isinf(l13) == 1) { + (int)l13; // COMPLIANT: Guarded not to be NaN (must be +Infinity) + } else { + (int)l13; // COMPLIANT: Casting NaN to integer + } + + if (isfinite(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // COMPLIANT: Casting NaN to integer + } + + if (isnormal(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // COMPLIANT: Casting NaN to integer + } + + if (isnan(l13)) { + (int)l13; // COMPLIANT: Casting NaN to integer + } else { + (int)l13; // COMPLIANT: Guarded not to be NaN + } + + isinf(l13) ? (int)l13 + : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use + isinf(l13) ? 0 : (int)l13; // COMPLIANT: Check on wrong branch + isfinite(l13) ? (int)l13 : 0; // COMPLIANT: Checked finite before use + isfinite(l13) ? 0 : (int)l13; // COMPLIANT: Checked on wrong branch + isnan(l13) ? (int)l13 : 0; // COMPLIANT: Check on wrong branch + isnan(l13) ? 0 : (int)l13; // COMPLIANT: Checked not NaN before use + + (int)pow(2, p1); // NON_COMPLIANT[False negative]: likely to be Infinity + (int)pow(2, sin(p1)); // COMPLIANT: not likely to be Infinity + (int)(1 / + sin(p1)); // NON_COMPLIANT: possible infinity from zero in denominator + (int)(1 / log(p1)); // COMPLIANT: not possibly zero in denominator + (int)pow(p1, p1); // COMPLIANT: NaN if p1 is zero + if (p1 != 0) { + (int)pow(p1, p1); // COMPLIANT: p1 is not zero + } + + (int)acos(p1); // COMPLIANT: NaN if p1 is not within -1..1 + (int)acos(cos(p1)); // COMPLIANT: cos(p1) is within -1..1 +} + +void castToInt(float p) { (int)p; } + +void checkBeforeCastToInt(float p) { + if (isfinite(p)) { + castToInt(p); + } +} + +void castToIntToFloatToInt(float p) { + // This should be reported as a violation, but not downstream from here. + castToInt((int)p); +} + +void addOneThenCastToInt(float p) { castToInt(p + 1); } +void addInfThenCastToInt(float p) { castToInt(p + 1.0 / 0.0); } +void addNaNThenCastToInt(float p) { castToInt(p + 0.0 / 0.0); } + +void f2() { + castToInt(1.0 / + 0.0); // NON_COMPLIANT: Infinity flows to denominator in division + castToInt(0.0 / 0.0); // COMPLIANT + checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT + checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT + addOneThenCastToInt(1.0 / 0.0); // NON_COMPLIANT[False negative] + addOneThenCastToInt(0.0 / 0.0); // NON_COMPLIANT + castToIntToFloatToInt(1.0 / 0.0); // NON_COMPLIANT + castToIntToFloatToInt(0.0 / 0.0); // COMPLIANT + + // Check that during flow analysis, we only report the true root cause: + float rootInf = 1.0 / 0.0; + float rootNaN = 0.0 / 0.0; + float middleInf = rootInf + 1; + float middleNaN = rootNaN + 1; + castToInt(middleInf); // NON_COMPLIANT + castToInt(middleNaN); // COMPLIANT + addInfThenCastToInt(middleInf); // NON_COMPLIANT + addNaNThenCastToInt(middleNaN); // COMPLIANT +} \ No newline at end of file diff --git a/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected b/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected new file mode 100644 index 0000000000..b567e06bc2 --- /dev/null +++ b/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected @@ -0,0 +1,136 @@ +problems +| test.c:36:8:36:9 | l5 | test.c:27:14:27:20 | ... / ... | test.c:36:3:36:9 | l5 | Possible NaN value $@ flows to a cast to integer. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:37:8:37:9 | l6 | test.c:28:14:28:20 | ... / ... | test.c:37:3:37:9 | l6 | Possible NaN value $@ flows to a cast to integer. | test.c:28:14:28:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | Possible NaN value $@ flows to a cast to integer. | test.c:31:14:32:15 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:39:8:39:9 | l8 | test.c:33:14:33:22 | ... / ... | test.c:39:3:39:9 | l8 | Possible NaN value $@ flows to a cast to integer. | test.c:33:14:33:22 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:46:3:46:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:46:3:46:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:47:3:47:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:47:3:47:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:48:3:48:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:48:3:48:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:49:3:49:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:49:3:49:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:50:3:50:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:50:3:50:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:51:3:51:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:51:3:51:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:52:3:52:4 | l6 | test.c:28:14:28:20 | ... / ... | test.c:52:3:52:4 | l6 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:28:14:28:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:53:3:53:4 | l7 | test.c:31:14:32:15 | ... / ... | test.c:53:3:53:4 | l7 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:31:14:32:15 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:54:3:54:4 | l8 | test.c:33:14:33:22 | ... / ... | test.c:54:3:54:4 | l8 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:33:14:33:22 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:61:11:61:17 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:66:11:66:19 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:72:20:72:28 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:75:24:75:32 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:126:10:126:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:126:5:126:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:132:10:132:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:132:5:132:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:138:10:138:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:138:5:138:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:144:10:144:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:144:5:144:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:148:10:148:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:148:5:148:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:155:25:155:27 | l13 | test.c:122:15:122:21 | ... / ... | test.c:155:20:155:27 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:157:28:157:30 | l13 | test.c:122:15:122:21 | ... / ... | test.c:157:23:157:30 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:158:21:158:23 | l13 | test.c:122:15:122:21 | ... / ... | test.c:158:16:158:23 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:165:8:165:10 | call to pow | test.c:165:3:165:18 | call to pow | test.c:165:3:165:18 | call to pow | Possible NaN value $@ flows to a cast to integer. | test.c:165:8:165:10 | call to pow | both arguments are equal to zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:170:8:170:11 | call to acos | test.c:170:3:170:15 | call to acos | test.c:170:3:170:15 | call to acos | Possible NaN value $@ flows to a cast to integer. | test.c:170:8:170:11 | call to acos | the argument has a range -1000000000000000...1000000000000000 which is outside the domain of this function (-1.0...1.0) | test.c:6:6:6:7 | f1 | f1 | +| test.c:174:32:174:32 | p | test.c:189:51:189:59 | ... / ... | test.c:174:27:174:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:189:51:189:59 | ... / ... | from division of zero by zero | test.c:189:6:189:24 | addNaNThenCastToInt | addNaNThenCastToInt | +| test.c:174:32:174:32 | p | test.c:193:13:193:21 | ... / ... | test.c:174:27:174:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:193:13:193:21 | ... / ... | from division of zero by zero | test.c:191:6:191:7 | f2 | f2 | +| test.c:174:32:174:32 | p | test.c:197:23:197:31 | ... / ... | test.c:174:27:174:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:197:23:197:31 | ... / ... | from division of zero by zero | test.c:191:6:191:7 | f2 | f2 | +| test.c:174:32:174:32 | p | test.c:203:19:203:27 | ... / ... | test.c:174:27:174:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:203:19:203:27 | ... / ... | from division of zero by zero | test.c:191:6:191:7 | f2 | f2 | +| test.c:184:18:184:18 | p | test.c:199:25:199:33 | ... / ... | test.c:184:13:184:18 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:199:25:199:33 | ... / ... | from division of zero by zero | test.c:191:6:191:7 | f2 | f2 | +edges +| test.c:27:14:27:20 | ... / ... | test.c:27:14:27:20 | ... / ... | provenance | | +| test.c:27:14:27:20 | ... / ... | test.c:36:3:36:9 | l5 | provenance | | +| test.c:27:14:27:20 | ... / ... | test.c:46:3:46:4 | l5 | provenance | | +| test.c:27:14:27:20 | ... / ... | test.c:47:3:47:4 | l5 | provenance | | +| test.c:27:14:27:20 | ... / ... | test.c:48:3:48:4 | l5 | provenance | | +| test.c:27:14:27:20 | ... / ... | test.c:49:3:49:4 | l5 | provenance | | +| test.c:27:14:27:20 | ... / ... | test.c:50:3:50:4 | l5 | provenance | | +| test.c:27:14:27:20 | ... / ... | test.c:51:3:51:4 | l5 | provenance | | +| test.c:28:14:28:20 | ... / ... | test.c:28:14:28:20 | ... / ... | provenance | | +| test.c:28:14:28:20 | ... / ... | test.c:37:3:37:9 | l6 | provenance | | +| test.c:28:14:28:20 | ... / ... | test.c:52:3:52:4 | l6 | provenance | | +| test.c:31:14:32:15 | ... / ... | test.c:31:14:32:15 | ... / ... | provenance | | +| test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | provenance | | +| test.c:31:14:32:15 | ... / ... | test.c:53:3:53:4 | l7 | provenance | | +| test.c:33:14:33:22 | ... / ... | test.c:33:14:33:22 | ... / ... | provenance | | +| test.c:33:14:33:22 | ... / ... | test.c:39:3:39:9 | l8 | provenance | | +| test.c:33:14:33:22 | ... / ... | test.c:54:3:54:4 | l8 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:122:15:122:21 | ... / ... | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:126:5:126:12 | l13 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:132:5:132:12 | l13 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:138:5:138:12 | l13 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:144:5:144:12 | l13 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:148:5:148:12 | l13 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:155:20:155:27 | l13 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:157:23:157:30 | l13 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:158:16:158:23 | l13 | provenance | | +| test.c:174:22:174:22 | p | test.c:174:27:174:32 | p | provenance | | +| test.c:182:34:182:34 | p | test.c:184:13:184:18 | p | provenance | | +| test.c:187:32:187:32 | p | test.c:187:47:187:51 | ... + ... | provenance | Config | +| test.c:187:47:187:51 | ... + ... | test.c:174:22:174:22 | p | provenance | | +| test.c:189:32:189:32 | p | test.c:189:47:189:59 | ... + ... | provenance | Config | +| test.c:189:47:189:59 | ... + ... | test.c:174:22:174:22 | p | provenance | | +| test.c:189:47:189:59 | ... + ... | test.c:174:22:174:22 | p | provenance | | +| test.c:189:51:189:59 | ... / ... | test.c:189:47:189:59 | ... + ... | provenance | Config | +| test.c:193:13:193:21 | ... / ... | test.c:174:22:174:22 | p | provenance | | +| test.c:197:23:197:31 | ... / ... | test.c:187:32:187:32 | p | provenance | | +| test.c:199:25:199:33 | ... / ... | test.c:182:34:182:34 | p | provenance | | +| test.c:203:19:203:27 | ... / ... | test.c:203:19:203:27 | ... / ... | provenance | | +| test.c:203:19:203:27 | ... / ... | test.c:205:21:205:31 | ... + ... | provenance | Config | +| test.c:205:21:205:31 | ... + ... | test.c:205:21:205:31 | ... + ... | provenance | | +| test.c:205:21:205:31 | ... + ... | test.c:207:13:207:21 | middleNaN | provenance | | +| test.c:205:21:205:31 | ... + ... | test.c:209:23:209:31 | middleNaN | provenance | | +| test.c:207:13:207:21 | middleNaN | test.c:174:22:174:22 | p | provenance | | +| test.c:209:23:209:31 | middleNaN | test.c:189:32:189:32 | p | provenance | | +nodes +| test.c:27:14:27:20 | ... / ... | semmle.label | ... / ... | +| test.c:27:14:27:20 | ... / ... | semmle.label | ... / ... | +| test.c:28:14:28:20 | ... / ... | semmle.label | ... / ... | +| test.c:28:14:28:20 | ... / ... | semmle.label | ... / ... | +| test.c:31:14:32:15 | ... / ... | semmle.label | ... / ... | +| test.c:31:14:32:15 | ... / ... | semmle.label | ... / ... | +| test.c:33:14:33:22 | ... / ... | semmle.label | ... / ... | +| test.c:33:14:33:22 | ... / ... | semmle.label | ... / ... | +| test.c:36:3:36:9 | l5 | semmle.label | l5 | +| test.c:37:3:37:9 | l6 | semmle.label | l6 | +| test.c:38:3:38:9 | l7 | semmle.label | l7 | +| test.c:39:3:39:9 | l8 | semmle.label | l8 | +| test.c:46:3:46:4 | l5 | semmle.label | l5 | +| test.c:47:3:47:4 | l5 | semmle.label | l5 | +| test.c:48:3:48:4 | l5 | semmle.label | l5 | +| test.c:49:3:49:4 | l5 | semmle.label | l5 | +| test.c:50:3:50:4 | l5 | semmle.label | l5 | +| test.c:51:3:51:4 | l5 | semmle.label | l5 | +| test.c:52:3:52:4 | l6 | semmle.label | l6 | +| test.c:53:3:53:4 | l7 | semmle.label | l7 | +| test.c:54:3:54:4 | l8 | semmle.label | l8 | +| test.c:61:5:61:18 | ... / ... | semmle.label | ... / ... | +| test.c:66:5:66:20 | ... / ... | semmle.label | ... / ... | +| test.c:72:14:72:29 | ... / ... | semmle.label | ... / ... | +| test.c:75:18:75:33 | ... / ... | semmle.label | ... / ... | +| test.c:122:15:122:21 | ... / ... | semmle.label | ... / ... | +| test.c:122:15:122:21 | ... / ... | semmle.label | ... / ... | +| test.c:126:5:126:12 | l13 | semmle.label | l13 | +| test.c:132:5:132:12 | l13 | semmle.label | l13 | +| test.c:138:5:138:12 | l13 | semmle.label | l13 | +| test.c:144:5:144:12 | l13 | semmle.label | l13 | +| test.c:148:5:148:12 | l13 | semmle.label | l13 | +| test.c:155:20:155:27 | l13 | semmle.label | l13 | +| test.c:157:23:157:30 | l13 | semmle.label | l13 | +| test.c:158:16:158:23 | l13 | semmle.label | l13 | +| test.c:165:3:165:18 | call to pow | semmle.label | call to pow | +| test.c:170:3:170:15 | call to acos | semmle.label | call to acos | +| test.c:174:22:174:22 | p | semmle.label | p | +| test.c:174:27:174:32 | p | semmle.label | p | +| test.c:182:34:182:34 | p | semmle.label | p | +| test.c:184:13:184:18 | p | semmle.label | p | +| test.c:187:32:187:32 | p | semmle.label | p | +| test.c:187:47:187:51 | ... + ... | semmle.label | ... + ... | +| test.c:189:32:189:32 | p | semmle.label | p | +| test.c:189:47:189:59 | ... + ... | semmle.label | ... + ... | +| test.c:189:47:189:59 | ... + ... | semmle.label | ... + ... | +| test.c:189:51:189:59 | ... / ... | semmle.label | ... / ... | +| test.c:193:13:193:21 | ... / ... | semmle.label | ... / ... | +| test.c:197:23:197:31 | ... / ... | semmle.label | ... / ... | +| test.c:199:25:199:33 | ... / ... | semmle.label | ... / ... | +| test.c:203:19:203:27 | ... / ... | semmle.label | ... / ... | +| test.c:203:19:203:27 | ... / ... | semmle.label | ... / ... | +| test.c:205:21:205:31 | ... + ... | semmle.label | ... + ... | +| test.c:205:21:205:31 | ... + ... | semmle.label | ... + ... | +| test.c:207:13:207:21 | middleNaN | semmle.label | middleNaN | +| test.c:209:23:209:31 | middleNaN | semmle.label | middleNaN | +subpaths diff --git a/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql b/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql new file mode 100644 index 0000000000..a1f729ed02 --- /dev/null +++ b/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.misuseofnanfloatingpointvalue.MisuseOfNaNFloatingPointValue + +class TestFileQuery extends MisuseOfNaNFloatingPointValueSharedQuery, TestQuery { } diff --git a/c/common/test/rules/misuseofnanfloatingpointvalue/test.c b/c/common/test/rules/misuseofnanfloatingpointvalue/test.c new file mode 100644 index 0000000000..bd997282f0 --- /dev/null +++ b/c/common/test/rules/misuseofnanfloatingpointvalue/test.c @@ -0,0 +1,210 @@ +#include "math.h" + +float getFloat() { return 1.0; } + +// Parameter could be infinity +void f1(float p1) { + float l1 = 1; + float l2 = 1.0 / 0; + float l3 = -l2; + + 10 / l1; // COMPLIANT + 10 / l2; // COMPLIANT: Underflows to zero + 10 / l3; // COMPLIANT: Underflow to negative zero + 10 / p1; // COMPLIANT: Reduce false positives by assuming not infinity + 10 / getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + (int)l1; // COMPLIANT + (int)l2; // COMPLIANT + (int)l3; // COMPLIANT + (int)p1; // COMPLIANT: Reduce false positives by assuming not infinity + (int)getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + // Not NaN: + float l4 = l1 / l1; // COMPLIANT + + // NaN because of infinity divided by itself: + float l5 = l2 / l2; // COMPLIANT: Division by infinity not allowed. + float l6 = l3 / l3; // COMPLIANT: Division by infinity not allowed. + + // NaN because of zero divided by itself: + float l7 = getFloat() / + p1; // COMPLIANT: Reduce false positives by assuming not infinity + float l8 = 0.0 / 0.0; + + (int)l4; // COMPLIANT + (int)l5; // NON_COMPLIANT: Casting NaN to int + (int)l6; // NON_COMPLIANT: Casting NaN to int + (int)l7; // NON_COMPLIANT: Casting NaN to int + (int)l8; // NON_COMPLIANT: Casting NaN to int + + l4 == 0; // COMPLIANT + l4 != 0; // COMPLIANT + l4 <= 0; // COMPLIANT + l4 < 0; // COMPLIANT + l4 >= 0; // COMPLIANT + l5 == 0; // NON_COMPLIANT: Comparison with NaN always false + l5 != 0; // NON_COMPLIANT: Comparison with NaN always false + l5 < 0; // NON_COMPLIANT: Comparison with NaN always false + l5 <= 0; // NON_COMPLIANT: Comparison with NaN always false + l5 > 0; // NON_COMPLIANT: Comparison with NaN always false + l5 >= 0; // NON_COMPLIANT: Comparison with NaN always false + l6 == 0; // NON_COMPLIANT: Comparison with NaN always false + l7 == 0; // NON_COMPLIANT: Comparison with NaN always false + l8 == 0; // NON_COMPLIANT: Comparison with NaN always false + + // Guards + float l9 = 0; + if (l9 != 0) { + (int)(l9 / l9); // COMPLIANT: l9 is not zero + } else { + (int)(l9 / l9); // NON_COMPLIANT: Casting NaN to integer + } + + float l10 = 0; + if (l10 == 0) { + (int)(l10 / l10); // NON_COMPLIANT: Casting NaN to integer + } else { + (int)(l10 / l10); // COMPLIANT: Guarded to not be NaN + } + + float l11 = 0; + l11 == 0 ? (int)(l11 / l11) : 0; // NON_COMPLIANT + l11 == 0 ? 0 : (int)(l11 / l11); // COMPLIANT + l11 != 0 ? (int)(l11 / l11) : 0; // COMPLIANT + l11 != 0 ? 0 : (int)(l11 / l11); // NON_COMPLIANT + + float l12 = 1.0 / 0; + if (isinf(l12)) { + (int)l12; // COMPLIANT: Casting Infinity to integer + } else { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } + + if (!isinf(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + if (isinf(l12) == 1) { + (int)l12; // COMPLIANT: Must be +Infinity + } else { + (int)l12; // COMPLIANT: May be -Infinity + } + + if (isfinite(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + if (isnormal(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + if (isnan(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + isinf(l12) ? (int)l12 : 0; // COMPLIANT: Check on wrong branch + isinf(l12) ? 0 : (int)l12; // COMPLIANT: Checked not infinite before use + isfinite(l12) ? (int)l12 : 0; // COMPLIANT: Checked finite before use + isfinite(l12) ? 0 : (int)l12; // COMPLIANT: Checked on wrong branch + isnan(l12) ? (int)l12 + : 0; // COMPLIANT: Checked NaN, therefore not infinite, before use + isnan(l12) ? 0 : (int)l12; // COMPLIANT: Check on wrong branch + + float l13 = 0.0 / 0; + if (isinf(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (isinf(l13) == 1) { + (int)l13; // COMPLIANT: Guarded not to be NaN (must be +Infinity) + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (isfinite(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (isnormal(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (isnan(l13)) { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } else { + (int)l13; // COMPLIANT: Guarded not to be NaN + } + + isinf(l13) ? (int)l13 + : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use + isinf(l13) ? 0 : (int)l13; // NON_COMPLIANT: Check on wrong branch + isfinite(l13) ? (int)l13 : 0; // COMPLIANT: Checked finite before use + isfinite(l13) ? 0 : (int)l13; // NON_COMPLIANT: Checked on wrong branch + isnan(l13) ? (int)l13 : 0; // NON_COMPLIANT: Check on wrong branch + isnan(l13) ? 0 : (int)l13; // COMPLIANT: Checked not NaN before use + + (int)pow(2, p1); // COMPLIANT: likely to be Infinity + (int)pow(2, sin(p1)); // COMPLIANT: not likely to be Infinity + (int)(1 / sin(p1)); // COMPLIANT: possible infinity from zero in denominator + (int)(1 / log(p1)); // COMPLIANT: not possibly zero in denominator + (int)pow(p1, p1); // NON_COMPLIANT: NaN if p1 is zero + if (p1 != 0) { + (int)pow(p1, p1); // COMPLIANT: p1 is not zero + } + + (int)acos(p1); // NON_COMPLIANT: NaN if p1 is not within -1..1 + (int)acos(cos(p1)); // COMPLIANT: cos(p1) is within -1..1 +} + +void castToInt(float p) { (int)p; } + +void checkBeforeCastToInt(float p) { + if (isfinite(p)) { + castToInt(p); + } +} + +void castToIntToFloatToInt(float p) { + // This should be reported as a violation, but not downstream from here. + castToInt((int)p); +} + +void addOneThenCastToInt(float p) { castToInt(p + 1); } +void addInfThenCastToInt(float p) { castToInt(p + 1.0 / 0.0); } +void addNaNThenCastToInt(float p) { castToInt(p + 0.0 / 0.0); } + +void f2() { + castToInt(1.0 / 0.0); // COMPLIANT: Infinity flows to denominator in division + castToInt(0.0 / 0.0); // COMPLIANT: NaN flows to denominator in division + checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT + checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT + addOneThenCastToInt(1.0 / 0.0); // COMPLIANT + addOneThenCastToInt(0.0 / 0.0); // NON_COMPLIANT + castToIntToFloatToInt(1.0 / 0.0); // COMPLIANT + castToIntToFloatToInt(0.0 / 0.0); // NON_COMPLIANT + + // Check that during flow analysis, we only report the true root cause: + float rootInf = 1.0 / 0.0; + float rootNaN = 0.0 / 0.0; + float middleInf = rootInf + 1; + float middleNaN = rootNaN + 1; + castToInt(middleInf); // COMPLIANT + castToInt(middleNaN); // NON_COMPLIANT + addInfThenCastToInt(middleInf); // NON_COMPLIANT + addNaNThenCastToInt(middleNaN); // NON_COMPLIANT +} \ No newline at end of file diff --git a/c/common/test/rules/namedbitfieldswithsignedintegertype/NamedBitFieldsWithSignedIntegerType.expected b/c/common/test/rules/namedbitfieldswithsignedintegertype/NamedBitFieldsWithSignedIntegerType.expected new file mode 100644 index 0000000000..7a6b7c33a5 --- /dev/null +++ b/c/common/test/rules/namedbitfieldswithsignedintegertype/NamedBitFieldsWithSignedIntegerType.expected @@ -0,0 +1,5 @@ +| test.c:6:7:6:8 | x1 | A named bit-field with signed integral type should have at least 2 bits of storage. | +| test.c:9:14:9:15 | x2 | A named bit-field with signed integral type should have at least 2 bits of storage. | +| test.c:11:7:11:8 | x3 | A named bit-field with signed integral type should have at least 2 bits of storage. | +| test.c:13:7:13:8 | x4 | A named bit-field with signed integral type should have at least 2 bits of storage. | +| test.c:22:14:22:14 | x | A named bit-field with signed integral type should have at least 2 bits of storage. | diff --git a/c/common/test/rules/namedbitfieldswithsignedintegertype/NamedBitFieldsWithSignedIntegerType.ql b/c/common/test/rules/namedbitfieldswithsignedintegertype/NamedBitFieldsWithSignedIntegerType.ql new file mode 100644 index 0000000000..a82fa7905a --- /dev/null +++ b/c/common/test/rules/namedbitfieldswithsignedintegertype/NamedBitFieldsWithSignedIntegerType.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.namedbitfieldswithsignedintegertype.NamedBitFieldsWithSignedIntegerType + +class TestFileQuery extends NamedBitFieldsWithSignedIntegerTypeSharedQuery, TestQuery { } diff --git a/c/common/test/rules/namedbitfieldswithsignedintegertype/test.c b/c/common/test/rules/namedbitfieldswithsignedintegertype/test.c new file mode 100644 index 0000000000..8fae6812fe --- /dev/null +++ b/c/common/test/rules/namedbitfieldswithsignedintegertype/test.c @@ -0,0 +1,28 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +#include + +struct SampleStruct { + int x1 : 1; // NON_COMPLIANT: very likely be signed, but if it's not, the + // query will automatically handle it since we use signed(), not + // isExplicitlySigned(). + signed int x2 : 1; // NON_COMPLIANT: single-bit named field with a signed type + signed char + x3 : 1; // NON_COMPLIANT: single-bit named field with a signed type + signed short + x4 : 1; // NON_COMPLIANT: single-bit named field with a signed type + unsigned int + x5 : 1; // COMPLIANT: single-bit named field but with an unsigned type + signed int x6 : 2; // COMPLIANT: named field with a signed type but declared + // to carry more than 1 bit + signed char : 1; // COMPLIANT: single-bit bit-field but unnamed +} sample_struct; + +struct S { + signed int x : 1; // NON-COMPLIANT + signed int y : 5; // COMPLIANT + signed int z : 7; // COMPLIANT + signed int : 0; // COMPLIANT + signed int : 1; // COMPLIANT + signed int : 2; // COMPLIANT +}; \ No newline at end of file diff --git a/c/common/test/rules/nonterminatedescapesequences/NonTerminatedEscapeSequences.expected b/c/common/test/rules/nonterminatedescapesequences/NonTerminatedEscapeSequences.expected new file mode 100644 index 0000000000..26401472ac --- /dev/null +++ b/c/common/test/rules/nonterminatedescapesequences/NonTerminatedEscapeSequences.expected @@ -0,0 +1,21 @@ +| test.c:37:18:37:24 | \u001aG | Invalid hexadecimal escape in string literal at '\\x1AG"'. | +| test.c:40:18:40:23 | \u00029 | Invalid octal escape in string literal at '\\029"'. | +| test.c:43:18:43:24 | \n7 | Invalid octal escape in string literal at '\\0127"'. | +| test.c:44:18:44:24 | \r7 | Invalid octal escape in string literal at '\\0157"'. | +| test.c:46:19:46:29 | \n\n9 | Invalid octal escape in string literal at '\\0129"'. | +| test.c:47:19:47:28 | \n\u00019 | Invalid octal escape in string literal at '\\019"'. | +| test.c:50:19:50:31 | \nAAA\u000f | Invalid octal escape in string literal at '\\012AAA\\017"'. | +| test.c:53:19:53:39 | Some Data \n\u000fA | Invalid octal escape in string literal at '\\017A"'. | +| test.c:54:19:55:21 | Some Data \n\u000fA5 | Invalid octal escape in string literal at '\\017A"\n "5"'. | +| test.c:56:19:58:25 | Some Data \n\u000fA\n1 | Invalid octal escape in string literal at '\\0121"'. | +| test.c:62:19:63:26 | \u0011G\u00012 | Invalid octal escape in string literal at '\\0012"'. | +| test.c:64:19:65:25 | \u0011GG\u0001 | Invalid hexadecimal escape in string literal at '\\x11G"\n "G\\001"'. | +| test.c:66:19:67:26 | \u0011GG\u00013 | Invalid hexadecimal escape in string literal at '\\x11G"\n "G\\0013"'. | +| test.c:66:19:67:26 | \u0011GG\u00013 | Invalid octal escape in string literal at '\\0013"'. | +| test.c:73:18:73:42 | Some Data \n\u000fA5 | Invalid octal escape in string literal at '\\017A" "5"'. | +| test.c:74:18:74:49 | Some Data \n\u000fA\n1 | Invalid octal escape in string literal at '\\0121"'. | +| test.c:76:18:76:32 | \u0011G\u00012 | Invalid octal escape in string literal at '\\0012"'. | +| test.c:77:18:77:32 | \u0011GG\u0001 | Invalid hexadecimal escape in string literal at '\\x11G" "G\\001"'. | +| test.c:78:18:78:33 | \u0011GG\u00013 | Invalid hexadecimal escape in string literal at '\\x11G" "G\\0013"'. | +| test.c:78:18:78:33 | \u0011GG\u00013 | Invalid octal escape in string literal at '\\0013"'. | +| test.c:81:11:81:16 | 10 | Invalid hexadecimal escape in string literal at '\\x0a''. | diff --git a/c/common/test/rules/nonterminatedescapesequences/NonTerminatedEscapeSequences.ql b/c/common/test/rules/nonterminatedescapesequences/NonTerminatedEscapeSequences.ql new file mode 100644 index 0000000000..c1aae3c31b --- /dev/null +++ b/c/common/test/rules/nonterminatedescapesequences/NonTerminatedEscapeSequences.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.nonterminatedescapesequences.NonTerminatedEscapeSequences + +class TestFileQuery extends NonTerminatedEscapeSequencesSharedQuery, TestQuery { } diff --git a/c/common/test/rules/nonterminatedescapesequences/test.c b/c/common/test/rules/nonterminatedescapesequences/test.c new file mode 100644 index 0000000000..67c6e3d5a3 --- /dev/null +++ b/c/common/test/rules/nonterminatedescapesequences/test.c @@ -0,0 +1,81 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +#include + +struct SampleStruct { + int x1 : 1; // NON_COMPLIANT: very likely be signed, but if it's not, the + // query will automatically handle it since we use signed(), not + // isExplicitlySigned(). + signed int x2 : 1; // NON_COMPLIANT: single-bit named field with a signed type + signed char + x3 : 1; // NON_COMPLIANT: single-bit named field with a signed type + signed short + x4 : 1; // NON_COMPLIANT: single-bit named field with a signed type + unsigned int + x5 : 1; // COMPLIANT: single-bit named field but with an unsigned type + signed int x6 : 2; // COMPLIANT: named field with a signed type but declared + // to carry more than 1 bit + signed char : 1; // COMPLIANT: single-bit bit-field but unnamed +} sample_struct; + +struct S { + signed int x : 1; // NON-COMPLIANT + signed int y : 5; // COMPLIANT + signed int z : 7; // COMPLIANT + signed int : 0; // COMPLIANT + signed int : 1; // COMPLIANT + signed int : 2; // COMPLIANT +}; +const char *a1 = "\x11" + "G"; // COMPLIANT + +const char *a2 = "\x1" + "G"; // COMPLIANT + +const char *a3 = "\x1A"; // COMPLIANT + +const char *a4 = "\x1AG"; // NON_COMPLIANT + +const char *a5 = "\021"; // COMPLIANT +const char *a6 = "\029"; // NON_COMPLIANT +const char *a7 = "\0" + "0"; // COMPLIANT +const char *a8 = "\0127"; // NON_COMPLIANT +const char *a9 = "\0157"; // NON_COMPLIANT + +const char *a10 = "\012\0129"; // NON_COMPLIANT (1x) +const char *a11 = "\012\019"; // NON_COMPLIANT +const char *a12 = "\012\017"; // COMPLIANT + +const char *a13 = "\012AAA\017"; // NON_COMPLIANT (1x) + +const char *a14 = "Some Data \012\017"; // COMPLIANT +const char *a15 = "Some Data \012\017A"; // NON_COMPLIANT (1x) +const char *a16 = "Some Data \012\017A" + "5"; // NON_COMPLIANT (1x) +const char *a17 = "Some Data \012\017" + "A" + "\0121"; // NON_COMPLIANT (1x) + +const char *a18 = "\x11" + "G\001"; // COMPLIANT +const char *a19 = "\x11" + "G\0012"; // NON_COMPLIANT (1x) +const char *a20 = "\x11G" + "G\001"; // NON_COMPLIANT (1x) +const char *a21 = "\x11G" + "G\0013"; // NON_COMPLIANT (2x) + +// clang-format off +const char *b1 = "\x11" "G"; // COMPLIANT +const char *b2 = "\x1" "G"; // COMPLIANT +const char *b3 = "\0" "0"; // COMPLIANT +const char *b4 = "Some Data \012\017A" "5"; // NON_COMPLIANT (1x) +const char *b5 = "Some Data \012\017" "A" "\0121"; // NON_COMPLIANT (1x) +const char *b6 = "\x11" "G\001"; // COMPLIANT +const char *b7 = "\x11" "G\0012"; // NON_COMPLIANT (1x) +const char *b8 = "\x11G" "G\001"; // NON_COMPLIANT (1x) +const char *b9 = "\x11G" "G\0013"; // NON_COMPLIANT (2x) + +char c1 = '\023'; // COMPLIANT +char c2 = '\x0a'; // COMPLIANT diff --git a/c/common/test/rules/nonuniqueenumerationconstant/NonUniqueEnumerationConstant.expected b/c/common/test/rules/nonuniqueenumerationconstant/NonUniqueEnumerationConstant.expected new file mode 100644 index 0000000000..65e57e3575 --- /dev/null +++ b/c/common/test/rules/nonuniqueenumerationconstant/NonUniqueEnumerationConstant.expected @@ -0,0 +1 @@ +| test.c:5:19:5:20 | c4 | Nonunique value of enum constant compared to $@ | test.c:5:23:5:24 | c5 | c5 | diff --git a/c/common/test/rules/nonuniqueenumerationconstant/NonUniqueEnumerationConstant.ql b/c/common/test/rules/nonuniqueenumerationconstant/NonUniqueEnumerationConstant.ql new file mode 100644 index 0000000000..97ba6f516e --- /dev/null +++ b/c/common/test/rules/nonuniqueenumerationconstant/NonUniqueEnumerationConstant.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.nonuniqueenumerationconstant.NonUniqueEnumerationConstant + +class TestFileQuery extends NonUniqueEnumerationConstantSharedQuery, TestQuery { } diff --git a/c/common/test/rules/nonuniqueenumerationconstant/test.c b/c/common/test/rules/nonuniqueenumerationconstant/test.c new file mode 100644 index 0000000000..0712cb59e4 --- /dev/null +++ b/c/common/test/rules/nonuniqueenumerationconstant/test.c @@ -0,0 +1,6 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +enum e { c = 3 }; // COMPLIANT +enum e1 { c1 = 3, c2 }; // COMPLIANT +enum e3 { c3 = 3, c4, c5 = 4 }; // NON_COMPLIANT +enum e4 { c6 = 3, c7, c8, c9 = 6 }; // COMPLIANT \ No newline at end of file diff --git a/c/common/test/rules/onlyfreememoryallocateddynamicallyshared/OnlyFreeMemoryAllocatedDynamicallyShared.expected b/c/common/test/rules/onlyfreememoryallocateddynamicallyshared/OnlyFreeMemoryAllocatedDynamicallyShared.expected index 5881d5e78f..a6c41a6d75 100644 --- a/c/common/test/rules/onlyfreememoryallocateddynamicallyshared/OnlyFreeMemoryAllocatedDynamicallyShared.expected +++ b/c/common/test/rules/onlyfreememoryallocateddynamicallyshared/OnlyFreeMemoryAllocatedDynamicallyShared.expected @@ -6,10 +6,10 @@ problems | test.c:18:36:18:38 | ptr | test.c:27:7:27:8 | & ... | test.c:18:36:18:38 | ptr | Free expression frees memory which was not dynamically allocated. | | test.c:26:8:26:8 | p | test.c:25:13:25:14 | & ... | test.c:26:8:26:8 | p | Free expression frees memory which was not dynamically allocated. | edges -| test.c:18:24:18:26 | ptr | test.c:18:36:18:38 | ptr | -| test.c:25:13:25:14 | & ... | test.c:26:8:26:8 | p | -| test.c:27:7:27:8 | & ... | test.c:28:15:28:15 | p | -| test.c:28:15:28:15 | p | test.c:18:24:18:26 | ptr | +| test.c:18:24:18:26 | ptr | test.c:18:36:18:38 | ptr | provenance | | +| test.c:25:13:25:14 | & ... | test.c:26:8:26:8 | p | provenance | | +| test.c:27:7:27:8 | & ... | test.c:28:15:28:15 | p | provenance | | +| test.c:28:15:28:15 | p | test.c:18:24:18:26 | ptr | provenance | | nodes | test.c:8:8:8:10 | g_p | semmle.label | g_p | | test.c:10:8:10:10 | g_p | semmle.label | g_p | diff --git a/c/common/test/rules/readofuninitializedmemory/test.c b/c/common/test/rules/readofuninitializedmemory/test.c index ce2c60484e..e76c5a22b3 100644 --- a/c/common/test/rules/readofuninitializedmemory/test.c +++ b/c/common/test/rules/readofuninitializedmemory/test.c @@ -94,4 +94,6 @@ void test_non_default_init() { static struct A ss; use_struct_A( ss); // COMPLIANT - static struct type variables are zero initialized + _Atomic int x; + use_int(x); // COMPLIANT - atomics are special, covered by other rules } \ No newline at end of file diff --git a/c/common/test/rules/resultofanassignmentoperatorshouldnotbeused/ResultOfAnAssignmentOperatorShouldNotBeUsed.expected b/c/common/test/rules/resultofanassignmentoperatorshouldnotbeused/ResultOfAnAssignmentOperatorShouldNotBeUsed.expected new file mode 100644 index 0000000000..c0a8359320 --- /dev/null +++ b/c/common/test/rules/resultofanassignmentoperatorshouldnotbeused/ResultOfAnAssignmentOperatorShouldNotBeUsed.expected @@ -0,0 +1,3 @@ +| test.c:9:7:9:12 | ... = ... | Use of an assignment operator's result. | +| test.c:13:11:13:16 | ... = ... | Use of an assignment operator's result. | +| test.c:15:8:15:13 | ... = ... | Use of an assignment operator's result. | diff --git a/c/common/test/rules/resultofanassignmentoperatorshouldnotbeused/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql b/c/common/test/rules/resultofanassignmentoperatorshouldnotbeused/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql new file mode 100644 index 0000000000..286e4424a4 --- /dev/null +++ b/c/common/test/rules/resultofanassignmentoperatorshouldnotbeused/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.resultofanassignmentoperatorshouldnotbeused.ResultOfAnAssignmentOperatorShouldNotBeUsed + +class TestFileQuery extends ResultOfAnAssignmentOperatorShouldNotBeUsedSharedQuery, TestQuery { } diff --git a/c/common/test/rules/resultofanassignmentoperatorshouldnotbeused/test.c b/c/common/test/rules/resultofanassignmentoperatorshouldnotbeused/test.c new file mode 100644 index 0000000000..db0a45384e --- /dev/null +++ b/c/common/test/rules/resultofanassignmentoperatorshouldnotbeused/test.c @@ -0,0 +1,16 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +void test() { + int l1, l2; + int l3[1]; + + l1 = l2; // COMPLIANT + + if (l1 = 1) // NON_COMPLIANT + { + } + + l1 = l3[l2 = 0]; // NON_COMPLIANT + + l1 = l2 = 0; // NON_COMPLIANT +} diff --git a/c/common/test/rules/unsignedoperationwithconstantoperandswraps/UnsignedOperationWithConstantOperandsWraps.expected b/c/common/test/rules/unsignedoperationwithconstantoperandswraps/UnsignedOperationWithConstantOperandsWraps.expected new file mode 100644 index 0000000000..33ec8d6995 --- /dev/null +++ b/c/common/test/rules/unsignedoperationwithconstantoperandswraps/UnsignedOperationWithConstantOperandsWraps.expected @@ -0,0 +1,4 @@ +| test.c:7:3:7:9 | ... + ... | Operation + of type unsigned int may wrap. | +| test.c:8:3:8:10 | ... += ... | Operation += of type unsigned int may wrap. | +| test.c:61:3:61:9 | ... - ... | Operation - of type unsigned int may wrap. | +| test.c:62:3:62:10 | ... -= ... | Operation -= of type unsigned int may wrap. | diff --git a/c/common/test/rules/unsignedoperationwithconstantoperandswraps/UnsignedOperationWithConstantOperandsWraps.ql b/c/common/test/rules/unsignedoperationwithconstantoperandswraps/UnsignedOperationWithConstantOperandsWraps.ql new file mode 100644 index 0000000000..b88e7637c1 --- /dev/null +++ b/c/common/test/rules/unsignedoperationwithconstantoperandswraps/UnsignedOperationWithConstantOperandsWraps.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.unsignedoperationwithconstantoperandswraps.UnsignedOperationWithConstantOperandsWraps + +class TestFileQuery extends UnsignedOperationWithConstantOperandsWrapsSharedQuery, TestQuery { } diff --git a/c/common/test/rules/unsignedoperationwithconstantoperandswraps/test.c b/c/common/test/rules/unsignedoperationwithconstantoperandswraps/test.c new file mode 100644 index 0000000000..214b18a44f --- /dev/null +++ b/c/common/test/rules/unsignedoperationwithconstantoperandswraps/test.c @@ -0,0 +1,83 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. + +#include + +void test_add_simple(unsigned int i1, unsigned int i2) { + i1 + i2; // NON_COMPLIANT - not bounds checked + i1 += i2; // NON_COMPLIANT - not bounds checked +} + +void test_add_precheck(unsigned int i1, unsigned int i2) { + if (UINT_MAX - i1 < i2) { + // handle error + } else { + i1 + i2; // COMPLIANT - bounds checked + i1 += i2; // COMPLIANT - bounds checked + } +} + +void test_add_precheck_2(unsigned int i1, unsigned int i2) { + if (i1 + i2 < i1) { + // handle error + } else { + i1 + i2; // COMPLIANT - bounds checked + i1 += i2; // COMPLIANT - bounds checked + } +} + +void test_add_postcheck(unsigned int i1, unsigned int i2) { + unsigned int i3 = i1 + i2; // COMPLIANT - checked for overflow afterwards + if (i3 < i1) { + // handle error + } + i1 += i2; // COMPLIANT - checked for overflow afterwards + if (i1 < i2) { + // handle error + } +} + +void test_ex2(unsigned int i1, unsigned int i2) { + unsigned int ci1 = 2; + unsigned int ci2 = 3; + ci1 + ci2; // COMPLIANT, compile time constants + i1 + 0; // COMPLIANT + i1 += 0; // COMPLIANT + i1 - 0; // COMPLIANT + i1 -= 0; // COMPLIANT + UINT_MAX - i1; // COMPLIANT - cannot be smaller than 0 + i1 * 1; // COMPLIANT + i1 *= 1; // COMPLIANT + if (0 <= i1 && i1 < 32) { + UINT_MAX >> i1; // COMPLIANT + } +} + +void test_ex3(unsigned int i1, unsigned int i2) { + i1 << i2; // COMPLIANT - by EX3 +} + +void test_sub_simple(unsigned int i1, unsigned int i2) { + i1 - i2; // NON_COMPLIANT - not bounds checked + i1 -= i2; // NON_COMPLIANT - not bounds checked +} + +void test_sub_precheck(unsigned int i1, unsigned int i2) { + if (i1 < i2) { + // handle error + } else { + i1 - i2; // COMPLIANT - bounds checked + i1 -= i2; // COMPLIANT - bounds checked + } +} + +void test_sub_postcheck(unsigned int i1, unsigned int i2) { + unsigned int i3 = i1 - i2; // COMPLIANT - checked for wrap afterwards + if (i3 > i1) { + // handle error + } + i1 -= i2; // COMPLIANT - checked for wrap afterwards + if (i1 > i2) { + // handle error + } +} \ No newline at end of file diff --git a/c/common/test/rules/useofnonzerooctalliteral/UseOfNonZeroOctalLiteral.expected b/c/common/test/rules/useofnonzerooctalliteral/UseOfNonZeroOctalLiteral.expected new file mode 100644 index 0000000000..bbd4264069 --- /dev/null +++ b/c/common/test/rules/useofnonzerooctalliteral/UseOfNonZeroOctalLiteral.expected @@ -0,0 +1,2 @@ +| test.c:5:3:5:5 | 10 | Non zero octal literal 012. | +| test.c:6:3:6:5 | 44 | Non zero octal literal 054. | diff --git a/c/common/test/rules/useofnonzerooctalliteral/UseOfNonZeroOctalLiteral.ql b/c/common/test/rules/useofnonzerooctalliteral/UseOfNonZeroOctalLiteral.ql new file mode 100644 index 0000000000..0404a7bc0c --- /dev/null +++ b/c/common/test/rules/useofnonzerooctalliteral/UseOfNonZeroOctalLiteral.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.useofnonzerooctalliteral.UseOfNonZeroOctalLiteral + +class TestFileQuery extends UseOfNonZeroOctalLiteralSharedQuery, TestQuery { } diff --git a/c/common/test/rules/useofnonzerooctalliteral/test.c b/c/common/test/rules/useofnonzerooctalliteral/test.c new file mode 100644 index 0000000000..11b439b02e --- /dev/null +++ b/c/common/test/rules/useofnonzerooctalliteral/test.c @@ -0,0 +1,7 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +void test_non_zero_octal() { + 0; // COMPLIANT - octal literal zero permitted + 012; // NON_COMPLIANT + 054; // NON_COMPLIANT +} \ No newline at end of file diff --git a/c/misra/src/codeql-pack.lock.yml b/c/misra/src/codeql-pack.lock.yml index 514e6963d0..a45ea8f438 100644 --- a/c/misra/src/codeql-pack.lock.yml +++ b/c/misra/src/codeql-pack.lock.yml @@ -2,13 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.9.3 + version: 4.0.3 codeql/dataflow: - version: 0.0.4 + version: 2.0.3 + codeql/mad: + version: 1.0.19 + codeql/rangeanalysis: + version: 1.0.19 codeql/ssa: - version: 0.1.5 + version: 1.0.19 codeql/tutorial: - version: 0.1.5 + version: 1.0.19 + codeql/typeflow: + version: 1.0.19 + codeql/typetracking: + version: 2.0.3 codeql/util: - version: 0.1.5 + version: 2.0.6 + codeql/xml: + version: 1.0.19 compiled: false diff --git a/c/misra/src/codeql-suites/misra-c-2012-third-edition-with-amendment-2.qls b/c/misra/src/codeql-suites/misra-c-2012-third-edition-with-amendment-2.qls new file mode 100644 index 0000000000..8d06e7c2c8 --- /dev/null +++ b/c/misra/src/codeql-suites/misra-c-2012-third-edition-with-amendment-2.qls @@ -0,0 +1,13 @@ +- description: MISRA C 2012 - Third Edition, First Revision including Amendment 2 +- qlpack: codeql/misra-c-coding-standards +- include: + kind: + - problem + - path-problem + tags contain: + - external/misra/c/2012/third-edition-first-revision + - external/misra/c/2012/amendment2 +- exclude: + tags contain: + - external/misra/audit + - external/misra/default-disabled diff --git a/c/misra/src/codeql-suites/misra-c-advisory.qls b/c/misra/src/codeql-suites/misra-c-advisory.qls new file mode 100644 index 0000000000..39df0d6583 --- /dev/null +++ b/c/misra/src/codeql-suites/misra-c-advisory.qls @@ -0,0 +1,12 @@ +- description: MISRA C 2023 (Advisory) +- qlpack: codeql/misra-c-coding-standards +- include: + kind: + - problem + - path-problem + tags contain: + - external/misra/obligation/advisory +- exclude: + tags contain: + - external/misra/audit + - external/misra/default-disabled diff --git a/c/misra/src/codeql-suites/misra-c-audit.qls b/c/misra/src/codeql-suites/misra-c-audit.qls new file mode 100644 index 0000000000..cac9df04ae --- /dev/null +++ b/c/misra/src/codeql-suites/misra-c-audit.qls @@ -0,0 +1,8 @@ +- description: MISRA C 2023 (Audit) +- qlpack: codeql/misra-c-coding-standards +- include: + kind: + - problem + - path-problem + tags contain: + - external/misra/c/audit diff --git a/c/misra/src/codeql-suites/misra-c-default.qls b/c/misra/src/codeql-suites/misra-c-default.qls new file mode 100644 index 0000000000..cdc6eb65ad --- /dev/null +++ b/c/misra/src/codeql-suites/misra-c-default.qls @@ -0,0 +1,11 @@ +- description: MISRA C 2023 (Default) +- qlpack: codeql/misra-c-coding-standards +- include: + kind: + - problem + - path-problem +- exclude: + tags contain: + - external/misra/audit + - external/misra/strict + - external/misra/default-disabled diff --git a/c/misra/src/codeql-suites/misra-c-mandatory.qls b/c/misra/src/codeql-suites/misra-c-mandatory.qls new file mode 100644 index 0000000000..09eccdc50c --- /dev/null +++ b/c/misra/src/codeql-suites/misra-c-mandatory.qls @@ -0,0 +1,12 @@ +- description: MISRA C 2023 (Advisory) +- qlpack: codeql/misra-c-coding-standards +- include: + kind: + - problem + - path-problem + tags contain: + - external/misra/obligation/mandatory +- exclude: + tags contain: + - external/misra/audit + - external/misra/default-disabled diff --git a/c/misra/src/codeql-suites/misra-c-required.qls b/c/misra/src/codeql-suites/misra-c-required.qls new file mode 100644 index 0000000000..f7c77e937a --- /dev/null +++ b/c/misra/src/codeql-suites/misra-c-required.qls @@ -0,0 +1,12 @@ +- description: MISRA C 2023 (Required) +- qlpack: codeql/misra-c-coding-standards +- include: + kind: + - problem + - path-problem + tags contain: + - external/misra/obligation/required +- exclude: + tags contain: + - external/misra/audit + - external/misra/default-disabled diff --git a/c/misra/src/codeql-suites/misra-c-strict.qls b/c/misra/src/codeql-suites/misra-c-strict.qls new file mode 100644 index 0000000000..b8f4885189 --- /dev/null +++ b/c/misra/src/codeql-suites/misra-c-strict.qls @@ -0,0 +1,8 @@ +- description: MISRA C 2023 (Strict) +- qlpack: codeql/misra-c-coding-standards +- include: + kind: + - problem + - path-problem + tags contain: + - external/misra/strict diff --git a/c/misra/src/codeql-suites/misra-default.qls b/c/misra/src/codeql-suites/misra-default.qls index 343379a2b3..e645bb1545 100644 --- a/c/misra/src/codeql-suites/misra-default.qls +++ b/c/misra/src/codeql-suites/misra-default.qls @@ -1,10 +1,2 @@ -- description: MISRA C 2012 (Default) -- qlpack: codeql/misra-c-coding-standards -- include: - kind: - - problem - - path-problem -- exclude: - tags contain: - - external/misra/audit - - external/misra/default-disabled +- description: "DEPRECATED - MISRA C 2012 - use misra-c-default.qls instead" +- import: codeql-suites/misra-c-default.qls diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll index a1b8d6fdb0..44193322ea 100644 --- a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -6,13 +6,17 @@ import codingstandards.c.misra import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils import MisraExpressions +newtype TEssentialFloatCategory = + Real() or + Complex() + newtype TEssentialTypeCategory = EssentiallyBooleanType() or EssentiallyCharacterType() or EssentiallyEnumType() or EssentiallySignedType() or EssentiallyUnsignedType() or - EssentiallyFloatingType() + EssentiallyFloatingType(TEssentialFloatCategory c) /** An essential type category, as specified by Appendix D.1. */ class EssentialTypeCategory extends TEssentialTypeCategory { @@ -27,7 +31,15 @@ class EssentialTypeCategory extends TEssentialTypeCategory { or this = EssentiallyUnsignedType() and result = "essentially Unsigned type" or - this = EssentiallyFloatingType() and result = "essentially Floating type" + this = EssentiallyFloatingType(Real()) and result = "essentially Floating type" + or + this = EssentiallyFloatingType(Complex()) and result = "essentially Complex Floating type" + } +} + +class EssentiallySignedOrUnsignedType extends EssentialTypeCategory { + EssentiallySignedOrUnsignedType() { + this = EssentiallySignedType() or this = EssentiallyUnsignedType() } } @@ -37,11 +49,7 @@ class EssentialTypeCategory extends TEssentialTypeCategory { private class ConstantIntegerExpr extends Expr { pragma[noinline] ConstantIntegerExpr() { - getEssentialTypeCategory(this.getType()) = - [ - EssentiallyUnsignedType().(EssentialTypeCategory), - EssentiallySignedType().(EssentialTypeCategory) - ] and + getEssentialTypeCategory(this.getType()) instanceof EssentiallySignedOrUnsignedType and exists(this.getValue().toFloat()) and not this instanceof Conversion } @@ -130,16 +138,24 @@ EssentialTypeCategory getEssentialTypeCategory(Type type) { essentialType.(IntegralType).isSigned() and not essentialType instanceof PlainCharType or + // Anonymous enums are considered to be signed + result = EssentiallySignedType() and + essentialType instanceof AnonymousEnumType and + not essentialType instanceof MisraBoolType + or result = EssentiallyUnsignedType() and essentialType.(IntegralType).isUnsigned() and not essentialType instanceof PlainCharType or result = EssentiallyEnumType() and - essentialType instanceof Enum and + essentialType instanceof NamedEnumType and not essentialType instanceof MisraBoolType or - result = EssentiallyFloatingType() and - essentialType instanceof FloatingPointType + result = EssentiallyFloatingType(Real()) and + essentialType instanceof RealNumberType + or + result = EssentiallyFloatingType(Complex()) and + essentialType instanceof ComplexNumberType ) } @@ -148,19 +164,30 @@ EssentialTypeCategory getEssentialTypeCategory(Type type) { */ pragma[nomagic] Type getEssentialType(Expr e) { - if e.hasExplicitConversion() - then - if e.getConversion() instanceof ParenthesisExpr - then - if e.getConversion().(ParenthesisExpr).hasExplicitConversion() - then result = e.getConversion().(ParenthesisExpr).getConversion().getType() - else result = e.getConversion().(ParenthesisExpr).getExpr().(EssentialExpr).getEssentialType() - else result = e.getConversion().getType() + if e.hasConversion() + then result = getEssentialTypeOfConversion(e.getFullyConverted()) + else result = e.(EssentialExpr).getEssentialType() +} + +Type getEssentialTypeOfConversion(Expr e) { + if e.(Conversion).isImplicit() or e instanceof ParenthesisExpr or e instanceof C11GenericExpr + then result = getEssentialTypeOfConversion(e.(Conversion).getExpr()) else result = e.(EssentialExpr).getEssentialType() } Type getEssentialTypeBeforeConversions(Expr e) { result = e.(EssentialExpr).getEssentialType() } +/** + * For most essential types, `Type.getSize()` is correct, except for complex floating types. + * + * For complex floating types, the size is the size of the real part, so we divide by 2. + */ +int getEssentialSize(Type essentialType) { + if getEssentialTypeCategory(essentialType) = EssentiallyFloatingType(Complex()) + then result = essentialType.getSize() / 2 + else result = essentialType.getSize() +} + class EssentialExpr extends Expr { Type getEssentialType() { result = this.getType() } @@ -179,12 +206,16 @@ class EssentialBinaryLogicalOperationExpr extends EssentialExpr, BinaryLogicalOp override Type getEssentialType() { result instanceof BoolType } } +class EssentialUnaryLogicalOperationExpr extends EssentialExpr, UnaryLogicalOperation { + override Type getEssentialType() { result instanceof BoolType } +} + class EssentialEqualityOperationExpr extends EssentialExpr, EqualityOperation { override Type getEssentialType() { result instanceof BoolType } } -class EssentialBinaryBitwiseOperationExpr extends EssentialExpr, BinaryBitwiseOperation { - EssentialBinaryBitwiseOperationExpr() { +class EssentialShiftOperationExpr extends EssentialExpr, BinaryBitwiseOperation { + EssentialShiftOperationExpr() { this instanceof LShiftExpr or this instanceof RShiftExpr } @@ -226,9 +257,7 @@ class EssentialUnaryPlusExpr extends EssentialExpr, UnaryPlusExpr { operandEssentialType = getEssentialType(getOperand()) and operandEssentialTypeCategory = getEssentialTypeCategory(operandEssentialType) | - if - operandEssentialTypeCategory = - [EssentiallyUnsignedType().(TEssentialTypeCategory), EssentiallySignedType()] + if operandEssentialTypeCategory instanceof EssentiallySignedOrUnsignedType then result = operandEssentialType else result = getStandardType() ) @@ -248,6 +277,13 @@ class EssentialUnaryMinusExpr extends EssentialExpr, UnaryMinusExpr { } } +bindingset[essentialTypeA, essentialTypeB] +private Type maxRankType(Type essentialTypeA, Type essentialTypeB) { + if essentialTypeA.getSize() > essentialTypeB.getSize() + then result = essentialTypeA + else result = essentialTypeB +} + class EssentialConditionalExpr extends EssentialExpr, ConditionalExpr { override Type getEssentialType() { exists(Type thenEssentialType, Type elseEssentialType | @@ -258,110 +294,169 @@ class EssentialConditionalExpr extends EssentialExpr, ConditionalExpr { then result = thenEssentialType else if - getEssentialTypeCategory(thenEssentialType) = EssentiallySignedType() and - getEssentialTypeCategory(elseEssentialType) = EssentiallySignedType() - then - if thenEssentialType.getSize() > elseEssentialType.getSize() - then result = thenEssentialType - else result = elseEssentialType - else - if - getEssentialTypeCategory(thenEssentialType) = EssentiallyUnsignedType() and - getEssentialTypeCategory(elseEssentialType) = EssentiallyUnsignedType() - then - if thenEssentialType.getSize() > elseEssentialType.getSize() - then result = thenEssentialType - else result = elseEssentialType - else result = this.getStandardType() + getEssentialTypeCategory(thenEssentialType) = getEssentialTypeCategory(elseEssentialType) and + getEssentialTypeCategory(thenEssentialType) instanceof EssentiallySignedOrUnsignedType + then result = maxRankType(thenEssentialType, elseEssentialType) + else result = this.getStandardType() ) } } -class EssentialBinaryArithmeticExpr extends EssentialExpr, BinaryArithmeticOperation { - EssentialBinaryArithmeticExpr() { - // GNU C extension has min/max which we can ignore - not this instanceof MinExpr and - not this instanceof MaxExpr +/** + * A binary operation subject to usual conversions, with essential type behaviour as specified by D.7.9. + */ +class EssentialBinaryOperationSubjectToUsualConversions extends EssentialExpr, BinaryOperation { + EssentialBinaryOperationSubjectToUsualConversions() { + this instanceof MulExpr + or + this instanceof DivExpr + or + this instanceof RemExpr + or + this instanceof AddExpr + or + this instanceof SubExpr + or + this instanceof BitwiseAndExpr + or + this instanceof BitwiseOrExpr + or + this instanceof BitwiseXorExpr } override Type getEssentialType() { exists( Type leftEssentialType, Type rightEssentialType, EssentialTypeCategory leftEssentialTypeCategory, - EssentialTypeCategory rightEssentialTypeCategory + EssentialTypeCategory rightEssentialTypeCategory, int intTypeSize | leftEssentialType = getEssentialType(getLeftOperand()) and rightEssentialType = getEssentialType(getRightOperand()) and leftEssentialTypeCategory = getEssentialTypeCategory(leftEssentialType) and - rightEssentialTypeCategory = getEssentialTypeCategory(rightEssentialType) + rightEssentialTypeCategory = getEssentialTypeCategory(rightEssentialType) and + // For rules around addition/subtraction with char types: + intTypeSize = any(IntType i | i.isSigned()).getSize() | if - leftEssentialTypeCategory = EssentiallySignedType() and - rightEssentialTypeCategory = EssentiallySignedType() + leftEssentialTypeCategory = rightEssentialTypeCategory and + leftEssentialTypeCategory instanceof EssentiallySignedOrUnsignedType then if exists(getValue()) - then result = stlr(this) - else ( - if leftEssentialType.getSize() > rightEssentialType.getSize() - then result = leftEssentialType - else result = rightEssentialType - ) - else - if - leftEssentialTypeCategory = EssentiallyUnsignedType() and - rightEssentialTypeCategory = EssentiallyUnsignedType() then - if exists(getValue()) - then result = utlr(this) - else ( - if leftEssentialType.getSize() > rightEssentialType.getSize() - then result = leftEssentialType - else result = rightEssentialType - ) - else - if - this instanceof AddExpr and - ( - leftEssentialTypeCategory = EssentiallyCharacterType() - or - rightEssentialTypeCategory = EssentiallyCharacterType() - ) and - ( - leftEssentialTypeCategory = - [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] - or - rightEssentialTypeCategory = - [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] - ) - or - this instanceof SubExpr and - leftEssentialTypeCategory = EssentiallyCharacterType() and - rightEssentialTypeCategory = - [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] - then result instanceof PlainCharType - else result = this.getStandardType() + leftEssentialTypeCategory = EssentiallySignedType() and result = stlr(this) + or + leftEssentialTypeCategory = EssentiallyUnsignedType() and result = utlr(this) + else result = maxRankType(leftEssentialType, rightEssentialType) + else result = this.getStandardType() + ) + } +} + +/** + * An add expression, with essential type behaviour as specified by D.7.9. + */ +class EssentialAddExpr extends EssentialBinaryOperationSubjectToUsualConversions, AddExpr { + override Type getEssentialType() { + exists( + Type otherOperandType, EssentialTypeCategory operandTypeCategory, + EssentialTypeCategory otherOperandTypeCategory, int intTypeSize + | + operandTypeCategory = getEssentialTypeCategory(getEssentialType(getAnOperand())) and + otherOperandType = getEssentialType(getAnOperand()) and + otherOperandTypeCategory = getEssentialTypeCategory(otherOperandType) and + intTypeSize = any(IntType i).getSize() + | + if + operandTypeCategory = EssentiallyCharacterType() and + otherOperandTypeCategory instanceof EssentiallySignedOrUnsignedType and + otherOperandType.getSize() <= intTypeSize + then result instanceof PlainCharType + else result = super.getEssentialType() + ) + } +} + +/** + * A sub expression, with essential type behaviour as specified by D.7.9. + */ +class EssentialSubExpr extends EssentialBinaryOperationSubjectToUsualConversions, SubExpr { + override Type getEssentialType() { + exists( + EssentialTypeCategory leftEssentialTypeCategory, Type rightEssentialType, + EssentialTypeCategory rightEssentialTypeCategory, int intTypeSize + | + leftEssentialTypeCategory = getEssentialTypeCategory(getEssentialType(getLeftOperand())) and + rightEssentialType = getEssentialType(getRightOperand()) and + rightEssentialTypeCategory = getEssentialTypeCategory(rightEssentialType) and + intTypeSize = any(IntType i).getSize() + | + if + leftEssentialTypeCategory = EssentiallyCharacterType() and + rightEssentialTypeCategory instanceof EssentiallySignedOrUnsignedType and + rightEssentialType.getSize() <= intTypeSize + then result instanceof PlainCharType + else result = super.getEssentialType() ) } } +/** + * A named Enum type, as per D.5. + */ +class NamedEnumType extends Enum { + NamedEnumType() { + not isAnonymous() + or + exists(Type useOfEnum | this = useOfEnum.stripType() | + exists(TypedefType t | t.getBaseType() = useOfEnum) + or + exists(Function f | f.getType() = useOfEnum or f.getAParameter().getType() = useOfEnum) + or + exists(Struct s | s.getAField().getType() = useOfEnum) + or + exists(Variable v | v.getType() = useOfEnum) + ) + } +} + +/** + * An anonymous Enum type, as per D.5. + */ +class AnonymousEnumType extends Enum { + AnonymousEnumType() { not this instanceof NamedEnumType } +} + +/** + * The EssentialType of an EnumConstantAccess, which may be essentially enum or essentially signed. + */ class EssentialEnumConstantAccess extends EssentialExpr, EnumConstantAccess { - override Type getEssentialType() { result = getTarget().getDeclaringEnum() } + override Type getEssentialType() { + exists(Enum e | e = getTarget().getDeclaringEnum() | + if e instanceof NamedEnumType then result = e else result = stlr(this) + ) + } } class EssentialLiteral extends EssentialExpr, Literal { override Type getEssentialType() { if this instanceof BooleanLiteral - then result instanceof MisraBoolType + then + // This returns a multitude of types - not sure if we really want that + result instanceof MisraBoolType else ( - if this.(CharLiteral).getCharacter().length() = 1 + if this instanceof CharLiteral then result instanceof PlainCharType - else ( - getStandardType().(IntegralType).isSigned() and - result = stlr(this) - or - not getStandardType().(IntegralType).isSigned() and - result = utlr(this) - ) + else + exists(Type underlyingStandardType | + underlyingStandardType = getStandardType().getUnderlyingType() + | + if underlyingStandardType instanceof IntType + then + if underlyingStandardType.(IntType).isSigned() + then result = stlr(this) + else result = utlr(this) + else result = getStandardType() + ) ) } } diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index e284cb5151..fad952166c 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,8 +1,9 @@ name: codeql/misra-c-coding-standards -version: 2.32.0-dev +version: 2.52.0-dev description: MISRA C 2012 suites: codeql-suites license: MIT +default-suite-file: codeql-suites/misra-c-default.qls dependencies: codeql/common-c-coding-standards: '*' - codeql/cpp-all: 0.9.3 + codeql/cpp-all: 4.0.3 diff --git a/c/misra/src/rules/DIR-4-10/PrecautionIncludeGuardsNotProvided.ql b/c/misra/src/rules/DIR-4-10/PrecautionIncludeGuardsNotProvided.ql index 58ec5c80a9..338437b5b2 100644 --- a/c/misra/src/rules/DIR-4-10/PrecautionIncludeGuardsNotProvided.ql +++ b/c/misra/src/rules/DIR-4-10/PrecautionIncludeGuardsNotProvided.ql @@ -10,6 +10,7 @@ * correctness * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/DIR-4-11/CheckMathLibraryFunctionParameters.ql b/c/misra/src/rules/DIR-4-11/CheckMathLibraryFunctionParameters.ql new file mode 100644 index 0000000000..4011b210f8 --- /dev/null +++ b/c/misra/src/rules/DIR-4-11/CheckMathLibraryFunctionParameters.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/check-math-library-function-parameters + * @name DIR-4-11: The validity of values passed to `math.h` library functions shall be checked + * @description Range, domain or pole errors in math functions may return unexpected values, trigger + * floating-point exceptions or set unexpected error modes. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/dir-4-11 + * correctness + * external/misra/c/2012/third-edition-first-revision + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.uncheckedrangedomainpoleerrors.UncheckedRangeDomainPoleErrors + +class CheckMathLibraryFunctionParametersQuery extends UncheckedRangeDomainPoleErrorsSharedQuery { + CheckMathLibraryFunctionParametersQuery() { + this = ContractsPackage::checkMathLibraryFunctionParametersQuery() + } +} diff --git a/c/misra/src/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.ql b/c/misra/src/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.ql new file mode 100644 index 0000000000..6a910a1a71 --- /dev/null +++ b/c/misra/src/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.ql @@ -0,0 +1,43 @@ +/** + * @id c/misra/low-precision-periodic-trigonometric-function-call + * @name DIR-4-11: The validity of values passed to trigonometric functions shall be checked + * @description Trigonometric periodic functions have significantly less precision when called with + * large floating-point values. + * @kind problem + * @precision high + * @problem.severity warning + * @tags external/misra/id/dir-4-11 + * correctness + * external/misra/c/2012/third-edition-first-revision + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis + +float getMaxAllowedAbsoluteValue(FloatingPointType t, string description) { + if t.getSize() <= 4 + then ( + // Per MISRA, assume k=1 for float types. + result = 3.15 and description = "pi" + ) else ( + // Allow k=10 for doubles, as the standard allows for a larger range depending on the + // implementation, application, and precision goals. + result = 10 * 3.15 and description = "10 * pi" + ) +} + +from FunctionCall fc, Expr argument, float maxValue, float maxAllowedValue, string maxAllowedStr +where + not isExcluded(fc, ContractsPackage::lowPrecisionPeriodicTrigonometricFunctionCallQuery()) and + fc.getTarget().getName() = ["sin", "cos", "tan"] and + argument = fc.getArgument(0) and + maxValue = rank[1](float bound | bound = [lowerBound(argument), upperBound(argument)].abs()) and + maxAllowedValue = getMaxAllowedAbsoluteValue(argument.getType(), maxAllowedStr) and + maxValue > maxAllowedValue +select fc, + "Call to periodic trigonometric function " + fc.getTarget().getName() + + " with maximum argument absolute value of " + maxValue.toString() + + ", which exceeds the recommended " + "maximum of " + maxAllowedStr + "." diff --git a/c/misra/src/rules/DIR-4-12/StdLibDynamicMemoryAllocationUsed.ql b/c/misra/src/rules/DIR-4-12/StdLibDynamicMemoryAllocationUsed.ql index dc1e21c97a..5c70bec761 100644 --- a/c/misra/src/rules/DIR-4-12/StdLibDynamicMemoryAllocationUsed.ql +++ b/c/misra/src/rules/DIR-4-12/StdLibDynamicMemoryAllocationUsed.ql @@ -11,6 +11,7 @@ * security * correctness * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql new file mode 100644 index 0000000000..0294fc6919 --- /dev/null +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/possible-misuse-of-undetected-infinity + * @name DIR-4-15: Evaluation of floating-point expressions shall not lead to the undetected generation of infinities + * @description Evaluation of floating-point expressions shall not lead to the undetected generation + * of infinities. + * @kind path-problem + * @precision medium + * @problem.severity warning + * @tags external/misra/id/dir-4-15 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.misuseofinfinitefloatingpointvalue.MisuseOfInfiniteFloatingPointValue + +class PossibleMisuseOfUndetectedInfinityQuery extends MisuseOfInfiniteFloatingPointValueSharedQuery { + PossibleMisuseOfUndetectedInfinityQuery() { + this = FloatingTypes2Package::possibleMisuseOfUndetectedInfinityQuery() + } +} diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql new file mode 100644 index 0000000000..9315a4ed4c --- /dev/null +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/possible-misuse-of-undetected-nan + * @name DIR-4-15: Evaluation of floating-point expressions shall not lead to the undetected generation of NaNs + * @description Evaluation of floating-point expressions shall not lead to the undetected generation + * of NaNs. + * @kind path-problem + * @precision low + * @problem.severity warning + * @tags external/misra/id/dir-4-15 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.misuseofnanfloatingpointvalue.MisuseOfNaNFloatingPointValue + +class PossibleMisuseOfUndetectedNaNQuery extends MisuseOfNaNFloatingPointValueSharedQuery { + PossibleMisuseOfUndetectedNaNQuery() { + this = FloatingTypes2Package::possibleMisuseOfUndetectedNaNQuery() + } +} diff --git a/c/misra/src/rules/DIR-4-2/UsageOfAssemblyLanguageShouldBeDocumented.ql b/c/misra/src/rules/DIR-4-2/UsageOfAssemblyLanguageShouldBeDocumented.ql index 9503024671..1afd57913e 100644 --- a/c/misra/src/rules/DIR-4-2/UsageOfAssemblyLanguageShouldBeDocumented.ql +++ b/c/misra/src/rules/DIR-4-2/UsageOfAssemblyLanguageShouldBeDocumented.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/dir-4-2 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/DIR-4-3/LanguageNotEncapsulatedAndIsolated.ql b/c/misra/src/rules/DIR-4-3/LanguageNotEncapsulatedAndIsolated.ql index fb9f00e9c4..698cbabf01 100644 --- a/c/misra/src/rules/DIR-4-3/LanguageNotEncapsulatedAndIsolated.ql +++ b/c/misra/src/rules/DIR-4-3/LanguageNotEncapsulatedAndIsolated.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/dir-4-3 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/DIR-4-4/SectionsOfCodeShallNotBeCommentedOut.ql b/c/misra/src/rules/DIR-4-4/SectionsOfCodeShallNotBeCommentedOut.ql index d0af758699..272a411f0e 100644 --- a/c/misra/src/rules/DIR-4-4/SectionsOfCodeShallNotBeCommentedOut.ql +++ b/c/misra/src/rules/DIR-4-4/SectionsOfCodeShallNotBeCommentedOut.ql @@ -9,6 +9,7 @@ * maintainability * readability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/DIR-4-5/IdentifiersInTheSameNameSpaceUnambiguous.ql b/c/misra/src/rules/DIR-4-5/IdentifiersInTheSameNameSpaceUnambiguous.ql index ced5bce28f..5dd78fc340 100644 --- a/c/misra/src/rules/DIR-4-5/IdentifiersInTheSameNameSpaceUnambiguous.ql +++ b/c/misra/src/rules/DIR-4-5/IdentifiersInTheSameNameSpaceUnambiguous.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/dir-4-5 * readability * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/DIR-4-6/PlainNumericalTypeUsedOverExplicitTypedef.ql b/c/misra/src/rules/DIR-4-6/PlainNumericalTypeUsedOverExplicitTypedef.ql index c3ea6dfdbd..0e6c902441 100644 --- a/c/misra/src/rules/DIR-4-6/PlainNumericalTypeUsedOverExplicitTypedef.ql +++ b/c/misra/src/rules/DIR-4-6/PlainNumericalTypeUsedOverExplicitTypedef.ql @@ -7,6 +7,7 @@ * @precision high * @problem.severity error * @tags external/misra/id/dir-4-6 + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ @@ -28,6 +29,8 @@ class BuiltInNumericType extends BuiltInType { this instanceof DoubleType or this instanceof LongDoubleType + or + this instanceof ComplexNumberType } } @@ -37,22 +40,64 @@ predicate forbiddenBuiltinNumericUsedInDecl(Variable var, string message) { message = "The type " + var.getType() + " is not a fixed-width numeric type." } +class SizedTypeString extends string { + string pattern; + int size; + + bindingset[this] + pragma[inline] + SizedTypeString() { + pattern = "(u?int|c?float)(4|8|16|32|64|128)_t" and + this.regexpMatch(pattern) and + size = this.regexpCapture(pattern, 2).toInt() + } + + bindingset[this] + pragma[inline] + int getSize() { result = size } + + bindingset[this] + pragma[inline] + predicate isComplex() { this.charAt(0) = "c" } +} + +predicate forbiddenComplexType(CTypedefType typedef, string message) { + typedef.getName().(SizedTypeString).isComplex() and + ( + if typedef.getBaseType().stripTopLevelSpecifiers() instanceof ComplexNumberType + then + typedef.getSize() * 8 != typedef.getName().(SizedTypeString).getSize() * 2 and + message = "The typedef type " + typedef.getName() + " does not have its indicated real size." + else message = "The typedef type " + typedef.getName() + " is not a complex type." + ) +} + +predicate forbiddenRealType(CTypedefType typedef, string message) { + not typedef.getName().(SizedTypeString).isComplex() and + ( + if typedef.getBaseType().stripTopLevelSpecifiers() instanceof ComplexNumberType + then message = "The typedef name " + typedef.getName() + " does not indicate a complex type." + else ( + typedef.getSize() * 8 != typedef.getName().(SizedTypeString).getSize() and + message = "The typedef type " + typedef.getName() + " does not have its indicated size." + ) + ) +} + predicate forbiddenTypedef(CTypedefType typedef, string message) { /* If the typedef's name contains an explicit size */ ( - if typedef.getName().regexpMatch("u?(int|float)(4|8|16|32|64|128)_t") + if typedef.getName() instanceof SizedTypeString then ( - /* Then the actual type size should match. */ - not typedef.getSize() * 8 = - // times 8 because getSize() gets the size in bytes - typedef.getName().regexpCapture("u?(int|float)(4|8|16|32|64|128)_t", 2).toInt() and - message = "The typedef type " + typedef.getName() + " does not have its indicated size." + forbiddenRealType(typedef, message) + or + forbiddenComplexType(typedef, message) ) else ( ( // type def is to a built in numeric type typedef.getBaseType() instanceof BuiltInNumericType and // but does not include the size in the name - not typedef.getName().regexpMatch("u?(int|float)(4|8|16|32|64|128)_t") + not typedef.getName() instanceof SizedTypeString or // this is a typedef to a forbidden type def forbiddenTypedef(typedef.getBaseType(), _) diff --git a/c/misra/src/rules/DIR-4-7/FunctionErrorInformationUntested.ql b/c/misra/src/rules/DIR-4-7/FunctionErrorInformationUntested.ql new file mode 100644 index 0000000000..0c0a3d7b1a --- /dev/null +++ b/c/misra/src/rules/DIR-4-7/FunctionErrorInformationUntested.ql @@ -0,0 +1,28 @@ +/** + * @id c/misra/function-error-information-untested + * @name DIR-4-7: If a function generates error information, then that error information shall be tested + * @description A function (whether it is part of the standard library, a third party library or a + * user defined function) may provide some means of indicating the occurrence of an + * error. This may be via a global error flag, a parametric error flag, a special + * return value or some other means. Whenever such a mechanism is provided by a + * function the calling program shall check for the indication of an error as soon as + * the function returns. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/dir-4-7 + * maintainability + * external/misra/c/2012/third-edition-first-revision + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.functionerroneousreturnvaluenottested.FunctionErroneousReturnValueNotTested + +class FunctionErrorInformationUntestedQuery extends FunctionErroneousReturnValueNotTestedSharedQuery +{ + FunctionErrorInformationUntestedQuery() { + this = ContractsPackage::functionErrorInformationUntestedQuery() + } +} diff --git a/c/misra/src/rules/DIR-4-8/ObjectWithNoPointerDereferenceShouldBeOpaque.ql b/c/misra/src/rules/DIR-4-8/ObjectWithNoPointerDereferenceShouldBeOpaque.ql index 56f2dd785d..b32a0a4aee 100644 --- a/c/misra/src/rules/DIR-4-8/ObjectWithNoPointerDereferenceShouldBeOpaque.ql +++ b/c/misra/src/rules/DIR-4-8/ObjectWithNoPointerDereferenceShouldBeOpaque.ql @@ -10,6 +10,7 @@ * @tags external/misra/id/dir-4-8 * readability * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/DIR-4-9/FunctionOverFunctionLikeMacro.ql b/c/misra/src/rules/DIR-4-9/FunctionOverFunctionLikeMacro.ql index e53294fba5..582715e34f 100644 --- a/c/misra/src/rules/DIR-4-9/FunctionOverFunctionLikeMacro.ql +++ b/c/misra/src/rules/DIR-4-9/FunctionOverFunctionLikeMacro.ql @@ -10,27 +10,16 @@ * external/misra/audit * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ import cpp import codingstandards.c.misra -import codingstandards.c.IrreplaceableFunctionLikeMacro +import codingstandards.cpp.rules.functionlikemacrosdefined.FunctionLikeMacrosDefined -predicate partOfConstantExpr(MacroInvocation i) { - exists(Expr e | - e.isConstant() and - not i.getExpr() = e and - i.getExpr().getParent+() = e - ) +class FunctionOverFunctionLikeMacroQuery extends FunctionLikeMacrosDefinedSharedQuery { + FunctionOverFunctionLikeMacroQuery() { + this = Preprocessor6Package::functionOverFunctionLikeMacroQuery() + } } - -from FunctionLikeMacro m -where - not isExcluded(m, Preprocessor6Package::functionOverFunctionLikeMacroQuery()) and - not m instanceof IrreplaceableFunctionLikeMacro and - //macros can have empty body - not m.getBody().length() = 0 and - //function call not allowed in a constant expression (where constant expr is parent) - forall(MacroInvocation i | i = m.getAnInvocation() | not partOfConstantExpr(i)) -select m, "Macro used instead of a function." diff --git a/c/misra/src/rules/DIR-5-1/PossibleDataRaceBetweenThreads.ql b/c/misra/src/rules/DIR-5-1/PossibleDataRaceBetweenThreads.ql new file mode 100644 index 0000000000..edf3705a9b --- /dev/null +++ b/c/misra/src/rules/DIR-5-1/PossibleDataRaceBetweenThreads.ql @@ -0,0 +1,162 @@ +/** + * @id c/misra/possible-data-race-between-threads + * @name DIR-5-1: There shall be no data races between threads + * @description Threads shall not access the same memory location concurrently without utilization + * of thread synchronization objects. + * @kind problem + * @precision medium + * @problem.severity error + * @tags external/misra/id/dir-5-1 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Objects +import codingstandards.c.SubObjects +import codingstandards.cpp.Concurrency + +newtype TNonReentrantOperation = + TReadWrite(SubObject object) { + object.getRootIdentity().getStorageDuration().isStatic() + or + object.getRootIdentity().getStorageDuration().isAllocated() + } or + TStdFunctionCall(FunctionCall call) { + call.getTarget() + .hasName([ + "setlocale", "tmpnam", "rand", "srand", "getenv", "getenv_s", "strok", "strerror", + "asctime", "ctime", "gmtime", "localtime", "mbrtoc16", "c16rtomb", "mbrtoc32", + "c32rtomb", "mbrlen", "mbrtowc", "wcrtomb", "mbsrtowcs", "wcsrtombs" + ]) + } + +class NonReentrantOperation extends TNonReentrantOperation { + string toString() { + exists(SubObject object | + this = TReadWrite(object) and + result = object.toString() + ) + or + exists(FunctionCall call | + this = TStdFunctionCall(call) and + result = call.getTarget().getName() + ) + } + + Expr getAReadExpr() { + exists(SubObject object | + this = TReadWrite(object) and + result = object.getAnAccess() + ) + or + this = TStdFunctionCall(result) + } + + Expr getAWriteExpr() { + exists(SubObject object, Assignment assignment | + this = TReadWrite(object) and + result = assignment and + assignment.getLValue() = object.getAnAccess() + ) + or + this = TStdFunctionCall(result) + } + + string getReadString() { + this = TReadWrite(_) and + result = "read operation" + or + this = TStdFunctionCall(_) and + result = "call to non-reentrant function" + } + + string getWriteString() { + this = TReadWrite(_) and + result = "write to object" + or + this = TStdFunctionCall(_) and + result = "call to non-reentrant function" + } + + Element getSourceElement() { + exists(SubObject object | + this = TReadWrite(object) and + result = object.getRootIdentity() + ) + or + this = TStdFunctionCall(result) + } +} + +class WritingThread extends ThreadedFunction { + NonReentrantOperation aWriteObject; + Expr aWriteExpr; + + WritingThread() { + aWriteExpr = aWriteObject.getAWriteExpr() and + // This function directly contains the write expression, or transitively calls the function + // that contains the write expression. + this.calls*(aWriteExpr.getEnclosingFunction()) and + // The write isn't synchronized with a mutex or condition object. + not aWriteExpr instanceof LockProtectedControlFlowNode and + // The write doesn't seem to be during a special initialization phase of the program. + not aWriteExpr.getEnclosingFunction().getName().matches(["%init%", "%boot%", "%start%"]) + } + + Expr getAWriteExpr() { result = aWriteExpr } +} + +class ReadingThread extends ThreadedFunction { + Expr aReadExpr; + + ReadingThread() { + exists(NonReentrantOperation op | + aReadExpr = op.getAReadExpr() and + this.calls*(aReadExpr.getEnclosingFunction()) and + not aReadExpr instanceof LockProtectedControlFlowNode + ) + } + + Expr getAReadExpr() { result = aReadExpr } +} + +predicate mayBeDataRace(Expr write, Expr read, NonReentrantOperation operation) { + exists(WritingThread wt | + wt.getAWriteExpr() = write and + write = operation.getAWriteExpr() and + exists(ReadingThread rt | + read = rt.getAReadExpr() and + read = operation.getAReadExpr() and + ( + wt.isMultiplySpawned() or + not wt = rt + ) + ) + ) +} + +from + WritingThread wt, ReadingThread rt, Expr write, Expr read, NonReentrantOperation operation, + string message, string writeString, string readString +where + not isExcluded(write, Concurrency9Package::possibleDataRaceBetweenThreadsQuery()) and + mayBeDataRace(write, read, operation) and + wt = min(WritingThread f | f.getAWriteExpr() = write | f order by f.getName()) and + rt = min(ReadingThread f | f.getAReadExpr() = read | f order by f.getName()) and + writeString = operation.getWriteString() and + readString = operation.getReadString() and + if wt.isMultiplySpawned() + then + message = + "Threaded " + writeString + + " $@ not synchronized from thread function $@ spawned from a loop." + else + message = + "Threaded " + writeString + + " $@ from thread function $@ is not synchronized with $@ from thread function $@." +select write, message, operation.getSourceElement(), operation.toString(), wt, wt.getName(), read, + "concurrent " + readString, rt, rt.getName() diff --git a/c/misra/src/rules/DIR-5-2/NotNoDeadlocksBetweenThreads.ql b/c/misra/src/rules/DIR-5-2/NotNoDeadlocksBetweenThreads.ql new file mode 100644 index 0000000000..5d949f56ed --- /dev/null +++ b/c/misra/src/rules/DIR-5-2/NotNoDeadlocksBetweenThreads.ql @@ -0,0 +1,25 @@ +/** + * @id c/misra/not-no-deadlocks-between-threads + * @name DIR-5-2: There shall be no deadlocks between threads + * @description Circular waits leading to thread deadlocks may be avoided by locking in a predefined + * order. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/dir-5-2 + * external/misra/c/2012/amendment4 + * correctness + * concurrency + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.preventdeadlockbylockinginpredefinedorder.PreventDeadlockByLockingInPredefinedOrder + +class NotNoDeadlocksBetweenThreadsQuery extends PreventDeadlockByLockingInPredefinedOrderSharedQuery +{ + NotNoDeadlocksBetweenThreadsQuery() { + this = Concurrency6Package::notNoDeadlocksBetweenThreadsQuery() + } +} diff --git a/c/misra/src/rules/DIR-5-3/BannedDynamicThreadCreation.ql b/c/misra/src/rules/DIR-5-3/BannedDynamicThreadCreation.ql new file mode 100644 index 0000000000..4bb526306b --- /dev/null +++ b/c/misra/src/rules/DIR-5-3/BannedDynamicThreadCreation.ql @@ -0,0 +1,29 @@ +/** + * @id c/misra/banned-dynamic-thread-creation + * @name DIR-5-3: There shall be no dynamic thread creation + * @description Creating threads outside of a well-defined program start-up phase creates + * uncertainty in program behavior and concurrency overhead costs. + * @kind problem + * @precision low + * @problem.severity error + * @tags external/misra/id/dir-5-3 + * external/misra/c/2012/amendment4 + * external/misra/c/audit + * correctness + * maintainability + * concurrency + * performance + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Concurrency + +from CThreadCreateCall tc, Function enclosingFunction +where + not isExcluded(tc, Concurrency6Package::bannedDynamicThreadCreationQuery()) and + enclosingFunction = tc.getEnclosingFunction() and + not enclosingFunction.getName() = "main" +select tc, "Possible dynamic creation of thread outside initialization in function '$@'.", + enclosingFunction, enclosingFunction.toString() diff --git a/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql b/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql new file mode 100644 index 0000000000..207e763fa7 --- /dev/null +++ b/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql @@ -0,0 +1,38 @@ +/** + * @id c/misra/thread-created-by-thread + * @name DIR-5-3: Threads shall not be created by other threads + * @description Creating threads within threads creates uncertainty in program behavior and + * concurrency overhead costs. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/dir-5-3 + * external/misra/c/2012/amendment4 + * correctness + * maintainability + * concurrency + * performance + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Concurrency + +class CThreadRoot extends Function { + CThreadCreateCall threadCreate; + + CThreadRoot() { threadCreate.getFunction() = this } + + /* Get a function which is reachable from this function */ + Function getAReachableFunction() { calls*(result) } + + CThreadCreateCall getACThreadCreateCall() { result = threadCreate } +} + +from CThreadCreateCall tc, CThreadRoot threadRoot +where + not isExcluded(tc, Concurrency6Package::threadCreatedByThreadQuery()) and + tc.getEnclosingFunction() = threadRoot.getAReachableFunction() +select tc, "Thread creation call reachable from function '$@', which may also be $@.", threadRoot, + threadRoot.toString(), threadRoot.getACThreadCreateCall(), "started as a thread" diff --git a/c/misra/src/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.ql b/c/misra/src/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.ql index f38e41a1b6..34a0f40fb6 100644 --- a/c/misra/src/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.ql +++ b/c/misra/src/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.ql @@ -8,13 +8,15 @@ * @tags external/misra/id/rule-1-2 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ import cpp import codingstandards.c.misra +import codingstandards.cpp.AlertReporting import codingstandards.c.Extensions from CCompilerExtension e where not isExcluded(e, Language3Package::languageExtensionsShouldNotBeUsedQuery()) -select e, "Is a compiler extension and is not portable to other compilers." +select MacroUnwrapper::unwrapElement(e), e.getMessage() diff --git a/c/misra/src/rules/RULE-1-3/OccurrenceOfUndefinedBehavior.ql b/c/misra/src/rules/RULE-1-3/OccurrenceOfUndefinedBehavior.ql index f6b295bd32..00ef875985 100644 --- a/c/misra/src/rules/RULE-1-3/OccurrenceOfUndefinedBehavior.ql +++ b/c/misra/src/rules/RULE-1-3/OccurrenceOfUndefinedBehavior.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-1-3 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ @@ -17,4 +18,4 @@ import codingstandards.c.UndefinedBehavior from CUndefinedBehavior c where not isExcluded(c, Language3Package::occurrenceOfUndefinedBehaviorQuery()) -select c, "May result in undefined behavior." +select c, c.getReason() diff --git a/c/misra/src/rules/RULE-1-4/EmergentLanguageFeaturesUsed.ql b/c/misra/src/rules/RULE-1-4/EmergentLanguageFeaturesUsed.ql index 56ab349a11..a413b1c29a 100644 --- a/c/misra/src/rules/RULE-1-4/EmergentLanguageFeaturesUsed.ql +++ b/c/misra/src/rules/RULE-1-4/EmergentLanguageFeaturesUsed.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-1-4 * maintainability * readability + * external/misra/c/2012/amendment2 * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-1-5/CallToObsolescentFunctionGets.ql b/c/misra/src/rules/RULE-1-5/CallToObsolescentFunctionGets.ql new file mode 100644 index 0000000000..4994c4ea6e --- /dev/null +++ b/c/misra/src/rules/RULE-1-5/CallToObsolescentFunctionGets.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/call-to-obsolescent-function-gets + * @name RULE-1-5: Disallowed usage of obsolescent function 'gets' + * @description The function 'gets' is an obsolescent language feature which was removed in C11. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-1-5 + * external/misra/c/2012/amendment3 + * security + * maintainability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from FunctionCall fc +where + not isExcluded(fc, Language4Package::callToObsolescentFunctionGetsQuery()) and + fc.getTarget().hasGlobalOrStdName("gets") +select fc, "Call to obsolescent function 'gets'." diff --git a/c/misra/src/rules/RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.ql b/c/misra/src/rules/RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.ql new file mode 100644 index 0000000000..645285f438 --- /dev/null +++ b/c/misra/src/rules/RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/function-types-not-in-prototype-form-obsolete + * @name RULE-1-5: Function types shall be in prototype form with named parameters + * @description The use of non-prototype format parameter type declarators is an obsolescent + * language feature. + * @kind problem + * @precision medium + * @problem.severity error + * @tags external/misra/id/rule-1-5 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.functiontypesnotinprototypeformshared.FunctionTypesNotInPrototypeFormShared + +class FunctionTypesNotInPrototypeFormObsoleteQuery extends FunctionTypesNotInPrototypeFormSharedSharedQuery +{ + FunctionTypesNotInPrototypeFormObsoleteQuery() { + this = Language4Package::functionTypesNotInPrototypeFormObsoleteQuery() + } +} diff --git a/c/misra/src/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql b/c/misra/src/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql new file mode 100644 index 0000000000..9d10522ecf --- /dev/null +++ b/c/misra/src/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql @@ -0,0 +1,32 @@ +/** + * @id c/misra/invalid-define-or-undef-of-std-bool-macro + * @name RULE-1-5: Programs may not undefine or redefine the macros bool, true, or false + * @description Directives that undefine and/or redefine the standard boolean macros has been + * declared an obsolescent language feature since C99. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-1-5 + * maintainability + * readability + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +string getABoolMacroName() { result = ["true", "false", "bool"] } + +from PreprocessorDirective directive, string opString, string macroName +where + not isExcluded(directive, Language4Package::invalidDefineOrUndefOfStdBoolMacroQuery()) and + macroName = getABoolMacroName() and + ( + macroName = directive.(Macro).getName() and + opString = "define" + or + macroName = directive.(PreprocessorUndef).getName() and + opString = "undefine" + ) +select directive, "Invalid " + opString + " of boolean standard macro '" + macroName + "'." diff --git a/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierFuncRedeclarationObsolete.ql b/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierFuncRedeclarationObsolete.ql new file mode 100644 index 0000000000..ba800885ef --- /dev/null +++ b/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierFuncRedeclarationObsolete.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/missing-static-specifier-func-redeclaration-obsolete + * @name RULE-1-5: If a function has internal linkage then all re-declarations shall include the static storage class + * @description Declaring a function with internal linkage without the static storage class + * specifier is an obselescent feature. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-1-5 + * readability + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.missingstaticspecifierfunctionredeclarationshared.MissingStaticSpecifierFunctionRedeclarationShared + +class MissingStaticSpecifierFuncRedeclarationObsoleteQuery extends MissingStaticSpecifierFunctionRedeclarationSharedSharedQuery +{ + MissingStaticSpecifierFuncRedeclarationObsoleteQuery() { + this = Language4Package::missingStaticSpecifierFuncRedeclarationObsoleteQuery() + } +} diff --git a/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationObsolete.ql b/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationObsolete.ql new file mode 100644 index 0000000000..9f9953aa6f --- /dev/null +++ b/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationObsolete.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/missing-static-specifier-object-redeclaration-obsolete + * @name RULE-1-5: If an object has internal linkage then all re-declarations shall include the static storage class + * @description Declaring an identifier with internal linkage without the static storage class + * specifier is an obselescent feature. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-1-5 + * readability + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.missingstaticspecifierobjectredeclarationshared.MissingStaticSpecifierObjectRedeclarationShared + +class MissingStaticSpecifierObjectRedeclarationObsoleteQuery extends MissingStaticSpecifierObjectRedeclarationSharedSharedQuery +{ + MissingStaticSpecifierObjectRedeclarationObsoleteQuery() { + this = Language4Package::missingStaticSpecifierObjectRedeclarationObsoleteQuery() + } +} diff --git a/c/misra/src/rules/RULE-1-5/SizeInReallocCallIsZero.ql b/c/misra/src/rules/RULE-1-5/SizeInReallocCallIsZero.ql new file mode 100644 index 0000000000..2b5cdaa851 --- /dev/null +++ b/c/misra/src/rules/RULE-1-5/SizeInReallocCallIsZero.ql @@ -0,0 +1,26 @@ +/** + * @id c/misra/size-in-realloc-call-is-zero + * @name RULE-1-5: Size argument value in realloc call is equal zero + * @description Invoking realloc with a size argument set to zero is implementation-defined behavior + * and declared as an obsolete feature in C18. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-1-5 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import semmle.code.cpp.rangeanalysis.new.RangeAnalysis +import codingstandards.cpp.Realloc + +from ReallocCall call +where + not isExcluded(call, Language4Package::sizeInReallocCallIsZeroQuery()) and + call.sizeIsExactlyZero() +select call, + "Size argument '$@' may equal zero in realloc call, resulting in obsolescent and/or implementation-defined behavior.", + call.getSizeArgument(), call.getSizeArgument().toString() diff --git a/c/misra/src/rules/RULE-1-5/SizeInReallocCallMayBeZero.ql b/c/misra/src/rules/RULE-1-5/SizeInReallocCallMayBeZero.ql new file mode 100644 index 0000000000..3e883e45f4 --- /dev/null +++ b/c/misra/src/rules/RULE-1-5/SizeInReallocCallMayBeZero.ql @@ -0,0 +1,26 @@ +/** + * @id c/misra/size-in-realloc-call-may-be-zero + * @name RULE-1-5: Size argument value in realloc call may equal zero + * @description Invoking realloc with a size argument set to zero is implementation-defined behavior + * and declared as an obsolete feature in C18. + * @kind problem + * @precision medium + * @problem.severity error + * @tags external/misra/id/rule-1-5 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Realloc + +from ReallocCall call +where + not isExcluded(call, Language4Package::sizeInReallocCallMayBeZeroQuery()) and + call.sizeMayBeZero() and + not call.sizeIsExactlyZero() +select call, + "Size argument '$@' equals zero in realloc call, resulting in obsolescent and/or implementation-defined behavior.", + call.getSizeArgument(), call.getSizeArgument().toString() diff --git a/c/misra/src/rules/RULE-1-5/UngetcCallOnStreamPositionZero.ql b/c/misra/src/rules/RULE-1-5/UngetcCallOnStreamPositionZero.ql new file mode 100644 index 0000000000..6a10c94030 --- /dev/null +++ b/c/misra/src/rules/RULE-1-5/UngetcCallOnStreamPositionZero.ql @@ -0,0 +1,81 @@ +/** + * @id c/misra/ungetc-call-on-stream-position-zero + * @name RULE-1-5: Disallowed obsolescent usage of 'ungetc' on a file stream at position zero + * @description Calling the function 'ungetc' on a file stream with a position of zero is an + * obsolescent language feature. + * @kind path-problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-1-5 + * external/misra/c/2012/amendment3 + * security + * maintainability + * external/misra/obligation/required + */ + +import cpp +import semmle.code.cpp.dataflow.new.DataFlow +import semmle.code.cpp.controlflow.Dominance +import codingstandards.c.misra + +/** + * This is an inconclusive list, which is adequate, as RULE-21-3 provides + * assurance we won't have false negatives, or care too much about false + * positives. + */ +class MoveStreamPositionCall extends FunctionCall { + Expr streamArgument; + + MoveStreamPositionCall() { + getTarget().hasGlobalOrStdName("fgetc") and + streamArgument = getArgument(0) + or + getTarget().hasGlobalOrStdName("getc") and + streamArgument = getArgument(0) + or + getTarget().hasGlobalOrStdName("fget") and + streamArgument = getArgument(2) + or + getTarget().hasGlobalOrStdName("fscanf") and + streamArgument = getArgument(0) + or + getTarget().hasGlobalOrStdName("fsetpos") and + streamArgument = getArgument(0) + or + getTarget().hasGlobalOrStdName("fseek") and + streamArgument = getArgument(0) + or + getTarget().hasGlobalOrStdName("fread") and + streamArgument = getArgument(3) + } + + Expr getStreamArgument() { result = streamArgument } +} + +module FilePositionZeroFlowConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { + node.asIndirectExpr().(FunctionCall).getTarget().hasGlobalOrStdName("fopen") + } + + predicate isSink(DataFlow::Node node) { + exists(FunctionCall fc | + fc.getTarget().hasGlobalOrStdName("ungetc") and + node.asIndirectExpr() = fc.getArgument(1) + ) + } + + predicate isBarrierIn(DataFlow::Node node) { + exists(MoveStreamPositionCall fc | node.asIndirectExpr() = fc.getStreamArgument()) + } +} + +module FilePositionZeroFlow = DataFlow::Global; + +import FilePositionZeroFlow::PathGraph + +from FilePositionZeroFlow::PathNode sink, FilePositionZeroFlow::PathNode source +where + not isExcluded(sink.getNode().asExpr(), Language4Package::ungetcCallOnStreamPositionZeroQuery()) and + FilePositionZeroFlow::flowPath(source, sink) +select sink.getNode(), source, sink, + "Obsolescent call to ungetc on file stream $@ at position zero.", source, source.toString() diff --git a/c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql b/c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql new file mode 100644 index 0000000000..e8abf1bbfb --- /dev/null +++ b/c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/use-of-obsolete-macro-atomic-var-init + * @name RULE-1-5: Disallowed usage of obsolete macro ATOMIC_VAR_INIT compiled as C18 + * @description The macro ATOMIC_VAR_INIT is has been declared an obsolescent language feature since + * C18. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-1-5 + * maintainability + * readability + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from MacroInvocation invoke +where + not isExcluded(invoke, Language4Package::useOfObsoleteMacroAtomicVarInitQuery()) and + invoke.getMacroName() = "ATOMIC_VAR_INIT" +select invoke, + "Usage of macro ATOMIC_VAR_INIT() is declared obscelescent in C18, and discouraged in earlier C versions." diff --git a/c/misra/src/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.ql b/c/misra/src/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.ql index 6fdde80119..d06ba09f3d 100644 --- a/c/misra/src/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.ql +++ b/c/misra/src/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.ql @@ -8,13 +8,22 @@ * @problem.severity warning * @tags external/misra/id/rule-10-1 * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra import codingstandards.c.misra.EssentialTypes -import codingstandards.cpp.Bitwise + +predicate hasComparableFloatValue(Expr e) { + exists(float value | + value = e.getValue().toFloat() or + value = -e.(UnaryMinusExpr).getOperand().getValue().toFloat() + | + value in [0.0, "Infinity".toFloat(), -"Infinity".toFloat()] + ) +} /** * Holds if the operator `operator` has an operand `child` that is of an inappropriate essential type @@ -33,8 +42,11 @@ predicate isInappropriateEssentialType( etc = EssentiallyCharacterType() and rationaleId = 4 or - etc = EssentiallyFloatingType() and + etc = EssentiallyFloatingType(Real()) and rationaleId = 1 + or + etc = EssentiallyFloatingType(Complex()) and + rationaleId = 9 ) or child = operator.(UnaryPlusExpr).getOperand() and @@ -64,8 +76,6 @@ predicate isInappropriateEssentialType( rationaleId = 8 ) or - // The table only talks about + and -, but below it clarifies ++ and -- are also considered to - // be equivalent. child = [ operator.(AddExpr).getAnOperand(), operator.(SubExpr).getAnOperand(), @@ -80,6 +90,13 @@ predicate isInappropriateEssentialType( rationaleId = 5 ) or + child = + [operator.(IncrementOperation).getAnOperand(), operator.(DecrementOperation).getAnOperand()] and + ( + etc = EssentiallyFloatingType(Complex()) and + rationaleId = 9 + ) + or child = [ operator.(DivExpr).getAnOperand(), operator.(MulExpr).getAnOperand(), @@ -107,13 +124,26 @@ predicate isInappropriateEssentialType( etc = EssentiallyEnumType() and rationaleId = 5 or - etc = EssentiallyFloatingType() and + etc = EssentiallyFloatingType(Real()) and rationaleId = 1 + or + etc = EssentiallyFloatingType(Complex()) and + rationaleId = 9 ) or child = operator.(RelationalOperation).getAnOperand() and - etc = EssentiallyBooleanType() and - rationaleId = 3 + ( + etc = EssentiallyBooleanType() and + rationaleId = 3 + or + etc = EssentiallyFloatingType(Complex()) and + rationaleId = 9 + ) + or + child = operator.(EqualityOperation).getAnOperand() and + rationaleId = 10 and + not hasComparableFloatValue(operator.(EqualityOperation).getAnOperand()) and + etc = EssentiallyFloatingType(_) or child = [operator.(NotExpr).getAnOperand(), operator.(BinaryLogicalOperation).getAnOperand()] and rationaleId = 2 and @@ -126,7 +156,7 @@ predicate isInappropriateEssentialType( or etc = EssentiallyUnsignedType() or - etc = EssentiallyFloatingType() + etc = EssentiallyFloatingType(_) ) or child = @@ -147,8 +177,11 @@ predicate isInappropriateEssentialType( etc = EssentiallySignedType() and rationaleId = 6 or - etc = EssentiallyFloatingType() and + etc = EssentiallyFloatingType(Real()) and rationaleId = 1 + or + etc = EssentiallyFloatingType(Complex()) and + rationaleId = 9 ) or child = @@ -171,14 +204,17 @@ predicate isInappropriateEssentialType( etc = EssentiallySignedType() and rationaleId = 7 or - etc = EssentiallyFloatingType() and + etc = EssentiallyFloatingType(Real()) and rationaleId = 1 + or + etc = EssentiallyFloatingType(Complex()) and + rationaleId = 9 ) or child = [ operator.(BinaryBitwiseOperation).getAnOperand(), - operator.(Bitwise::AssignBitwiseOperation).getAnOperand() + operator.(AssignBitwiseOperation).getAnOperand(), operator.(ComplementExpr).getAnOperand() ] and not operator instanceof LShiftExpr and not operator instanceof RShiftExpr and @@ -197,8 +233,11 @@ predicate isInappropriateEssentialType( etc = EssentiallySignedType() and rationaleId = 6 or - etc = EssentiallyFloatingType() and + etc = EssentiallyFloatingType(Real()) and rationaleId = 1 + or + etc = EssentiallyFloatingType(Complex()) and + rationaleId = 9 ) or child = operator.(ConditionalExpr).getCondition() and @@ -215,7 +254,7 @@ predicate isInappropriateEssentialType( etc = EssentiallyUnsignedType() and rationaleId = 2 or - etc = EssentiallyFloatingType() and + etc = EssentiallyFloatingType(_) and rationaleId = 2 ) ) @@ -240,15 +279,22 @@ string getRationaleMessage(int rationaleId, EssentialTypeCategory etc) { result = "Bitwise operator applied to operand of " + etc + " and not essentially unsigned." or rationaleId = 7 and - result = "Right hand operatand of shift operator is " + etc + " and not not essentially unsigned." + result = "Right hand operand of shift operator is " + etc + " and not not essentially unsigned." or rationaleId = 8 and result = "Operand of essentially Unsigned type will be converted to a signed type with the signedness dependent on the implemented size of int." + or + rationaleId = 9 and + result = "Use of essentially Complex type in this way is a constraint violation." + or + rationaleId = 10 and + result = + "Floating point numbers have inherent error such that comparisons should consider precision and not exact equality." } from Expr operator, Expr child, int rationaleId, EssentialTypeCategory etc where not isExcluded(operator, EssentialTypesPackage::operandsOfAnInappropriateEssentialTypeQuery()) and isInappropriateEssentialType(operator, child, etc, rationaleId) -select operator, getRationaleMessage(rationaleId, etc) +select child, getRationaleMessage(rationaleId, etc) diff --git a/c/misra/src/rules/RULE-10-1/PointerTypeOnLogicalOperator.ql b/c/misra/src/rules/RULE-10-1/PointerTypeOnLogicalOperator.ql index 21bfdcb2be..b17f3710d5 100644 --- a/c/misra/src/rules/RULE-10-1/PointerTypeOnLogicalOperator.ql +++ b/c/misra/src/rules/RULE-10-1/PointerTypeOnLogicalOperator.ql @@ -8,6 +8,7 @@ * @problem.severity warning * @tags external/misra/id/rule-10-1 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql b/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql index ad0c630e23..0e98c6c570 100644 --- a/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql +++ b/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-10-2 * maintainability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ @@ -31,7 +32,7 @@ where // But the overall essential type is not essentially character type getEssentialTypeCategory(getEssentialType(addOrSub)) = EssentiallyCharacterType() or - // Or this is a subtration of one character with another, which is permitted, but produces an integral type + // Or this is a subtraction of one character with another, which is permitted, but produces an integral type getEssentialTypeCategory(getEssentialType(addOrSub.getLeftOperand())) = EssentiallyCharacterType() and getEssentialTypeCategory(getEssentialType(addOrSub.getRightOperand())) = diff --git a/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql b/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql index 353f6a9c8d..7574531332 100644 --- a/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql +++ b/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-10-3 * maintainability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ @@ -47,5 +48,11 @@ where lValueTypeCategory = EssentiallyUnsignedType() and const >= 0 and const <= 2.pow(lValueEssentialType.getSize() * 8) + ) and + // Exception 4: Real floating point values may be assignable to complex floating point values + not ( + lValueTypeCategory = EssentiallyFloatingType(Complex()) and + rValueTypeCategory = EssentiallyFloatingType(Real()) and + lValueEssentialType.getSize() >= rValueEssentialType.getSize() * 2 ) select rValue, message diff --git a/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql b/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql index d5ef8b6d26..71681ad3bc 100644 --- a/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql +++ b/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-10-4 * maintainability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ @@ -29,6 +30,11 @@ where rightOpTypeCategory = getEssentialTypeCategory(rightOpEssentialType) and ( not leftOpTypeCategory = rightOpTypeCategory and + not ( + // Exception 3: Operands where both are real or complex floating types are allowed. + leftOpTypeCategory = EssentiallyFloatingType(_) and + rightOpTypeCategory = EssentiallyFloatingType(_) + ) and message = "The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: " + leftOpTypeCategory + ", right operand: " + rightOpTypeCategory + ")." @@ -37,7 +43,7 @@ where // be reported as non-compliant. leftOpTypeCategory = EssentiallyEnumType() and rightOpTypeCategory = EssentiallyEnumType() and - not leftOpEssentialType = rightOpEssentialType and + not leftOpEssentialType.getUnspecifiedType() = rightOpEssentialType.getUnspecifiedType() and message = "The operands of this operator with usual arithmetic conversions have mismatched essentially Enum types (left operand: " + leftOpEssentialType + ", right operand: " + rightOpEssentialType + ")." diff --git a/c/misra/src/rules/RULE-10-5/InappropriateEssentialTypeCast.ql b/c/misra/src/rules/RULE-10-5/InappropriateEssentialTypeCast.ql index 1ff8374e97..7cadb104ad 100644 --- a/c/misra/src/rules/RULE-10-5/InappropriateEssentialTypeCast.ql +++ b/c/misra/src/rules/RULE-10-5/InappropriateEssentialTypeCast.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-10-5 * maintainability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ @@ -22,14 +23,14 @@ predicate isIncompatibleEssentialTypeCast(EssentialTypeCategory fromCat, Essenti toCat = [ EssentiallyCharacterType(), EssentiallyEnumType(), EssentiallySignedType(), - EssentiallyUnsignedType(), EssentiallyFloatingType().(TEssentialTypeCategory) + EssentiallyUnsignedType(), EssentiallyFloatingType(_).(TEssentialTypeCategory) ] or fromCat = EssentiallyCharacterType() and toCat = [ EssentiallyBooleanType(), EssentiallyEnumType(), - EssentiallyFloatingType().(TEssentialTypeCategory) + EssentiallyFloatingType(_).(TEssentialTypeCategory) ] or fromCat = EssentiallyEnumType() and @@ -41,7 +42,7 @@ predicate isIncompatibleEssentialTypeCast(EssentialTypeCategory fromCat, Essenti fromCat = EssentiallyUnsignedType() and toCat = [EssentiallyBooleanType(), EssentiallyEnumType().(TEssentialTypeCategory)] or - fromCat = EssentiallyFloatingType() and + fromCat = EssentiallyFloatingType(_) and toCat = [ EssentiallyBooleanType(), EssentiallyCharacterType(), diff --git a/c/misra/src/rules/RULE-10-6/AssignmentToWiderEssentialType.ql b/c/misra/src/rules/RULE-10-6/AssignmentToWiderEssentialType.ql index 09e731ba71..8927e8570a 100644 --- a/c/misra/src/rules/RULE-10-6/AssignmentToWiderEssentialType.ql +++ b/c/misra/src/rules/RULE-10-6/AssignmentToWiderEssentialType.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-10-6 * maintainability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql b/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql index 1cf20378fa..d674f78dc3 100644 --- a/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql +++ b/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql @@ -10,6 +10,7 @@ * @tags external/misra/id/rule-10-7 * maintainability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ @@ -18,6 +19,16 @@ import codingstandards.c.misra import codingstandards.c.misra.EssentialTypes import codingstandards.c.misra.MisraExpressions +bindingset[essentialTypeLeft, essentialTypeRight] +pragma[inline_late] +predicate isSameEssentialTypeCategory(Type essentialTypeLeft, Type essentialTypeRight) { + getEssentialTypeCategory(essentialTypeLeft) = getEssentialTypeCategory(essentialTypeRight) + or + // Complex and real floating types are considered interchangeable + getEssentialTypeCategory(essentialTypeLeft) = EssentiallyFloatingType(_) and + getEssentialTypeCategory(essentialTypeRight) = EssentiallyFloatingType(_) +} + from OperationWithUsualArithmeticConversions arith, CompositeExpression compositeOp, Expr otherOp, Type compositeEssentialType, Type otherOpEssentialType @@ -28,11 +39,11 @@ where not otherOp = compositeOp and compositeEssentialType = getEssentialType(compositeOp) and otherOpEssentialType = getEssentialType(otherOp) and - compositeEssentialType.getSize() < otherOpEssentialType.getSize() and + getEssentialSize(compositeEssentialType) < getEssentialSize(otherOpEssentialType) and // Operands of a different type category in an operation with the usual arithmetic conversions is // prohibited by Rule 10.4, so we only report cases here where the essential type categories are // the same - getEssentialTypeCategory(compositeEssentialType) = getEssentialTypeCategory(otherOpEssentialType) + isSameEssentialTypeCategory(compositeEssentialType, otherOpEssentialType) select arith, "Implicit conversion of $@ from " + compositeEssentialType + " to " + otherOpEssentialType, compositeOp, "composite op" diff --git a/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql b/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql index 8e58ded416..b4d54bf2e8 100644 --- a/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql +++ b/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-10-8 * maintainability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ @@ -29,12 +30,19 @@ where castTypeCategory = getEssentialTypeCategory(castEssentialType) and compositeTypeCategory = getEssentialTypeCategory(compositeExprEssentialType) and ( - not castTypeCategory = compositeTypeCategory and - message = - "Cast from " + compositeTypeCategory + " to " + castTypeCategory + " changes type category." - or - castTypeCategory = compositeTypeCategory and - castEssentialType.getSize() > compositeExprEssentialType.getSize() and - message = "Cast from " + compositeTypeCategory + " to " + castTypeCategory + " widens type." + if + not castTypeCategory = compositeTypeCategory and + not ( + // Exception 2: Casts between real or complex floating types are allowed + castTypeCategory = EssentiallyFloatingType(_) and + compositeTypeCategory = EssentiallyFloatingType(_) + ) + then + message = + "Cast from " + compositeTypeCategory + " to " + castTypeCategory + " changes type category." + else ( + getEssentialSize(castEssentialType) > getEssentialSize(compositeExprEssentialType) and + message = "Cast from " + compositeTypeCategory + " to " + castTypeCategory + " widens type." + ) ) select ce, message diff --git a/c/misra/src/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.ql b/c/misra/src/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.ql index bfac04da6f..7678fc1d23 100644 --- a/c/misra/src/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.ql +++ b/c/misra/src/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.ql @@ -8,12 +8,13 @@ * @problem.severity error * @tags external/misra/id/rule-11-1 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.c.Pointers +import codingstandards.cpp.types.Pointers from CStyleCast cast, Type type, Type newType where diff --git a/c/misra/src/rules/RULE-11-10/AtomicQualifierAppliedToVoid.ql b/c/misra/src/rules/RULE-11-10/AtomicQualifierAppliedToVoid.ql new file mode 100644 index 0000000000..6440e84070 --- /dev/null +++ b/c/misra/src/rules/RULE-11-10/AtomicQualifierAppliedToVoid.ql @@ -0,0 +1,55 @@ +/** + * @id c/misra/atomic-qualifier-applied-to-void + * @name RULE-11-10: The _Atomic qualifier shall not be applied to the incomplete type void + * @description Conversions between types by using an _Atomic void type may result in undefined + * behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-11-10 + * correctness + * external/misra/c/2012/third-edition-first-revision + * external/misra/c/2012/amendment4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +class AtomicVoidType extends Type { + AtomicVoidType() { + hasSpecifier("atomic") and + getUnspecifiedType() instanceof VoidType + } +} + +predicate usesAtomicVoid(Type root) { + root instanceof AtomicVoidType + or + usesAtomicVoid(root.(DerivedType).getBaseType()) + or + usesAtomicVoid(root.(RoutineType).getReturnType()) + or + usesAtomicVoid(root.(RoutineType).getAParameterType()) + or + usesAtomicVoid(root.(FunctionPointerType).getReturnType()) + or + usesAtomicVoid(root.(FunctionPointerType).getAParameterType()) + or + usesAtomicVoid(root.(TypedefType).getBaseType()) +} + +class ExplicitType extends Type { + Element getDeclaration(string description) { + result.(DeclarationEntry).getType() = this and description = result.(DeclarationEntry).getName() + or + result.(CStyleCast).getType() = this and description = "Cast" + } +} + +from Element decl, ExplicitType explicitType, string elementDescription +where + not isExcluded(decl, Declarations9Package::atomicQualifierAppliedToVoidQuery()) and + decl = explicitType.getDeclaration(elementDescription) and + usesAtomicVoid(explicitType) +select decl, elementDescription + " declared with an atomic void type." diff --git a/c/misra/src/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.ql b/c/misra/src/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.ql index 007b43963b..5c16dc1afb 100644 --- a/c/misra/src/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.ql +++ b/c/misra/src/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.ql @@ -8,12 +8,13 @@ * @problem.severity error * @tags external/misra/id/rule-11-2 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.c.Pointers +import codingstandards.cpp.types.Pointers import codingstandards.cpp.Type from Cast cast, Type type, Type newType diff --git a/c/misra/src/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.ql b/c/misra/src/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.ql index ede0a2834e..cf41cfafa5 100644 --- a/c/misra/src/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.ql +++ b/c/misra/src/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.ql @@ -9,12 +9,13 @@ * @problem.severity error * @tags external/misra/id/rule-11-3 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.c.Pointers +import codingstandards.cpp.types.Pointers from CStyleCast cast, Type baseTypeFrom, Type baseTypeTo where @@ -22,7 +23,11 @@ where baseTypeFrom = cast.getExpr().getType().(PointerToObjectType).getBaseType() and baseTypeTo = cast.getType().(PointerToObjectType).getBaseType() and // exception: cast to a char, signed char, or unsigned char is permitted - not baseTypeTo.stripType() instanceof CharType and + not ( + baseTypeTo.stripType() instanceof CharType and + // Exception does not apply to _Atomic types + not baseTypeFrom.hasSpecifier("atomic") + ) and ( ( baseTypeFrom.isVolatile() and not baseTypeTo.isVolatile() diff --git a/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql b/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql index 263545dc1f..336f5d4643 100644 --- a/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql +++ b/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql @@ -8,19 +8,79 @@ * @problem.severity error * @tags external/misra/id/rule-11-4 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ import cpp import codingstandards.c.misra -import codingstandards.c.Pointers +import codingstandards.cpp.Macro +import codingstandards.cpp.types.Pointers -from CStyleCast cast, Type typeFrom, Type typeTo +MacroInvocation getAMacroInvocation(CStyleCast cast) { result.getAnExpandedElement() = cast } + +Macro getPrimaryMacro(CStyleCast cast) { + exists(MacroInvocation mi | + mi = getAMacroInvocation(cast) and + not exists(MacroInvocation otherMi | + otherMi = getAMacroInvocation(cast) and otherMi.getParentInvocation() = mi + ) and + result = mi.getMacro() + ) +} + +Macro getNonFunctionPrimaryMacro(CStyleCast cast) { + result = getPrimaryMacro(cast) and + not result instanceof FunctionLikeMacro +} + +from + Locatable primaryLocation, CStyleCast cast, Type typeFrom, Type typeTo, string message, + string extraMessage, Locatable optionalPlaceholderLocation, string optionalPlaceholderMessage where not isExcluded(cast, Pointers1Package::conversionBetweenPointerToObjectAndIntegerTypeQuery()) and typeFrom = cast.getExpr().getUnderlyingType() and typeTo = cast.getUnderlyingType() and - [typeFrom, typeTo] instanceof IntegralType and - [typeFrom, typeTo] instanceof PointerToObjectType and - not isNullPointerConstant(cast.getExpr()) -select cast, "Cast performed between a pointer to object type and a pointer to an integer type." + ( + typeFrom instanceof PointerToObjectType and + typeTo instanceof IntegralType and + message = + "Cast from pointer to object type '" + typeFrom + "' to integer type '" + typeTo + "'" + + extraMessage + "." + or + typeFrom instanceof IntegralType and + typeTo instanceof PointerToObjectType and + message = + "Cast from integer type '" + typeFrom + "' to pointer to object type '" + typeTo + "'" + + extraMessage + "." + ) and + not isNullPointerConstant(cast.getExpr()) and + // If this alert is arising through a non-function-like macro expansion, flag the macro instead, to + // help make the alerts more manageable. We only do this for non-function-like macros because they + // cannot be context specific. + if exists(getNonFunctionPrimaryMacro(cast)) + then + primaryLocation = getNonFunctionPrimaryMacro(cast) and + extraMessage = "" and + optionalPlaceholderLocation = primaryLocation and + optionalPlaceholderMessage = "" + else ( + primaryLocation = cast and + // If the cast is in a macro expansion which is context specific, we still report the original + // location, but also add a link to the most specific macro that contains the cast, to aid + // validation. + if exists(getPrimaryMacro(cast)) + then + extraMessage = " from expansion of macro $@" and + exists(Macro m | + m = getPrimaryMacro(cast) and + optionalPlaceholderLocation = m and + optionalPlaceholderMessage = m.getName() + ) + else ( + extraMessage = "" and + optionalPlaceholderLocation = cast and + optionalPlaceholderMessage = "" + ) + ) +select primaryLocation, message, optionalPlaceholderLocation, optionalPlaceholderMessage diff --git a/c/misra/src/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.ql b/c/misra/src/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.ql index 3450f1ae90..b316b39a56 100644 --- a/c/misra/src/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.ql +++ b/c/misra/src/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.ql @@ -8,17 +8,18 @@ * @problem.severity error * @tags external/misra/id/rule-11-5 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ import cpp import codingstandards.c.misra -import codingstandards.c.Pointers +import codingstandards.cpp.types.Pointers from Cast cast, VoidPointerType type, PointerToObjectType newType where not isExcluded(cast, Pointers1Package::conversionFromPointerToVoidIntoPointerToObjectQuery()) and - type = cast.getExpr().getUnderlyingType() and + type = cast.getExpr().getUnspecifiedType() and newType = cast.getUnderlyingType() and not isNullPointerConstant(cast.getExpr()) select cast, diff --git a/c/misra/src/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql b/c/misra/src/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql index b36d8dafb1..2293ede61e 100644 --- a/c/misra/src/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql +++ b/c/misra/src/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql @@ -8,12 +8,13 @@ * @problem.severity error * @tags external/misra/id/rule-11-6 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.c.Pointers +import codingstandards.cpp.types.Pointers from CStyleCast cast, Type typeFrom, Type typeTo where @@ -22,5 +23,5 @@ where typeTo = cast.getUnderlyingType() and [typeFrom, typeTo] instanceof ArithmeticType and [typeFrom, typeTo] instanceof VoidPointerType and - not isNullPointerConstant(cast.getExpr()) + not cast.getExpr() instanceof Zero select cast, "Cast performed between a pointer to void type and an arithmetic type." diff --git a/c/misra/src/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.ql b/c/misra/src/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.ql index 30b643963c..82ac620aa7 100644 --- a/c/misra/src/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.ql +++ b/c/misra/src/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.ql @@ -8,12 +8,13 @@ * @problem.severity error * @tags external/misra/id/rule-11-7 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.c.Pointers +import codingstandards.cpp.types.Pointers class MisraNonIntegerArithmeticType extends Type { MisraNonIntegerArithmeticType() { diff --git a/c/misra/src/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.ql b/c/misra/src/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.ql index 17b0df1a0e..c0f447d5b5 100644 --- a/c/misra/src/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.ql +++ b/c/misra/src/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.ql @@ -8,6 +8,7 @@ * @problem.severity error * @tags external/misra/id/rule-11-8 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ @@ -23,5 +24,9 @@ where baseTypeFrom.isVolatile() and not baseTypeTo.isVolatile() and qualificationName = "volatile" or baseTypeFrom.isConst() and not baseTypeTo.isConst() and qualificationName = "const" + or + baseTypeFrom.hasSpecifier("atomic") and + not baseTypeTo.hasSpecifier("atomic") and + qualificationName = "atomic" ) select cast, "Cast of pointer removes " + qualificationName + " qualification from its base type." diff --git a/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql b/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql index 81ea8b1dfd..28b256e85c 100644 --- a/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql +++ b/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql @@ -7,26 +7,37 @@ * @problem.severity error * @tags external/misra/id/rule-11-9 * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.c.Pointers +import codingstandards.cpp.types.Pointers import codingstandards.cpp.Type from Zero zero, Expr e, string type where not isExcluded(zero, Pointers1Package::macroNullNotUsedAsIntegerNullPointerConstantQuery()) and - // exclude the base-case (NULL macros and void pointer casts) - not isNullPointerConstant(zero) and + // Exclude the base-case (NULL macros and void pointer casts) + // Note: we cannot use the isNullPointerConstant predicate here because it permits + // the use of `0` without casting, which is prohibited here. + not ( + zero.findRootCause() instanceof NullMacro + or + // integer constant `0` explicitly cast to void pointer + exists(Conversion c | c = zero.getConversion() | + not c.isImplicit() and + c.getUnderlyingType() instanceof VoidPointerType + ) + ) and ( // ?: operator exists(ConditionalExpr parent | ( - parent.getThen().getAChild*() = zero and parent.getElse().getType() instanceof PointerType + parent.getThen() = zero and parent.getElse().getType() instanceof PointerType or - parent.getElse().getAChild*() = zero and parent.getThen().getType() instanceof PointerType + parent.getElse() = zero and parent.getThen().getType() instanceof PointerType ) and // exclude a common conditional pattern used in macros such as 'assert' not parent.isInMacroExpansion() and diff --git a/c/misra/src/rules/RULE-12-1/ImplicitPrecedenceOfOperatorsInExpression.ql b/c/misra/src/rules/RULE-12-1/ImplicitPrecedenceOfOperatorsInExpression.ql index 005fffa32d..134068463c 100644 --- a/c/misra/src/rules/RULE-12-1/ImplicitPrecedenceOfOperatorsInExpression.ql +++ b/c/misra/src/rules/RULE-12-1/ImplicitPrecedenceOfOperatorsInExpression.ql @@ -9,6 +9,7 @@ * @problem.severity warning * @tags external/misra/id/rule-12-1 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-12-1/UnenclosedSizeofOperand.ql b/c/misra/src/rules/RULE-12-1/UnenclosedSizeofOperand.ql index 8975e7dff7..0081de320c 100644 --- a/c/misra/src/rules/RULE-12-1/UnenclosedSizeofOperand.ql +++ b/c/misra/src/rules/RULE-12-1/UnenclosedSizeofOperand.ql @@ -9,6 +9,7 @@ * @problem.severity warning * @tags external/misra/id/rule-12-1 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-12-2/RightHandOperandOfAShiftRange.ql b/c/misra/src/rules/RULE-12-2/RightHandOperandOfAShiftRange.ql index 891ca1e82a..da7a0f181e 100644 --- a/c/misra/src/rules/RULE-12-2/RightHandOperandOfAShiftRange.ql +++ b/c/misra/src/rules/RULE-12-2/RightHandOperandOfAShiftRange.ql @@ -8,6 +8,7 @@ * @problem.severity error * @tags external/misra/id/rule-12-2 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ @@ -20,14 +21,51 @@ class ShiftExpr extends BinaryBitwiseOperation { ShiftExpr() { this instanceof LShiftExpr or this instanceof RShiftExpr } } -from ShiftExpr e, Expr right, int max_val +MacroInvocation getAMacroInvocation(ShiftExpr se) { result.getAnExpandedElement() = se } + +Macro getPrimaryMacro(ShiftExpr se) { + exists(MacroInvocation mi | + mi = getAMacroInvocation(se) and + not exists(MacroInvocation otherMi | + otherMi = getAMacroInvocation(se) and otherMi.getParentInvocation() = mi + ) and + result = mi.getMacro() + ) +} + +from + ShiftExpr e, Expr right, int max_val, float lowerBound, float upperBound, Type essentialType, + string extraMessage, Locatable optionalPlaceholderLocation, string optionalPlaceholderMessage where not isExcluded(right, Contracts7Package::rightHandOperandOfAShiftRangeQuery()) and right = e.getRightOperand().getFullyConverted() and - max_val = (8 * getEssentialType(e.getLeftOperand()).getSize()) - 1 and + essentialType = getEssentialType(e.getLeftOperand()) and + max_val = (8 * essentialType.getSize()) - 1 and + upperBound = upperBound(right) and + lowerBound = lowerBound(right) and + ( + lowerBound < 0 or + upperBound > max_val + ) and + // If this shift happens inside a macro, then report the macro as well + // for easier validation ( - lowerBound(right) < 0 or - upperBound(right) > max_val + if exists(getPrimaryMacro(e)) + then + extraMessage = " from expansion of macro $@" and + exists(Macro m | + m = getPrimaryMacro(e) and + optionalPlaceholderLocation = m and + optionalPlaceholderMessage = m.getName() + ) + else ( + extraMessage = "" and + optionalPlaceholderLocation = e and + optionalPlaceholderMessage = "" + ) ) select right, - "The right hand operand of the shift operator shall lie in the range 0 to " + max_val + "." + "The possible range of the right operand of the shift operator (" + lowerBound + ".." + upperBound + + ") is outside the the valid shift range (0.." + max_val + + ") for the essential type of the left operand (" + essentialType + ")" + extraMessage + ".", + optionalPlaceholderLocation, optionalPlaceholderMessage diff --git a/c/misra/src/rules/RULE-12-3/CommaOperatorShouldNotBeUsed.ql b/c/misra/src/rules/RULE-12-3/CommaOperatorShouldNotBeUsed.ql index ec782d84f5..bccb382804 100644 --- a/c/misra/src/rules/RULE-12-3/CommaOperatorShouldNotBeUsed.ql +++ b/c/misra/src/rules/RULE-12-3/CommaOperatorShouldNotBeUsed.ql @@ -7,6 +7,7 @@ * @problem.severity recommendation * @tags external/misra/id/rule-12-3 * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-12-4/ConstantUnsignedIntegerExpressionsWrapAround.ql b/c/misra/src/rules/RULE-12-4/ConstantUnsignedIntegerExpressionsWrapAround.ql index 5009ef292d..1ebbf184bb 100644 --- a/c/misra/src/rules/RULE-12-4/ConstantUnsignedIntegerExpressionsWrapAround.ql +++ b/c/misra/src/rules/RULE-12-4/ConstantUnsignedIntegerExpressionsWrapAround.ql @@ -14,6 +14,7 @@ * @tags external/misra/id/rule-12-4 * correctness * security + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-12-5/SizeofOperatorUsedOnArrayTypeParam.ql b/c/misra/src/rules/RULE-12-5/SizeofOperatorUsedOnArrayTypeParam.ql index 3eed267198..2e080419e1 100644 --- a/c/misra/src/rules/RULE-12-5/SizeofOperatorUsedOnArrayTypeParam.ql +++ b/c/misra/src/rules/RULE-12-5/SizeofOperatorUsedOnArrayTypeParam.ql @@ -7,6 +7,7 @@ * @precision very-high * @problem.severity error * @tags external/misra/id/rule-12-5 + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/mandatory */ diff --git a/c/misra/src/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.ql b/c/misra/src/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.ql new file mode 100644 index 0000000000..5085e5dc7b --- /dev/null +++ b/c/misra/src/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.ql @@ -0,0 +1,40 @@ +/** + * @id c/misra/atomic-aggregate-object-directly-accessed + * @name RULE-12-6: Structure and union members of atomic objects shall not be directly accessed + * @description Accessing a member of an atomic structure or union results in undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-12-6 + * external/misra/c/2012/amendment4 + * correctness + * concurrency + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from Expr expr, Field field +where + not isExcluded(expr, Concurrency6Package::atomicAggregateObjectDirectlyAccessedQuery()) and + not expr.isUnevaluated() and + ( + exists(FieldAccess fa | + expr = fa and + fa.getQualifier().getType().hasSpecifier("atomic") and + field = fa.getTarget() + ) + or + exists(PointerFieldAccess fa | + expr = fa and + fa.getQualifier() + .getType() + .stripTopLevelSpecifiers() + .(PointerType) + .getBaseType() + .hasSpecifier("atomic") and + field = fa.getTarget() + ) + ) +select expr, "Invalid access to member '$@' on atomic struct or union.", field, field.getName() diff --git a/c/misra/src/rules/RULE-13-1/InitializerListsContainPersistentSideEffects.ql b/c/misra/src/rules/RULE-13-1/InitializerListsContainPersistentSideEffects.ql index 3cce2bb825..69ecbede58 100644 --- a/c/misra/src/rules/RULE-13-1/InitializerListsContainPersistentSideEffects.ql +++ b/c/misra/src/rules/RULE-13-1/InitializerListsContainPersistentSideEffects.ql @@ -8,6 +8,7 @@ * @problem.severity error * @tags external/misra/id/rule-13-1 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql b/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql new file mode 100644 index 0000000000..86756668a8 --- /dev/null +++ b/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql @@ -0,0 +1,117 @@ +/** + * @id c/misra/unsequenced-atomic-reads + * @name RULE-13-2: The value of an atomic variable shall not depend on the evaluation order of interleaved threads + * @description The value of an atomic variable shall not depend on evaluation order and + * interleaving of threads. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-13-2 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import semmle.code.cpp.dataflow.TaintTracking +import codingstandards.c.misra +import codingstandards.c.Ordering +import codingstandards.c.orderofevaluation.VariableAccessOrdering +import codingstandards.cpp.StdFunctionOrMacro + +class AtomicAccessInFullExpressionOrdering extends Ordering::Configuration { + AtomicAccessInFullExpressionOrdering() { this = "AtomicAccessInFullExpressionOrdering" } + + override predicate isCandidate(Expr e1, Expr e2) { + exists(AtomicVariableAccess a, AtomicVariableAccess b, FullExpr e | a = e1 and b = e2 | + a.getTarget() = b.getTarget() and + a.getARead().(ConstituentExpr).getFullExpr() = e and + b.getARead().(ConstituentExpr).getFullExpr() = e and + not a = b + ) + } +} + +/** + * A read of a variable specified as `_Atomic`. + * + * Note, it may be accessed directly, or by passing its address into the std atomic functions. + */ +class AtomicVariableAccess extends VariableAccess { + AtomicVariableAccess() { getTarget().getType().hasSpecifier("atomic") } + + /* Get the `atomic_load()` call this VarAccess occurs in. */ + Expr getAtomicFunctionRead() { + exists(AddressOfExpr addrParent, AtomicReadOrWriteCall fc | + fc.getName().matches("atomic_load%") and + // StdFunctionOrMacro arguments are not necessarily reliable, so we look for any AddressOfExpr + // that is an argument to a call to `atomic_load`. + addrParent = fc.getArgument(0) and + addrParent.getAnOperand() = this and + result = fc.getExpr() + ) + } + + /* Get the `atomic_store()` call this VarAccess occurs in. */ + Expr getAtomicFunctionWrite(Expr storedValue) { + exists(AddressOfExpr addrParent, AtomicReadOrWriteCall fc | + addrParent = fc.getArgument(0) and + addrParent.getAnOperand() = this and + result = fc.getExpr() and + ( + fc.getName().matches(["%store%", "%exchange%", "%fetch_%"]) and + not fc.getName().matches("%compare%") and + storedValue = fc.getArgument(1) + or + fc.getName().matches(["%compare%"]) and + storedValue = fc.getArgument(2) + ) + ) + } + + /** + * Gets an assigned expr, either in the form `x = ` or `atomic_store(&x, )`. + */ + Expr getAnAssignedExpr() { + exists(getAtomicFunctionWrite(result)) + or + exists(AssignExpr assign | + assign.getLValue() = this and + result = assign.getRValue() + ) + } + + /** + * Gets the expression holding this variable access, either in the form `x` or `atomic_read(&x)`. + */ + Expr getARead() { + result = getAtomicFunctionRead() + or + result = this + } +} + +from + AtomicAccessInFullExpressionOrdering config, FullExpr e, Variable v, AtomicVariableAccess va1, + AtomicVariableAccess va2, Expr va1Read, Expr va2Read +where + not isExcluded(e, SideEffects3Package::unsequencedAtomicReadsQuery()) and + va1Read = va1.getARead() and + va2Read = va2.getARead() and + e = va1Read.(ConstituentExpr).getFullExpr() and + // Careful here. The `VariableAccess` in a pair of atomic function calls may not be unsequenced, + // for instance in gcc where atomic functions expand to StmtExprs, which have clear sequences. + // In this case, the result of `getARead()` for a pair of atomic function calls may be + // unsequenced even though the `VariableAccess`es within those calls are not. + config.isUnsequenced(va1Read, va2Read) and + v = va1.getTarget() and + v = va2.getTarget() and + // Exclude cases where the variable is assigned a value tainted by the other variable access. + not exists(Expr write | + write = va1.getAnAssignedExpr() and + TaintTracking::localTaint(DataFlow::exprNode(va2.getARead()), DataFlow::exprNode(write)) + ) and + // Impose an ordering, show the first access. + va1.getLocation().isBefore(va2.getLocation(), _) +select e, "Atomic variable $@ has a $@ that is unsequenced with $@.", v, v.getName(), va1, + "previous read", va2, "another read" diff --git a/c/misra/src/rules/RULE-13-2/UnsequencedSideEffects.ql b/c/misra/src/rules/RULE-13-2/UnsequencedSideEffects.ql index c1ac4d4b40..90b0315e88 100644 --- a/c/misra/src/rules/RULE-13-2/UnsequencedSideEffects.ql +++ b/c/misra/src/rules/RULE-13-2/UnsequencedSideEffects.ql @@ -8,14 +8,14 @@ * @problem.severity error * @tags external/misra/id/rule-13-2 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.c.Expr -import codingstandards.c.SideEffects import codingstandards.c.Ordering +import codingstandards.c.SideEffects class VariableEffectOrAccess extends Expr { VariableEffectOrAccess() { diff --git a/c/misra/src/rules/RULE-13-3/SideEffectAndCrementInFullExpression.ql b/c/misra/src/rules/RULE-13-3/SideEffectAndCrementInFullExpression.ql index 3dd03120c8..173827e04e 100644 --- a/c/misra/src/rules/RULE-13-3/SideEffectAndCrementInFullExpression.ql +++ b/c/misra/src/rules/RULE-13-3/SideEffectAndCrementInFullExpression.ql @@ -10,6 +10,7 @@ * @tags external/misra/id/rule-13-3 * readability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql b/c/misra/src/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql index 6938f8e627..c840947b1f 100644 --- a/c/misra/src/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql +++ b/c/misra/src/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql @@ -9,14 +9,17 @@ * @tags external/misra/id/rule-13-4 * correctness * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ import cpp import codingstandards.c.misra +import codingstandards.cpp.rules.resultofanassignmentoperatorshouldnotbeused.ResultOfAnAssignmentOperatorShouldNotBeUsed -from AssignExpr e -where - not isExcluded(e, SideEffects1Package::resultOfAnAssignmentOperatorShouldNotBeUsedQuery()) and - not exists(ExprStmt s | s.getExpr() = e) -select e, "Use of an assignment operator's result." +class ResultOfAnAssignmentOperatorShouldNotBeUsedQuery extends ResultOfAnAssignmentOperatorShouldNotBeUsedSharedQuery +{ + ResultOfAnAssignmentOperatorShouldNotBeUsedQuery() { + this = SideEffects1Package::resultOfAnAssignmentOperatorShouldNotBeUsedQuery() + } +} diff --git a/c/misra/src/rules/RULE-13-5/PossibleSuppressedSideEffectInLogicOperatorOperand.ql b/c/misra/src/rules/RULE-13-5/PossibleSuppressedSideEffectInLogicOperatorOperand.ql index 90faf9ec23..9a5b7b2b7b 100644 --- a/c/misra/src/rules/RULE-13-5/PossibleSuppressedSideEffectInLogicOperatorOperand.ql +++ b/c/misra/src/rules/RULE-13-5/PossibleSuppressedSideEffectInLogicOperatorOperand.ql @@ -9,6 +9,7 @@ * @problem.severity error * @tags external/misra/id/rule-13-5 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-13-6/SizeofOperandWithSideEffect.ql b/c/misra/src/rules/RULE-13-6/SizeofOperandWithSideEffect.ql index 10317b1169..759ad9b06a 100644 --- a/c/misra/src/rules/RULE-13-6/SizeofOperandWithSideEffect.ql +++ b/c/misra/src/rules/RULE-13-6/SizeofOperandWithSideEffect.ql @@ -8,7 +8,8 @@ * @problem.severity error * @tags external/misra/id/rule-13-6 * correctness - * external/misra/obligation/mandatory + * external/misra/c/2012/third-edition-first-revision + * external/misra/obligation/required */ import cpp diff --git a/c/misra/src/rules/RULE-14-1/LoopOverEssentiallyFloatType.ql b/c/misra/src/rules/RULE-14-1/LoopOverEssentiallyFloatType.ql index 6a0f772f61..3d351c898e 100644 --- a/c/misra/src/rules/RULE-14-1/LoopOverEssentiallyFloatType.ql +++ b/c/misra/src/rules/RULE-14-1/LoopOverEssentiallyFloatType.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-14-1 * maintainability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ @@ -20,6 +21,6 @@ from ForStmt forLoop, Variable loopIterationVariable where not isExcluded(loopIterationVariable, EssentialTypesPackage::loopOverEssentiallyFloatTypeQuery()) and getAnIterationVariable(forLoop) = loopIterationVariable and - getEssentialTypeCategory(loopIterationVariable.getType()) = EssentiallyFloatingType() + getEssentialTypeCategory(loopIterationVariable.getType()) = EssentiallyFloatingType(_) select loopIterationVariable, "Loop iteration variable " + loopIterationVariable.getName() + " is essentially Floating type." diff --git a/c/misra/src/rules/RULE-14-2/ForLoopNotWellFormed.ql b/c/misra/src/rules/RULE-14-2/ForLoopNotWellFormed.ql index 106bd9b5c6..7b3dc3c8dc 100644 --- a/c/misra/src/rules/RULE-14-2/ForLoopNotWellFormed.ql +++ b/c/misra/src/rules/RULE-14-2/ForLoopNotWellFormed.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-14-2 * readability * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql index eb8e9ede82..1bd2708750 100644 --- a/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql +++ b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql @@ -10,6 +10,7 @@ * correctness * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-14-4/NonBooleanIfCondition.ql b/c/misra/src/rules/RULE-14-4/NonBooleanIfCondition.ql index 87d9d31512..f9a24d9492 100644 --- a/c/misra/src/rules/RULE-14-4/NonBooleanIfCondition.ql +++ b/c/misra/src/rules/RULE-14-4/NonBooleanIfCondition.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-14-4 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-14-4/NonBooleanIterationCondition.ql b/c/misra/src/rules/RULE-14-4/NonBooleanIterationCondition.ql index b2644a7a92..8418993db2 100644 --- a/c/misra/src/rules/RULE-14-4/NonBooleanIterationCondition.ql +++ b/c/misra/src/rules/RULE-14-4/NonBooleanIterationCondition.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-14-4 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-15-1/GotoStatementUsed.ql b/c/misra/src/rules/RULE-15-1/GotoStatementUsed.ql index ddc85c305c..84c7dbd408 100644 --- a/c/misra/src/rules/RULE-15-1/GotoStatementUsed.ql +++ b/c/misra/src/rules/RULE-15-1/GotoStatementUsed.ql @@ -8,14 +8,14 @@ * @tags external/misra/id/rule-15-1 * correctness * security + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ import cpp import codingstandards.c.misra +import codingstandards.cpp.rules.gotostatementshouldnotbeused.GotoStatementShouldNotBeUsed -from Stmt s -where - not isExcluded(s, Statements6Package::gotoStatementUsedQuery()) and - (s instanceof GotoStmt or s instanceof ComputedGotoStmt) -select s, "Use of goto." +class GotoStatementUsedQuery extends GotoStatementShouldNotBeUsedSharedQuery { + GotoStatementUsedQuery() { this = Statements6Package::gotoStatementUsedQuery() } +} diff --git a/c/misra/src/rules/RULE-15-2/GotoLabelLocationCondition.ql b/c/misra/src/rules/RULE-15-2/GotoLabelLocationCondition.ql index d12521dd7e..623fb9baed 100644 --- a/c/misra/src/rules/RULE-15-2/GotoLabelLocationCondition.ql +++ b/c/misra/src/rules/RULE-15-2/GotoLabelLocationCondition.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-15-2 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql b/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql index aeb356b501..a88f3170de 100644 --- a/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql +++ b/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql @@ -9,54 +9,14 @@ * @tags external/misra/id/rule-15-3 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra +import codingstandards.cpp.rules.gotoreferencealabelinsurroundingblock.GotoReferenceALabelInSurroundingBlock -predicate isPartOfSwitch(Stmt goto) { - exists(SwitchStmt switch | switch.getStmt() = goto.getParent()) +class GotoLabelBlockConditionQuery extends GotoReferenceALabelInSurroundingBlockSharedQuery { + GotoLabelBlockConditionQuery() { this = Statements2Package::gotoLabelBlockConditionQuery() } } - -SwitchCase getSwitchCase(Stmt stmt) { - exists(int index, SwitchStmt switch | - getStmtInSwitch(switch, stmt, index) and getStmtInSwitch(switch, result, index - 1) - ) - or - exists(int index, SwitchStmt switch, Stmt other | - getStmtInSwitch(switch, stmt, index) and - getStmtInSwitch(switch, other, index - 1) and - not other instanceof SwitchCase and - result = getSwitchCase(other) - ) -} - -predicate getStmtInSwitch(SwitchStmt switch, Stmt s, int index) { - switch.getStmt().(BlockStmt).getStmt(index) = s -} - -int statementDepth(Stmt statement) { - statement.getParent() = statement.getEnclosingFunction().getBlock() and result = 1 - or - statementDepth(statement.getParent()) + 1 = result -} - -from GotoStmt goto, Stmt target, int gotoDepth, int targetDepth -where - not isExcluded(goto, Statements2Package::gotoLabelBlockConditionQuery()) and - goto.getTarget() = target and - gotoDepth = statementDepth(goto) and - targetDepth = statementDepth(target) and - targetDepth >= gotoDepth and - ( - targetDepth = gotoDepth - implies - ( - not isPartOfSwitch(goto) and not goto.getParent() = target.getParent() - or - isPartOfSwitch(goto) and not getSwitchCase(goto) = getSwitchCase(target) - ) - ) -select goto, "The $@ statement and its $@ are not declared or enclosed in the same block.", goto, - "goto", target, "label" diff --git a/c/misra/src/rules/RULE-15-4/LoopIterationCondition.ql b/c/misra/src/rules/RULE-15-4/LoopIterationCondition.ql index ed541a68d0..b172a2c1ea 100644 --- a/c/misra/src/rules/RULE-15-4/LoopIterationCondition.ql +++ b/c/misra/src/rules/RULE-15-4/LoopIterationCondition.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-15-4 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-15-5/FunctionReturnCondition.ql b/c/misra/src/rules/RULE-15-5/FunctionReturnCondition.ql index 2fb5ad9d65..8e777d7332 100644 --- a/c/misra/src/rules/RULE-15-5/FunctionReturnCondition.ql +++ b/c/misra/src/rules/RULE-15-5/FunctionReturnCondition.ql @@ -9,6 +9,7 @@ * maintainability * readability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-15-6/LoopCompoundCondition.ql b/c/misra/src/rules/RULE-15-6/LoopCompoundCondition.ql index c596cb2970..9cc5bf9dda 100644 --- a/c/misra/src/rules/RULE-15-6/LoopCompoundCondition.ql +++ b/c/misra/src/rules/RULE-15-6/LoopCompoundCondition.ql @@ -1,6 +1,6 @@ /** * @id c/misra/loop-compound-condition - * @name RULE-15-6: the statement forming the body of a loop shall be a compound statement + * @name RULE-15-6: The statement forming the body of a loop shall be a compound statement * @description if the body of a loop is not enclosed in braces, then this can lead to incorrect * execution, and is hard for developers to maintain. * @kind problem @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-15-6 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-15-6/SelectionCompoundCondition.ql b/c/misra/src/rules/RULE-15-6/SelectionCompoundCondition.ql index 0c97b3ea5a..f84c142414 100644 --- a/c/misra/src/rules/RULE-15-6/SelectionCompoundCondition.ql +++ b/c/misra/src/rules/RULE-15-6/SelectionCompoundCondition.ql @@ -1,6 +1,6 @@ /** * @id c/misra/selection-compound-condition - * @name RULE-15-6: the statement forming the body of a loop shall be a compound statement + * @name RULE-15-6: The statement forming the body of a slection statement shall be a compound statement * @description if the body of a selection statement is not enclosed in braces, then this can lead * to incorrect execution, and is hard for developers to maintain. * @kind problem @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-15-6 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-15-6/SwitchCompoundCondition.ql b/c/misra/src/rules/RULE-15-6/SwitchCompoundCondition.ql index 837bfb12c1..1d446f323f 100644 --- a/c/misra/src/rules/RULE-15-6/SwitchCompoundCondition.ql +++ b/c/misra/src/rules/RULE-15-6/SwitchCompoundCondition.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-15-6 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-15-7/IfElseEndCondition.ql b/c/misra/src/rules/RULE-15-7/IfElseEndCondition.ql index f3992d26f5..ee06f484fe 100644 --- a/c/misra/src/rules/RULE-15-7/IfElseEndCondition.ql +++ b/c/misra/src/rules/RULE-15-7/IfElseEndCondition.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-15-7 * readability * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-16-1/SwitchCaseStartCondition.ql b/c/misra/src/rules/RULE-16-1/SwitchCaseStartCondition.ql index e30ac1bd7b..4ceca23d8f 100644 --- a/c/misra/src/rules/RULE-16-1/SwitchCaseStartCondition.ql +++ b/c/misra/src/rules/RULE-16-1/SwitchCaseStartCondition.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-16-1 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-16-1/SwitchStmtNotWellFormed.ql b/c/misra/src/rules/RULE-16-1/SwitchStmtNotWellFormed.ql index 9da9242a78..644994562a 100644 --- a/c/misra/src/rules/RULE-16-1/SwitchStmtNotWellFormed.ql +++ b/c/misra/src/rules/RULE-16-1/SwitchStmtNotWellFormed.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-16-1 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.ql b/c/misra/src/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.ql index df4b6fc93a..45ad0519bb 100644 --- a/c/misra/src/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.ql +++ b/c/misra/src/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-16-2 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-16-3/BreakShallTerminateSwitchClause.ql b/c/misra/src/rules/RULE-16-3/BreakShallTerminateSwitchClause.ql index e62fe8c8d4..5ff30b53e0 100644 --- a/c/misra/src/rules/RULE-16-3/BreakShallTerminateSwitchClause.ql +++ b/c/misra/src/rules/RULE-16-3/BreakShallTerminateSwitchClause.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-16-3 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql b/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql index a5d7c3cf2c..441e30b7e7 100644 --- a/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql +++ b/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql @@ -10,6 +10,7 @@ * @tags external/misra/id/rule-16-4 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql b/c/misra/src/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql index f86e242ee3..5a93477b9a 100644 --- a/c/misra/src/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql +++ b/c/misra/src/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql @@ -6,6 +6,7 @@ * @precision very-high * @problem.severity recommendation * @tags external/misra/id/rule-16-5 + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-16-6/SwitchClauseNumberCondition.ql b/c/misra/src/rules/RULE-16-6/SwitchClauseNumberCondition.ql index 8ddb2e49b2..0259f8023d 100644 --- a/c/misra/src/rules/RULE-16-6/SwitchClauseNumberCondition.ql +++ b/c/misra/src/rules/RULE-16-6/SwitchClauseNumberCondition.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-16-6 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql b/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql index 9aeb50d26e..06be288e2c 100644 --- a/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql +++ b/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-16-7 * readability * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-17-1/FeaturesOfStdarghUsed.ql b/c/misra/src/rules/RULE-17-1/FeaturesOfStdarghUsed.ql index 1cde8b98f2..ddccb58ad1 100644 --- a/c/misra/src/rules/RULE-17-1/FeaturesOfStdarghUsed.ql +++ b/c/misra/src/rules/RULE-17-1/FeaturesOfStdarghUsed.ql @@ -7,6 +7,7 @@ * @problem.severity error * @tags external/misra/id/rule-17-1 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql b/c/misra/src/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql new file mode 100644 index 0000000000..1e32793c3f --- /dev/null +++ b/c/misra/src/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql @@ -0,0 +1,27 @@ +/** + * @id c/misra/non-void-return-type-of-noreturn-function + * @name RULE-17-10: A function declared with _noreturn shall have a return type of void + * @description Function declared with _noreturn will by definition not return a value, and should + * be declared to return void. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-17-10 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Noreturn + +from NoreturnFunction f, Type returnType +where + not isExcluded(f, NoReturnPackage::nonVoidReturnTypeOfNoreturnFunctionQuery()) and + returnType = f.getType() and + not returnType instanceof VoidType and + not f.isCompilerGenerated() +select f, + "The function " + f.getName() + " is declared _noreturn but has a return type of " + + returnType.toString() + "." diff --git a/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql b/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql new file mode 100644 index 0000000000..4dd939effe --- /dev/null +++ b/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql @@ -0,0 +1,29 @@ +/** + * @id c/misra/function-with-no-returning-branch-should-be-noreturn + * @name RULE-17-11: A function without a branch that returns shall be declared with _Noreturn + * @description Functions which cannot return should be declared with _Noreturn. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-17-11 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Noreturn + +from Function f +where + not isExcluded(f, NoReturnPackage::functionWithNoReturningBranchShouldBeNoreturnQuery()) and + not f instanceof NoreturnFunction and + not mayReturn(f) and + f.hasDefinition() and + not f.getName() = "main" and // Allowed exception; _Noreturn main() is undefined behavior. + // Harden against c++ cases. + not f.isFromUninstantiatedTemplate(_) and + not f.isDeleted() and + not f.isCompilerGenerated() +select f, "The function " + f.getName() + " cannot return and should be declared as _Noreturn." diff --git a/c/misra/src/rules/RULE-17-12/FunctionAddressesShouldAddressOperator.ql b/c/misra/src/rules/RULE-17-12/FunctionAddressesShouldAddressOperator.ql new file mode 100644 index 0000000000..c95612b7ba --- /dev/null +++ b/c/misra/src/rules/RULE-17-12/FunctionAddressesShouldAddressOperator.ql @@ -0,0 +1,33 @@ +/** + * @id c/misra/function-addresses-should-address-operator + * @name RULE-17-12: A function identifier should only be called with a parenthesized parameter list or used with a & + * @description A function identifier should only be called with a parenthesized parameter list or + * used with a & (address-of). + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-17-12 + * readability + * external/misra/c/2012/amendment3 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra + +predicate isImplicitlyAddressed(FunctionAccess access) { + not access.getParent() instanceof AddressOfExpr and + // Note: the following *seems* to only exist in c++ codebases, for instance, + // when calling a member. In c, this syntax should always extract as a + // [FunctionCall] rather than a [ExprCall] of a [FunctionAccess]. Still, this + // is a good pattern to be defensive against. + not exists(ExprCall call | call.getExpr() = access) +} + +from FunctionAccess funcAccess +where + not isExcluded(funcAccess, FunctionTypesPackage::functionAddressesShouldAddressOperatorQuery()) and + isImplicitlyAddressed(funcAccess) +select funcAccess, + "The address of function " + funcAccess.getTarget().getName() + + " is taken without the & operator." diff --git a/c/misra/src/rules/RULE-17-2/RecursiveFunctionCondition.ql b/c/misra/src/rules/RULE-17-2/RecursiveFunctionCondition.ql index b6f13c4d1f..c7cb818119 100644 --- a/c/misra/src/rules/RULE-17-2/RecursiveFunctionCondition.ql +++ b/c/misra/src/rules/RULE-17-2/RecursiveFunctionCondition.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-17-2 * maintainability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-17-3/FunctionDeclaredImplicitly.ql b/c/misra/src/rules/RULE-17-3/FunctionDeclaredImplicitly.ql index 304d0a9bf6..af6c9bccad 100644 --- a/c/misra/src/rules/RULE-17-3/FunctionDeclaredImplicitly.ql +++ b/c/misra/src/rules/RULE-17-3/FunctionDeclaredImplicitly.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-17-3 * correctness * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/mandatory */ diff --git a/c/misra/src/rules/RULE-17-4/NonVoidFunctionReturnCondition.ql b/c/misra/src/rules/RULE-17-4/NonVoidFunctionReturnCondition.ql index 24329e5ab5..1529a403c9 100644 --- a/c/misra/src/rules/RULE-17-4/NonVoidFunctionReturnCondition.ql +++ b/c/misra/src/rules/RULE-17-4/NonVoidFunctionReturnCondition.ql @@ -10,6 +10,7 @@ * correctness * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/mandatory */ diff --git a/c/misra/src/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.ql b/c/misra/src/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.ql index 208e8153d6..1a142ddb22 100644 --- a/c/misra/src/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.ql +++ b/c/misra/src/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.ql @@ -8,12 +8,13 @@ * @problem.severity error * @tags external/misra/id/rule-17-5 * correctness - * external/misra/obligation/advisory + * external/misra/c/2012/third-edition-first-revision + * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /** * Models a function parameter of type array with specified size diff --git a/c/misra/src/rules/RULE-17-6/UseOfArrayStatic.ql b/c/misra/src/rules/RULE-17-6/UseOfArrayStatic.ql index 876321c455..0a1232b6ad 100644 --- a/c/misra/src/rules/RULE-17-6/UseOfArrayStatic.ql +++ b/c/misra/src/rules/RULE-17-6/UseOfArrayStatic.ql @@ -8,6 +8,7 @@ * @problem.severity error * @tags external/misra/id/rule-17-6 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/mandatory */ diff --git a/c/misra/src/rules/RULE-17-7/ValueReturnedByAFunctionNotUsed.ql b/c/misra/src/rules/RULE-17-7/ValueReturnedByAFunctionNotUsed.ql index 02d0a54ec1..934aeb79d3 100644 --- a/c/misra/src/rules/RULE-17-7/ValueReturnedByAFunctionNotUsed.ql +++ b/c/misra/src/rules/RULE-17-7/ValueReturnedByAFunctionNotUsed.ql @@ -8,12 +8,12 @@ * @problem.severity error * @tags external/misra/id/rule-17-7 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.cpp.dataflow.DataFlow from Call c where diff --git a/c/misra/src/rules/RULE-17-8/ModificationOfFunctionParameter.ql b/c/misra/src/rules/RULE-17-8/ModificationOfFunctionParameter.ql index 6867455a45..95cddb57d3 100644 --- a/c/misra/src/rules/RULE-17-8/ModificationOfFunctionParameter.ql +++ b/c/misra/src/rules/RULE-17-8/ModificationOfFunctionParameter.ql @@ -9,6 +9,7 @@ * @problem.severity warning * @tags external/misra/id/rule-17-8 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql b/c/misra/src/rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql new file mode 100644 index 0000000000..dedac9da9e --- /dev/null +++ b/c/misra/src/rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/return-statement-in-noreturn-function + * @name RULE-17-9: Verify that a function declared with _Noreturn does not return + * @description Returning inside a function declared with _Noreturn is undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-17-9 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.functionnoreturnattributecondition.FunctionNoReturnAttributeCondition + +class ReturnStatementInNoreturnFunctionQuery extends FunctionNoReturnAttributeConditionSharedQuery { + ReturnStatementInNoreturnFunctionQuery() { + this = NoReturnPackage::returnStatementInNoreturnFunctionQuery() + } +} diff --git a/c/misra/src/rules/RULE-18-1/PointerAndDerivedPointerMustAddressSameArray.ql b/c/misra/src/rules/RULE-18-1/PointerAndDerivedPointerMustAddressSameArray.ql index f17d596ead..c8944bd30d 100644 --- a/c/misra/src/rules/RULE-18-1/PointerAndDerivedPointerMustAddressSameArray.ql +++ b/c/misra/src/rules/RULE-18-1/PointerAndDerivedPointerMustAddressSameArray.ql @@ -8,6 +8,7 @@ * @problem.severity error * @tags external/misra/id/rule-18-1 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql b/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql new file mode 100644 index 0000000000..dc1433d5e4 --- /dev/null +++ b/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql @@ -0,0 +1,51 @@ +/** + * @id c/misra/pointers-to-variably-modified-array-types-used + * @name RULE-18-10: Pointers to variably-modified array types shall not be used + * @description Pointers to variably-modified array types shall not be used, as these pointer types + * are frequently incompatible with other fixed or variably sized arrays, resulting in + * undefined behavior. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-18-10 + * external/misra/c/2012/amendment4 + * correctness + * security + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.types.VariablyModifiedTypes + +from VmtDeclarationEntry v, string declstr, string adjuststr, string relationstr +where + not isExcluded(v, InvalidMemory3Package::pointersToVariablyModifiedArrayTypesUsedQuery()) and + // Capture only pointers to VLA types, not raw VLA types. + not v.getVlaType() = v.getType() and + ( + if v instanceof ParameterDeclarationEntry + then declstr = "Parameter " + else + if v instanceof VariableDeclarationEntry + then declstr = "Variable " + else declstr = "Declaration " + ) and + ( + if + v instanceof ParameterDeclarationEntry and + v.getType() instanceof ParameterAdjustedVariablyModifiedType + then adjuststr = "adjusted to" + else adjuststr = "declared with" + ) and + ( + if v.getType().(PointerType).getBaseType() instanceof CandidateVlaType + then relationstr = "pointer to" + else relationstr = "with inner" + ) and + // Remove results that appear to be unreliable, potentially from a macro. + not v.appearsDuplicated() +select v, + declstr + v.getName() + " is " + adjuststr + " variably-modified type, " + relationstr + + " variable length array of non constant size $@ and element type '" + + v.getVlaType().getVariableBaseType() + "'", v.getSizeExpr(), v.getSizeExpr().toString() diff --git a/c/misra/src/rules/RULE-18-2/SubtractionBetweenPointersMustAddressSameArray.ql b/c/misra/src/rules/RULE-18-2/SubtractionBetweenPointersMustAddressSameArray.ql index b6fbb31f1c..ec3a30d5ba 100644 --- a/c/misra/src/rules/RULE-18-2/SubtractionBetweenPointersMustAddressSameArray.ql +++ b/c/misra/src/rules/RULE-18-2/SubtractionBetweenPointersMustAddressSameArray.ql @@ -8,6 +8,7 @@ * @problem.severity error * @tags external/misra/id/rule-18-2 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-18-3/RelationalOperatorComparesPointerToDifferentArray.ql b/c/misra/src/rules/RULE-18-3/RelationalOperatorComparesPointerToDifferentArray.ql index d7785a2d0e..4624cea616 100644 --- a/c/misra/src/rules/RULE-18-3/RelationalOperatorComparesPointerToDifferentArray.ql +++ b/c/misra/src/rules/RULE-18-3/RelationalOperatorComparesPointerToDifferentArray.ql @@ -8,6 +8,7 @@ * @problem.severity error * @tags external/misra/id/rule-18-3 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-18-4/DoNotUseAdditionOrSubtractionOperatorsOnPointers.ql b/c/misra/src/rules/RULE-18-4/DoNotUseAdditionOrSubtractionOperatorsOnPointers.ql index a5f8a85ff1..a1a1ad367b 100644 --- a/c/misra/src/rules/RULE-18-4/DoNotUseAdditionOrSubtractionOperatorsOnPointers.ql +++ b/c/misra/src/rules/RULE-18-4/DoNotUseAdditionOrSubtractionOperatorsOnPointers.ql @@ -8,6 +8,7 @@ * @problem.severity error * @tags external/misra/id/rule-18-4 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-18-5/NoMoreThanTwoLevelsOfPointerNestingInDeclarations.ql b/c/misra/src/rules/RULE-18-5/NoMoreThanTwoLevelsOfPointerNestingInDeclarations.ql index 7a847acbfa..f467c41804 100644 --- a/c/misra/src/rules/RULE-18-5/NoMoreThanTwoLevelsOfPointerNestingInDeclarations.ql +++ b/c/misra/src/rules/RULE-18-5/NoMoreThanTwoLevelsOfPointerNestingInDeclarations.ql @@ -8,6 +8,7 @@ * @problem.severity error * @tags external/misra/id/rule-18-5 * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-18-6/AutomaticStorageObjectAddressCopiedToOtherObject.ql b/c/misra/src/rules/RULE-18-6/AutomaticStorageObjectAddressCopiedToOtherObject.ql index 6d947efb16..efbc8d1334 100644 --- a/c/misra/src/rules/RULE-18-6/AutomaticStorageObjectAddressCopiedToOtherObject.ql +++ b/c/misra/src/rules/RULE-18-6/AutomaticStorageObjectAddressCopiedToOtherObject.ql @@ -9,6 +9,7 @@ * @problem.severity error * @tags external/misra/id/rule-18-6 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.ql b/c/misra/src/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.ql new file mode 100644 index 0000000000..6a520447d1 --- /dev/null +++ b/c/misra/src/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.ql @@ -0,0 +1,39 @@ +/** + * @id c/misra/thread-local-object-address-copied-to-global-object + * @name RULE-18-6: The address of an object with thread-local storage shall not be copied to a global object + * @description Storing the address of a thread-local object in a global object will result in + * undefined behavior if the address is accessed after the relevant thread is + * terminated. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-18-6 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Objects +import codingstandards.cpp.Concurrency + +from AssignExpr assignment, Element threadLocal, ObjectIdentity static +where + not isExcluded(assignment, Pointers1Package::threadLocalObjectAddressCopiedToGlobalObjectQuery()) and + assignment.getLValue() = static.getASubobjectAccess() and + static.getStorageDuration().isStatic() and + ( + exists(ObjectIdentity threadLocalObj | + threadLocal = threadLocalObj and + assignment.getRValue() = threadLocalObj.getASubobjectAddressExpr() and + threadLocalObj.getStorageDuration().isThread() + ) + or + exists(TSSGetFunctionCall getCall | + threadLocal = getCall.getKey() and + assignment.getRValue() = getCall + ) + ) +select assignment, "Thread local object $@ address copied to static object $@.", + threadLocal.getLocation(), threadLocal.toString(), static.getLocation(), static.toString() diff --git a/c/misra/src/rules/RULE-18-7/FlexibleArrayMembersDeclared.ql b/c/misra/src/rules/RULE-18-7/FlexibleArrayMembersDeclared.ql index 5ae2c9b9c6..73f0732ba5 100644 --- a/c/misra/src/rules/RULE-18-7/FlexibleArrayMembersDeclared.ql +++ b/c/misra/src/rules/RULE-18-7/FlexibleArrayMembersDeclared.ql @@ -7,6 +7,7 @@ * @problem.severity error * @tags external/misra/id/rule-18-7 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql b/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql index 00d02cdc02..cf19c02eca 100644 --- a/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql +++ b/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-18-8 * correctness * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ @@ -15,33 +16,53 @@ import cpp import codingstandards.c.misra /** - * A variable length array (VLA) - * ie an array where the size - * is not an integer constant expression + * Typedefs may be declared as VLAs, eg, `typedef int vla[x];`. This query finds types that refer to + * such typedef types, for instance `vla foo;` or adding a dimension via `vla bar[10];`. + * + * Consts and other specifiers may be added, but `vla *ptr;` is not a VLA any more, and is excluded. */ -class VariableLengthArray extends VariableDeclarationEntry { - VariableLengthArray() { - //VLAs will not have: static/extern specifiers (compilation error) - not this.hasSpecifier("static") and - not this.hasSpecifier("extern") and - //VLAs are not allowed to be initialized - not this.getDeclaration().hasInitializer() and - exists(ArrayType a | - //a.hasArraySize() does not catch multidimensional VLAs like a[1][] - a.toString().matches("%[]%") and - this.getUnspecifiedType() = a and - //variable length array is one declared in block or function prototype - ( - this.getDeclaration().getParentScope() instanceof Function or - this.getDeclaration().getParentScope() instanceof BlockStmt - ) +class VlaTypedefType extends Type { + VlaDeclStmt vlaDecl; + ArrayType arrayType; + + VlaTypedefType() { + // Holds for direct references to the typedef type: + this = vlaDecl.getType() and + vlaDecl.getType() instanceof TypedefType and + arrayType = vlaDecl.getType().stripTopLevelSpecifiers() + or + // Handle arrays of VLA typedefs, and carefully handle specified VLA typedef types, as + // `stripTopLevelSpecifiers` resolves past the VLA typedef type. + exists(DerivedType dt, VlaTypedefType vlaType | + (dt instanceof ArrayType or dt instanceof SpecifiedType) and + this = dt and + vlaType = dt.getBaseType() and + vlaDecl = vlaType.getVlaDeclStmt() and + arrayType = vlaType.getArrayType() ) } + + VlaDeclStmt getVlaDeclStmt() { result = vlaDecl } + + ArrayType getArrayType() { result = arrayType } } -from VariableLengthArray v +from Variable v, Expr size, ArrayType arrayType, VlaDeclStmt vlaDecl, string typeStr where not isExcluded(v, Declarations7Package::variableLengthArrayTypesUsedQuery()) and - //an exception, argv in : int main(int argc, char *argv[]) - not v.getDeclaration().getParentScope().(Function).hasName("main") -select v, "Variable length array declared." + size = vlaDecl.getVlaDimensionStmt(0).getDimensionExpr() and + ( + // Holds is if v is a variable declaration: + v = vlaDecl.getVariable() and + arrayType = v.getType().stripTopLevelSpecifiers() + or + // Holds is if v is a typedef declaration: + exists(VlaTypedefType typedef | + v.getType() = typedef and + arrayType = typedef.getArrayType() and + vlaDecl = typedef.getVlaDeclStmt() + ) + ) and + typeStr = arrayType.getBaseType().toString() +select v, "Variable length array of element type '" + typeStr + "' with non-constant size $@.", + size, size.toString() diff --git a/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql b/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql new file mode 100644 index 0000000000..da73214859 --- /dev/null +++ b/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql @@ -0,0 +1,68 @@ +/** + * @id c/misra/array-to-pointer-conversion-of-temporary-object + * @name RULE-18-9: An object with temporary lifetime shall not undergo array to pointer conversion + * @description Modifying or accessing elements of an array with temporary lifetime that has been + * converted to a pointer will result in undefined behavior. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-18-9 + * external/misra/c/2012/amendment3 + * correctness + * security + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Objects + +/** + * Holds if the value of an expression is used or stored. + * + * For instance, `(x)` does not use any values, but `x + y` uses `x` and `y`. + * + * A pointer-to-array conversion does not need to be flagged if the result of + * that conversion is not used or stored. + */ +predicate isUsedOrStored(Expr e) { + e = any(Operation o).getAnOperand() + or + e = any(ConditionalExpr c).getCondition() + or + e = any(Call c).getAnArgument() + or + e = any(VariableDeclarationEntry d).getDeclaration().getInitializer().getExpr() + or + e = any(ClassAggregateLiteral l).getAFieldExpr(_) +} + +/** + * Find expressions that defer their value directly to an inner expression + * value. + * + * When an array is on the rhs of a comma expr, or in the then/else branch of a + * ternary expr, and the result us used as a pointer, then the ArrayToPointer + * conversion is marked inside comma expr/ternary expr, on the operands. These + * conversions are only non-compliant if they flow into an operation or store. + * + * Full flow analysis with localFlowStep should not be necessary, and may cast a + * wider net than needed for some queries, potentially resulting in false + * positives. + */ +Expr temporaryObjectFlowStep(Expr e) { + e = result.(CommaExpr).getRightOperand() + or + e = result.(ConditionalExpr).getThen() + or + e = result.(ConditionalExpr).getElse() +} + +from FieldAccess fa, TemporaryObjectIdentity temporary, ArrayToPointerConversion conversion +where + not isExcluded(conversion, InvalidMemory3Package::arrayToPointerConversionOfTemporaryObjectQuery()) and + fa = temporary.getASubobjectAccess() and + conversion.getExpr() = fa and + isUsedOrStored(temporaryObjectFlowStep*(conversion.getExpr())) +select conversion, "Array to pointer conversion of array $@ from temporary object $@.", + fa.getTarget(), fa.getTarget().getName(), temporary, temporary.toString() diff --git a/c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql b/c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql new file mode 100644 index 0000000000..5ccc8316ec --- /dev/null +++ b/c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql @@ -0,0 +1,47 @@ +/** + * @id c/misra/modifiable-l-value-subscripted-with-temporary-lifetime + * @name RULE-18-9: Usage of the subscript operator on an object with temporary lifetime shall not return a modifiable value + * @description Modifying elements of an array with temporary lifetime will result in undefined + * behavior. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-18-9 + * external/misra/c/2012/amendment3 + * correctness + * security + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Objects +import codeql.util.Boolean + +predicate usedAsModifiableLvalue(Expr expr, Boolean allowArrayAccess) { + exists(Assignment parent | parent.getLValue() = expr) + or + exists(CrementOperation parent | parent.getOperand() = expr) + or + exists(AddressOfExpr parent | parent.getOperand() = expr) + or + // Don't report `x.y[0].m[0]++` twice. Recurse with `allowArrayAccess` set to false. + exists(FieldAccess parent | + parent.getQualifier() = expr and usedAsModifiableLvalue(parent, false) + ) + or + allowArrayAccess = true and + exists(ArrayExpr parent | parent.getArrayBase() = expr and usedAsModifiableLvalue(parent, true)) +} + +from ArrayExpr expr, FieldAccess fieldAccess, TemporaryObjectIdentity tempObject +where + not isExcluded(expr, + InvalidMemory3Package::modifiableLValueSubscriptedWithTemporaryLifetimeQuery()) and + expr = tempObject.getASubobjectAccess() and + fieldAccess = expr.getArrayBase() and + not expr.isUnevaluated() and + usedAsModifiableLvalue(expr, true) +select expr, + "Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ ", + fieldAccess, fieldAccess.getTarget().getName(), tempObject, tempObject.toString() diff --git a/c/misra/src/rules/RULE-19-1/ObjectAssignedToAnOverlappingObject.ql b/c/misra/src/rules/RULE-19-1/ObjectAssignedToAnOverlappingObject.ql index b39ce4fba4..31c24dcdd8 100644 --- a/c/misra/src/rules/RULE-19-1/ObjectAssignedToAnOverlappingObject.ql +++ b/c/misra/src/rules/RULE-19-1/ObjectAssignedToAnOverlappingObject.ql @@ -7,6 +7,7 @@ * @problem.severity error * @tags external/misra/id/rule-19-1 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/mandatory */ diff --git a/c/misra/src/rules/RULE-19-1/ObjectCopiedToAnOverlappingObject.ql b/c/misra/src/rules/RULE-19-1/ObjectCopiedToAnOverlappingObject.ql index bee9b41e2c..33de4f84b6 100644 --- a/c/misra/src/rules/RULE-19-1/ObjectCopiedToAnOverlappingObject.ql +++ b/c/misra/src/rules/RULE-19-1/ObjectCopiedToAnOverlappingObject.ql @@ -7,13 +7,13 @@ * @problem.severity error * @tags external/misra/id/rule-19-1 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/mandatory */ import cpp import codingstandards.c.misra import semmle.code.cpp.valuenumbering.GlobalValueNumbering -import codingstandards.cpp.dataflow.DataFlow /** * Offset in bytes of a field access diff --git a/c/misra/src/rules/RULE-19-2/UnionKeywordShouldNotBeUsed.ql b/c/misra/src/rules/RULE-19-2/UnionKeywordShouldNotBeUsed.ql index b3028d9add..14d01c47e3 100644 --- a/c/misra/src/rules/RULE-19-2/UnionKeywordShouldNotBeUsed.ql +++ b/c/misra/src/rules/RULE-19-2/UnionKeywordShouldNotBeUsed.ql @@ -7,6 +7,7 @@ * @problem.severity warning * @tags external/misra/id/rule-19-2 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-2-1/UnreachableCode.ql b/c/misra/src/rules/RULE-2-1/UnreachableCode.ql index 5de46fd9ea..020338913a 100644 --- a/c/misra/src/rules/RULE-2-1/UnreachableCode.ql +++ b/c/misra/src/rules/RULE-2-1/UnreachableCode.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-2-1 * readability * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-2-2/DeadCode.ql b/c/misra/src/rules/RULE-2-2/DeadCode.ql index c9ecb5e934..97c3808607 100644 --- a/c/misra/src/rules/RULE-2-2/DeadCode.ql +++ b/c/misra/src/rules/RULE-2-2/DeadCode.ql @@ -9,13 +9,89 @@ * @tags external/misra/id/rule-2-2 * readability * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.cpp.rules.deadcode.DeadCode +import codingstandards.cpp.alertreporting.HoldsForAllCopies +import codingstandards.cpp.deadcode.UselessAssignments -class MisraCDeadCodeQuery extends DeadCodeSharedQuery { - MisraCDeadCodeQuery() { this = DeadCodePackage::deadCodeQuery() } +/** + * Gets an explicit cast from `e` if one exists. + */ +Cast getExplicitCast(Expr e) { + exists(Conversion c | c = e.getExplicitlyConverted() | + result = c + or + result = c.(ParenthesisExpr).getExpr() + ) +} + +class ExprStmtExpr extends Expr { + ExprStmtExpr() { exists(ExprStmt es | es.getExpr() = this) } +} + +/** + * An "operation" as defined by MISRA C Rule 2.2 that is dead, i.e. it's removal has no effect on + * the behaviour of the program. + */ +class DeadOperationInstance extends Expr { + string description; + + DeadOperationInstance() { + // Exclude cases nested within macro expansions, because the code may be "live" in other + // expansions + isNotWithinMacroExpansion(this) and + exists(ExprStmtExpr e | + if exists(getExplicitCast(e)) + then + this = getExplicitCast(e) and + // void conversions are permitted + not getExplicitCast(e) instanceof VoidConversion and + description = "Cast operation is unused" + else ( + this = e and + ( + if e instanceof Assignment + then + exists(SsaDefinition sd, LocalScopeVariable v | + e = sd.getDefinition() and + sd.getDefiningValue(v).isPure() and + // The definition is useless + isUselessSsaDefinition(sd, v) and + description = "Assignment to " + v.getName() + " is unused and has no side effects" + ) + else ( + e.isPure() and + description = "Result of operation is unused and has no side effects" + ) + ) + ) + ) + } + + string getDescription() { result = description } } + +class DeadOperation = HoldsForAllCopies::LogicalResultElement; + +from + DeadOperation deadOperation, DeadOperationInstance instance, string message, Element explainer, + string explainerDescription +where + not isExcluded(instance, DeadCodePackage::deadCodeQuery()) and + instance = deadOperation.getAnElementInstance() and + if instance instanceof FunctionCall + then + message = instance.getDescription() + " from call to function $@" and + explainer = instance.(FunctionCall).getTarget() and + explainerDescription = explainer.(Function).getName() + else ( + message = instance.getDescription() and + // Ignore the explainer + explainer = instance and + explainerDescription = "" + ) +select deadOperation, message + ".", explainer, explainerDescription diff --git a/c/misra/src/rules/RULE-2-3/UnusedTypeDeclarations.ql b/c/misra/src/rules/RULE-2-3/UnusedTypeDeclarations.ql index 3192ee960f..b4c6bbf42c 100644 --- a/c/misra/src/rules/RULE-2-3/UnusedTypeDeclarations.ql +++ b/c/misra/src/rules/RULE-2-3/UnusedTypeDeclarations.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-2-3 * readability * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-2-4/UnusedTagDeclaration.ql b/c/misra/src/rules/RULE-2-4/UnusedTagDeclaration.ql index c10985f28c..9ad460068b 100644 --- a/c/misra/src/rules/RULE-2-4/UnusedTagDeclaration.ql +++ b/c/misra/src/rules/RULE-2-4/UnusedTagDeclaration.ql @@ -9,12 +9,13 @@ * @tags external/misra/id/rule-2-4 * readability * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ import cpp import codingstandards.c.misra -import codingstandards.cpp.TypeUses +import codingstandards.cpp.types.Uses from UserType s where @@ -31,5 +32,5 @@ where // `isInMacroExpansion` is broken for `UserType`s. not s.isInMacroExpansion() and // Exclude template parameters, in case this is run on C++ code. - not s instanceof TemplateParameter + not s instanceof TypeTemplateParameter select s, "struct " + s.getName() + " has an unused tag." diff --git a/c/misra/src/rules/RULE-2-5/UnusedMacroDeclaration.ql b/c/misra/src/rules/RULE-2-5/UnusedMacroDeclaration.ql index ed2b1f6065..2b5a8e8c1d 100644 --- a/c/misra/src/rules/RULE-2-5/UnusedMacroDeclaration.ql +++ b/c/misra/src/rules/RULE-2-5/UnusedMacroDeclaration.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-2-5 * readability * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ @@ -18,7 +19,18 @@ import codingstandards.c.misra from Macro m where not isExcluded(m, DeadCodePackage::unusedMacroDeclarationQuery()) and + // We consider a macro "used" if there is a macro access not exists(MacroAccess ma | ma.getMacro() = m) and + // Or if there exists a check whether the macro is defined which the extractor + // hasn't been able to tie to a macro (usually because this use came before + // the macro was defined e.g. a header guard) + not exists(PreprocessorBranchDirective bd | + // Covers the #ifdef and #ifndef cases + bd.getHead() = m.getName() + or + // Covers the use of defined() to check if a macro is defined + m.getName() = bd.getHead().regexpCapture(".*defined *\\(? *([^\\s()]+) *\\)?\\.*", 1) + ) and // We consider a macro "used" if the name is undef-ed at some point in the same file, or a file // that includes the file defining the macro. This will over approximate use in the case of a // macro which is defined, then undefined, then re-defined but not used. diff --git a/c/misra/src/rules/RULE-2-6/UnusedLabelDeclaration.ql b/c/misra/src/rules/RULE-2-6/UnusedLabelDeclaration.ql index 4ab96707e4..7838c5fc1f 100644 --- a/c/misra/src/rules/RULE-2-6/UnusedLabelDeclaration.ql +++ b/c/misra/src/rules/RULE-2-6/UnusedLabelDeclaration.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-2-6 * readability * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-2-7/UnusedParameter.ql b/c/misra/src/rules/RULE-2-7/UnusedParameter.ql index b9c2f32f60..e27caee50b 100644 --- a/c/misra/src/rules/RULE-2-7/UnusedParameter.ql +++ b/c/misra/src/rules/RULE-2-7/UnusedParameter.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-2-7 * readability * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-2-8/UnusedObjectDefinition.ql b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinition.ql new file mode 100644 index 0000000000..13355b7f74 --- /dev/null +++ b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinition.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/unused-object-definition + * @name RULE-2-8: A project should not contain unused object definitions + * @description Object definitions which are unused should be removed. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-2-8 + * maintainability + * performance + * external/misra/c/2012/amendment4 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.deadcode.UnusedObjects + +from ReportDeadObject report +where + not isExcluded(report.getPrimaryElement(), DeadCode2Package::unusedObjectDefinitionQuery()) and + not report.hasAttrUnused() +select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocatable(), + report.getOptionalPlaceholderMessage() diff --git a/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionStrict.ql b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionStrict.ql new file mode 100644 index 0000000000..4eb1ad9773 --- /dev/null +++ b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionStrict.ql @@ -0,0 +1,26 @@ +/** + * @id c/misra/unused-object-definition-strict + * @name RULE-2-8: A project should not contain '__attribute__((unused))' object definitions + * @description A strict query which reports all unused object definitions with + * '__attribute__((unused))'. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-2-8 + * maintainability + * performance + * external/misra/c/2012/amendment4 + * external/misra/c/strict + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.deadcode.UnusedObjects + +from ReportDeadObject report +where + not isExcluded(report.getPrimaryElement(), DeadCode2Package::unusedObjectDefinitionStrictQuery()) and + report.hasAttrUnused() +select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocatable(), + report.getOptionalPlaceholderMessage() diff --git a/c/misra/src/rules/RULE-20-1/IncludeDirectivesPrecededByDirectivesOrComments.ql b/c/misra/src/rules/RULE-20-1/IncludeDirectivesPrecededByDirectivesOrComments.ql index aa0d733eb2..ba78abcb5e 100644 --- a/c/misra/src/rules/RULE-20-1/IncludeDirectivesPrecededByDirectivesOrComments.ql +++ b/c/misra/src/rules/RULE-20-1/IncludeDirectivesPrecededByDirectivesOrComments.ql @@ -8,6 +8,7 @@ * @problem.severity warning * @tags external/misra/id/rule-20-1 * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-20-10/PreprocessorHashOperatorsShouldNotBeUsed.ql b/c/misra/src/rules/RULE-20-10/PreprocessorHashOperatorsShouldNotBeUsed.ql index f0d82928fb..016589af94 100644 --- a/c/misra/src/rules/RULE-20-10/PreprocessorHashOperatorsShouldNotBeUsed.ql +++ b/c/misra/src/rules/RULE-20-10/PreprocessorHashOperatorsShouldNotBeUsed.ql @@ -8,6 +8,7 @@ * @problem.severity warning * @tags external/misra/id/rule-20-10 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.ql b/c/misra/src/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.ql index 6ea7aa0a13..fc87186d3e 100644 --- a/c/misra/src/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.ql +++ b/c/misra/src/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.ql @@ -8,19 +8,16 @@ * @problem.severity warning * @tags external/misra/id/rule-20-11 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.cpp.Macro +import codingstandards.cpp.rules.macroparameterfollowinghash.MacroParameterFollowingHash -from Macro m -where - not isExcluded(m, Preprocessor2Package::moreThanOneHashOperatorInMacroDefinitionQuery()) and - exists(StringizingOperator one, TokenPastingOperator two | - one.getMacro() = m and - two.getMacro() = m and - one.getOffset() < two.getOffset() - ) -select m, "Macro definition uses an # operator followed by a ## operator." +class MoreThanOneHashOperatorInMacroDefinitionQuery extends MacroParameterFollowingHashSharedQuery { + MoreThanOneHashOperatorInMacroDefinitionQuery() { + this = Preprocessor2Package::moreThanOneHashOperatorInMacroDefinitionQuery() + } +} diff --git a/c/misra/src/rules/RULE-20-12/MacroParameterUsedAsHashOperand.ql b/c/misra/src/rules/RULE-20-12/MacroParameterUsedAsHashOperand.ql index 6a66afb74b..da66f66fb2 100644 --- a/c/misra/src/rules/RULE-20-12/MacroParameterUsedAsHashOperand.ql +++ b/c/misra/src/rules/RULE-20-12/MacroParameterUsedAsHashOperand.ql @@ -10,27 +10,17 @@ * @tags external/misra/id/rule-20-12 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.cpp.Macro +import codingstandards.cpp.rules.amixedusemacroargumentsubjecttoexpansion.AMixedUseMacroArgumentSubjectToExpansion -from FunctionLikeMacro m, MacroInvocation mi, int i, string expanded, string param -where - not isExcluded(mi, Preprocessor2Package::macroParameterUsedAsHashOperandQuery()) and - mi = m.getAnInvocation() and - param = m.getParameter(i) and - ( - exists(TokenPastingOperator op | op.getMacro() = m and op.getOperand() = param) - or - exists(StringizingOperator op | op.getMacro() = m and op.getOperand() = param) - ) and - // An expansion that is equal to "" means the expansion is not used and is optimized away by EDG. This happens when the expanded argument is an operand to `#` or `##`. - // This check ensure there is an expansion that is used. - expanded = mi.getExpandedArgument(i) and - not expanded = "" and - not mi.getUnexpandedArgument(i) = mi.getExpandedArgument(i) -select m, - "Macro " + m.getName() + " contains use of parameter " + param + " used in multiple contexts." +class MacroParameterUsedAsHashOperandQuery extends AMixedUseMacroArgumentSubjectToExpansionSharedQuery +{ + MacroParameterUsedAsHashOperandQuery() { + this = Preprocessor2Package::macroParameterUsedAsHashOperandQuery() + } +} diff --git a/c/misra/src/rules/RULE-20-2/ForbiddenCharactersInHeaderFileName.ql b/c/misra/src/rules/RULE-20-2/ForbiddenCharactersInHeaderFileName.ql index a9b27e8669..d9942c3e56 100644 --- a/c/misra/src/rules/RULE-20-2/ForbiddenCharactersInHeaderFileName.ql +++ b/c/misra/src/rules/RULE-20-2/ForbiddenCharactersInHeaderFileName.ql @@ -8,6 +8,7 @@ * @problem.severity error * @tags external/misra/id/rule-20-2 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-20-4/MacroDefinedWithTheSameNameAsKeyword.ql b/c/misra/src/rules/RULE-20-4/MacroDefinedWithTheSameNameAsKeyword.ql index 6b9ae71120..210e081bb1 100644 --- a/c/misra/src/rules/RULE-20-4/MacroDefinedWithTheSameNameAsKeyword.ql +++ b/c/misra/src/rules/RULE-20-4/MacroDefinedWithTheSameNameAsKeyword.ql @@ -11,6 +11,7 @@ * correctness * readability * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-20-5/UndefShouldNotBeUsed.ql b/c/misra/src/rules/RULE-20-5/UndefShouldNotBeUsed.ql index c253c795e8..15bec51bf8 100644 --- a/c/misra/src/rules/RULE-20-5/UndefShouldNotBeUsed.ql +++ b/c/misra/src/rules/RULE-20-5/UndefShouldNotBeUsed.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-20-5 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-20-6/FunctionLikeMacroArgsContainHashTokenCQuery.ql b/c/misra/src/rules/RULE-20-6/FunctionLikeMacroArgsContainHashTokenCQuery.ql index 3e212dc972..e0fc8e4510 100644 --- a/c/misra/src/rules/RULE-20-6/FunctionLikeMacroArgsContainHashTokenCQuery.ql +++ b/c/misra/src/rules/RULE-20-6/FunctionLikeMacroArgsContainHashTokenCQuery.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-20-6 * readability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-20-7/MacroParameterNotEnclosedInParenthesesCQuery.ql b/c/misra/src/rules/RULE-20-7/MacroParameterNotEnclosedInParenthesesCQuery.ql index ad4882d07c..e557f99a18 100644 --- a/c/misra/src/rules/RULE-20-7/MacroParameterNotEnclosedInParenthesesCQuery.ql +++ b/c/misra/src/rules/RULE-20-7/MacroParameterNotEnclosedInParenthesesCQuery.ql @@ -10,6 +10,7 @@ * @tags external/misra/id/rule-20-7 * correctness * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-20-8/ControllingExpressionIfDirective.ql b/c/misra/src/rules/RULE-20-8/ControllingExpressionIfDirective.ql index cd55e03ee0..5e2c1fbc27 100644 --- a/c/misra/src/rules/RULE-20-8/ControllingExpressionIfDirective.ql +++ b/c/misra/src/rules/RULE-20-8/ControllingExpressionIfDirective.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-20-8 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-20-9/IdentifiersUsedInPreprocessorExpression.ql b/c/misra/src/rules/RULE-20-9/IdentifiersUsedInPreprocessorExpression.ql index 15ca323038..be6f3c00f3 100644 --- a/c/misra/src/rules/RULE-20-9/IdentifiersUsedInPreprocessorExpression.ql +++ b/c/misra/src/rules/RULE-20-9/IdentifiersUsedInPreprocessorExpression.ql @@ -10,6 +10,7 @@ * @tags external/misra/id/rule-20-9 * correctness * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-21-1/DefineAndUndefUsedOnReservedIdentifierOrMacroName.ql b/c/misra/src/rules/RULE-21-1/DefineAndUndefUsedOnReservedIdentifierOrMacroName.ql index b37b5cb92e..86d8426df8 100644 --- a/c/misra/src/rules/RULE-21-1/DefineAndUndefUsedOnReservedIdentifierOrMacroName.ql +++ b/c/misra/src/rules/RULE-21-1/DefineAndUndefUsedOnReservedIdentifierOrMacroName.ql @@ -10,6 +10,7 @@ * correctness * readability * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-21-10/StandardLibraryTimeAndDateFunctionsUsed.ql b/c/misra/src/rules/RULE-21-10/StandardLibraryTimeAndDateFunctionsUsed.ql index c519ebe701..0ad9c350f2 100644 --- a/c/misra/src/rules/RULE-21-10/StandardLibraryTimeAndDateFunctionsUsed.ql +++ b/c/misra/src/rules/RULE-21-10/StandardLibraryTimeAndDateFunctionsUsed.ql @@ -7,6 +7,7 @@ * @problem.severity error * @tags external/misra/id/rule-21-10 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-21-11/StandardHeaderFileTgmathhUsed.ql b/c/misra/src/rules/RULE-21-11/StandardHeaderFileTgmathhUsed.ql index 5a33f94fb6..50c4d48cb6 100644 --- a/c/misra/src/rules/RULE-21-11/StandardHeaderFileTgmathhUsed.ql +++ b/c/misra/src/rules/RULE-21-11/StandardHeaderFileTgmathhUsed.ql @@ -7,7 +7,8 @@ * @problem.severity error * @tags external/misra/id/rule-21-11 * correctness - * external/misra/obligation/required + * external/misra/c/2012/third-edition-first-revision + * external/misra/obligation/advisory */ import cpp diff --git a/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql b/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql index 727cb190e9..b8d17de8aa 100644 --- a/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql +++ b/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql @@ -8,6 +8,7 @@ * @problem.severity warning * @tags external/misra/id/rule-21-12 * correctness + * external/misra/c/2012/amendment2 * external/misra/obligation/advisory */ @@ -17,7 +18,8 @@ import codingstandards.c.misra class FPExceptionHandlingFunction extends Function { FPExceptionHandlingFunction() { this.hasName([ - "feclearexcept", "fegetexceptflag", "feraiseexcept", "fesetexceptflag", "fetestexcept" + "feclearexcept", "fegetexceptflag", "feraiseexcept", "fesetexceptflag", "fetestexcept", + "fesetenv", "feupdateenv", "fesetround" ]) and this.getFile().getBaseName() = "fenv.h" } @@ -32,22 +34,30 @@ class FPExceptionHandlingMacro extends Macro { } } -from Locatable call, string name, string kind +from Locatable element, string name, string message where - not isExcluded(call, BannedPackage::exceptionHandlingFeaturesOfFenvhUsedQuery()) and + not isExcluded(element, BannedPackage::exceptionHandlingFeaturesOfFenvhUsedQuery()) and ( + exists(Include include | + include.getIncludedFile().getBaseName() = "fenv.h" and + message = "Include of banned header" and + name = "fenv.h" and + element = include + ) + or exists(FPExceptionHandlingFunction f | - call = f.getACallToThisFunction() and + element = f.getACallToThisFunction() and name = f.getName() and - kind = "function" + message = "Call to banned function" ) or exists(FPExceptionHandlingMacro m | - call = m.getAnInvocation() and + element = m.getAnInvocation() and name = m.getName() and - kind = "macro" and + message = "Expansion of banned macro" and // Exclude macro invocations expanded from other macro invocations from macros in fenv.h. - not call.(MacroInvocation).getParentInvocation().getMacro().getFile().getBaseName() = "fenv.h" + not element.(MacroInvocation).getParentInvocation().getMacro().getFile().getBaseName() = + "fenv.h" ) ) -select call, "Call to banned " + kind + " " + name + "." +select element, message + " '" + name + "'." diff --git a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql index 70ec91e3c1..b7ccf534fa 100644 --- a/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql +++ b/c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql @@ -7,6 +7,7 @@ * @precision very-high * @problem.severity error * @tags external/misra/id/rule-21-13 + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/mandatory */ diff --git a/c/misra/src/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.ql b/c/misra/src/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.ql index 44e21d14db..b487f5b9b5 100644 --- a/c/misra/src/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.ql +++ b/c/misra/src/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.ql @@ -9,13 +9,14 @@ * @tags external/misra/id/rule-21-14 * maintainability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra import codingstandards.c.misra.EssentialTypes -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import NullTerminatedStringToMemcmpFlow::PathGraph // Data flow from a StringLiteral or from an array of characters, to a memcmp call diff --git a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql index 2c585d8f10..28dce7b638 100644 --- a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql +++ b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql @@ -7,12 +7,13 @@ * @precision very-high * @problem.severity error * @tags external/misra/id/rule-21-15 + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.c.Pointers +import codingstandards.cpp.types.Pointers class MemCmpMoveCpy extends Function { // Couldn't extend BuiltInFunction because it misses `memcmp` diff --git a/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql b/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql index 1a939e920c..cb70567660 100644 --- a/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql +++ b/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql @@ -10,6 +10,7 @@ * @tags external/misra/id/rule-21-16 * maintainability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-21-17/StringFunctionPointerArgumentOutOfBounds.ql b/c/misra/src/rules/RULE-21-17/StringFunctionPointerArgumentOutOfBounds.ql index a4850781f6..31d3434c58 100644 --- a/c/misra/src/rules/RULE-21-17/StringFunctionPointerArgumentOutOfBounds.ql +++ b/c/misra/src/rules/RULE-21-17/StringFunctionPointerArgumentOutOfBounds.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-21-17 * correctness * security + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/mandatory */ diff --git a/c/misra/src/rules/RULE-21-18/StringLibrarySizeArgumentOutOfBounds.ql b/c/misra/src/rules/RULE-21-18/StringLibrarySizeArgumentOutOfBounds.ql index 3554b2791e..22ccc14b69 100644 --- a/c/misra/src/rules/RULE-21-18/StringLibrarySizeArgumentOutOfBounds.ql +++ b/c/misra/src/rules/RULE-21-18/StringLibrarySizeArgumentOutOfBounds.ql @@ -10,6 +10,7 @@ * @tags external/misra/id/rule-21-18 * correctness * security + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/mandatory */ diff --git a/c/misra/src/rules/RULE-21-19/ValuesReturnedByLocaleSettingUsedAsPtrToConst.ql b/c/misra/src/rules/RULE-21-19/ValuesReturnedByLocaleSettingUsedAsPtrToConst.ql index 0e02cc1d84..6fa3ad92be 100644 --- a/c/misra/src/rules/RULE-21-19/ValuesReturnedByLocaleSettingUsedAsPtrToConst.ql +++ b/c/misra/src/rules/RULE-21-19/ValuesReturnedByLocaleSettingUsedAsPtrToConst.ql @@ -9,6 +9,7 @@ * @problem.severity error * @tags external/misra/id/rule-21-19 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/mandatory */ diff --git a/c/misra/src/rules/RULE-21-2/DoNotDeclareAReservedIdentifier.ql b/c/misra/src/rules/RULE-21-2/DoNotDeclareAReservedIdentifier.ql index 89140222da..80ad8386bc 100644 --- a/c/misra/src/rules/RULE-21-2/DoNotDeclareAReservedIdentifier.ql +++ b/c/misra/src/rules/RULE-21-2/DoNotDeclareAReservedIdentifier.ql @@ -9,6 +9,7 @@ * correctness * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-21-20/CallToSetlocaleInvalidatesOldPointers.ql b/c/misra/src/rules/RULE-21-20/CallToSetlocaleInvalidatesOldPointers.ql index c193e899db..6441add7fc 100644 --- a/c/misra/src/rules/RULE-21-20/CallToSetlocaleInvalidatesOldPointers.ql +++ b/c/misra/src/rules/RULE-21-20/CallToSetlocaleInvalidatesOldPointers.ql @@ -9,6 +9,7 @@ * @problem.severity error * @tags external/misra/id/rule-21-20 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/mandatory */ diff --git a/c/misra/src/rules/RULE-21-20/CallToSetlocaleInvalidatesOldPointersWarn.ql b/c/misra/src/rules/RULE-21-20/CallToSetlocaleInvalidatesOldPointersWarn.ql index 0bbcb045d9..e7e97e2639 100644 --- a/c/misra/src/rules/RULE-21-20/CallToSetlocaleInvalidatesOldPointersWarn.ql +++ b/c/misra/src/rules/RULE-21-20/CallToSetlocaleInvalidatesOldPointersWarn.ql @@ -9,6 +9,7 @@ * @problem.severity warning * @tags external/misra/id/rule-21-20 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/mandatory */ diff --git a/c/misra/src/rules/RULE-21-21/SystemOfStdlibhUsed.ql b/c/misra/src/rules/RULE-21-21/SystemOfStdlibhUsed.ql index b38f159c14..81dd6ba1a3 100644 --- a/c/misra/src/rules/RULE-21-21/SystemOfStdlibhUsed.ql +++ b/c/misra/src/rules/RULE-21-21/SystemOfStdlibhUsed.ql @@ -8,6 +8,7 @@ * @problem.severity error * @tags external/misra/id/rule-21-21 * security + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql b/c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql new file mode 100644 index 0000000000..fc8565ade5 --- /dev/null +++ b/c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql @@ -0,0 +1,52 @@ +/** + * @id c/misra/tg-math-argument-with-invalid-essential-type + * @name RULE-21-22: All operand arguments to type-generic macros in shall have an appropriate essential type + * @description All operand arguments to any type-generic macros in shall have an + * appropriate essential type. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-21-22 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.TgMath +import codingstandards.c.misra.EssentialTypes + +EssentialTypeCategory getAnAllowedEssentialTypeCategory(TgMathInvocation call) { + result = EssentiallySignedType() + or + result = EssentiallyUnsignedType() + or + result = EssentiallyFloatingType(Real()) + or + call.allowsComplex() and + result = EssentiallyFloatingType(Complex()) +} + +string getAllowedTypesString(TgMathInvocation call) { + if call.allowsComplex() + then result = "essentially signed, unsigned, or floating type" + else result = "essentially signed, unsigned, or real floating type" +} + +from + TgMathInvocation call, Expr convertedArg, Expr unconverted, int argIndex, Type type, + EssentialTypeCategory category +where + not isExcluded(call, EssentialTypes2Package::tgMathArgumentWithInvalidEssentialTypeQuery()) and + // We must handle conversions specially, as clang inserts casts in the macro body we want to ignore. + convertedArg = call.getExplicitlyConvertedOperandArgument(argIndex) and + unconverted = convertedArg.getUnconverted() and + // Do not use `convertedArg.getEssentialType()`, as that is affected by clang's casts in the macro body. + type = getEssentialTypeBeforeConversions(convertedArg) and + category = getEssentialTypeCategory(type) and + not category = getAnAllowedEssentialTypeCategory(call) +select unconverted, + "Argument " + (argIndex + 1) + " provided to type-generic macro '" + call.getMacroName() + + "' has " + category.toString().toLowerCase() + ", which is not " + getAllowedTypesString(call) + + "." diff --git a/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql b/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql new file mode 100644 index 0000000000..34d3b62b2c --- /dev/null +++ b/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql @@ -0,0 +1,73 @@ +/** + * @id c/misra/tg-math-arguments-with-differing-standard-type + * @name RULE-21-23: Operand arguments for an invocation of a type-generic macro shall have the same standard type + * @description All operand arguments to any multi-argument type-generic macros in shall + * have the same standard type. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-21-23 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.TgMath + +string argTypesString(TgMathInvocation call, int i) { + exists(string typeStr | + typeStr = getEffectiveStandardType(call.getOperandArgument(i)).toString() and + ( + i = 0 and result = typeStr + or + i > 0 and result = argTypesString(call, i - 1) + ", " + typeStr + ) + ) +} + +/** + * If the range of values can be represented as a signed int, it is promoted to signed int. + * + * A value may also promote to unsigned int but only if `int` cannot represent the range of + * values. Which basically means only an `unsigned int` promotes to `unsigned int`, so we don't + * need to do anything in this case. + * + * An unsigned int bitfield with fewer than 32 bits is promoted to `int`. + */ +predicate promotesToSignedInt(Expr e) { + exists(int intBits, int intBytes | + intBytes = any(IntType t).getSize() and + intBits = intBytes * 8 and + ( + e.(FieldAccess).getTarget().(BitField).getNumBits() < intBits + or + e.getUnderlyingType().(IntegralType).getSize() < intBytes + ) + ) +} + +Type getPromotedType(Expr e) { + if promotesToSignedInt(e) then result.(IntType).isSigned() else result = e.getUnderlyingType() +} + +Type canonicalize(Type type) { + if type instanceof IntegralType + then result = type.(IntegralType).getCanonicalArithmeticType() + else result = type +} + +Type getEffectiveStandardType(Expr e) { result = canonicalize(getPromotedType(e)) } + +from TgMathInvocation call, Type firstType +where + not isExcluded(call, EssentialTypes2Package::tgMathArgumentsWithDifferingStandardTypeQuery()) and + firstType = getEffectiveStandardType(call.getExplicitlyConvertedOperandArgument(0)) and + not forall(Expr arg | arg = call.getExplicitlyConvertedOperandArgument(_) | + firstType = getEffectiveStandardType(arg) + ) +select call, + "Call to type-generic macro '" + call.getMacroName() + + "' has arguments with differing standard types (" + + argTypesString(call, call.getNumberOfOperandArguments() - 1) + ")." diff --git a/c/misra/src/rules/RULE-21-24/CallToBannedRandomFunction.ql b/c/misra/src/rules/RULE-21-24/CallToBannedRandomFunction.ql new file mode 100644 index 0000000000..8066cc80cb --- /dev/null +++ b/c/misra/src/rules/RULE-21-24/CallToBannedRandomFunction.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/call-to-banned-random-function + * @name RULE-21-24: The random number generator functions of shall not be used + * @description The standard functions rand() and srand() will not give high quality random results + * in all implementations and are therefore banned. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-21-24 + * security + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from FunctionCall call, string name +where + not isExcluded(call, Banned2Package::callToBannedRandomFunctionQuery()) and + name = ["rand", "srand"] and + call.getTarget().hasGlobalOrStdName(name) +select call, "Call to banned random number generation function '" + name + "'." diff --git a/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql b/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql new file mode 100644 index 0000000000..684b4e50cb --- /dev/null +++ b/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql @@ -0,0 +1,110 @@ +/** + * @id c/misra/invalid-memory-order-argument + * @name RULE-21-25: All memory synchronization operations shall be executed in sequentially consistent order + * @description Only the memory ordering of 'memory_order_seq_cst' is fully portable and consistent. + * @kind path-problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-25 + * external/misra/c/2012/amendment4 + * correctness + * concurrency + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.StdFunctionOrMacro +import semmle.code.cpp.dataflow.new.DataFlow + +class MemoryOrderEnum extends Enum { + MemoryOrderEnum() { + this.hasGlobalOrStdName("memory_order") + or + exists(TypedefType t | + t.getName() = "memory_order" and + t.getBaseType() = this + ) + } +} + +/* A member of the set of memory orders defined in the `memory_order` enum */ +class MemoryOrder extends EnumConstant { + MemoryOrder() { getDeclaringEnum() instanceof MemoryOrderEnum } + + int getIntValue() { result = getValue().toInt() } +} + +/* This is the only standardized memory order, allowed by RULE-21-25. */ +class AllowedMemoryOrder extends MemoryOrder { + AllowedMemoryOrder() { getName() = "memory_order_seq_cst" } +} + +/* An expression referring to a memory order */ +class MemoryOrderConstantAccess extends EnumConstantAccess { + MemoryOrderConstantAccess() { getTarget() instanceof MemoryOrder } + + predicate isAllowedOrder() { getTarget() instanceof AllowedMemoryOrder } +} + +/* An expression with a constant value that equals a `MemoryOrder` constant */ +class MemoryOrderConstantExpr extends Expr { + MemoryOrder ord; + + MemoryOrderConstantExpr() { + if this instanceof MemoryOrderConstantAccess + then ord = this.(MemoryOrderConstantAccess).getTarget() + else ord.getIntValue() = getValue().toInt() + } + + /* Get the name of the `MemoryOrder` this expression is valued as. */ + string getMemoryOrderString() { result = ord.getName() } +} + +module MemoryOrderFlowConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { + // Direct usage of memory order constant + exists(MemoryOrderConstantAccess constant | + node.asExpr() = constant and + not constant.isAllowedOrder() + ) + or + // A literal with a disallowed constant integer value + exists(Literal literal | + node.asExpr() = literal and + not literal.getValue().toInt() = any(AllowedMemoryOrder a).getValue().toInt() + ) + } + + predicate isSink(DataFlow::Node node) { + exists(AtomicallySequencedCall call | call.getAMemoryOrderArgument() = node.asExpr()) + } +} + +module MemoryOrderFlow = DataFlow::Global; + +import MemoryOrderFlow::PathGraph + +/** + * If the node is a memory order constant, or shares a value with a memory order constant, then + * return the name of that constant. Otherwise, simply print the node. + */ +string describeMemoryOrderNode(DataFlow::Node node) { + if node.asExpr() instanceof MemoryOrderConstantExpr + then result = node.asExpr().(MemoryOrderConstantExpr).getMemoryOrderString() + else result = node.toString() +} + +from + Expr argument, AtomicallySequencedCall function, string value, MemoryOrderFlow::PathNode source, + MemoryOrderFlow::PathNode sink +where + not isExcluded(argument, Concurrency6Package::invalidMemoryOrderArgumentQuery()) and + MemoryOrderFlow::flowPath(source, sink) and + argument = sink.getNode().asExpr() and + value = describeMemoryOrderNode(source.getNode()) and + // Double check that we didn't find flow from something equivalent to the allowed value. + not value = any(AllowedMemoryOrder e).getName() and + function.getAMemoryOrderArgument() = argument +select argument, source, sink, "Invalid memory order '$@' in call to function '$@'.", value, value, + function, function.getName() diff --git a/c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql b/c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql new file mode 100644 index 0000000000..929eb5bd0a --- /dev/null +++ b/c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql @@ -0,0 +1,76 @@ +/** + * @id c/misra/timedlock-on-inappropriate-mutex-type + * @name RULE-21-26: The Standard Library function mtx_timedlock() shall only be invoked on mutexes of type mtx_timed + * @description The Standard Library function mtx_timedlock() shall only be invoked on mutex objects + * of appropriate mutex type. + * @kind path-problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-21-26 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import semmle.code.cpp.dataflow.new.DataFlow + +class MutexTimed extends EnumConstant { + MutexTimed() { hasName("mtx_timed") } +} + +class MutexInitCall extends FunctionCall { + Expr mutexExpr; + Expr mutexTypeExpr; + + MutexInitCall() { + getTarget().hasName("mtx_init") and + mutexExpr = getArgument(0) and + mutexTypeExpr = getArgument(1) + } + + predicate isTimedMutexType() { + exists(EnumConstantAccess baseTypeAccess | + ( + baseTypeAccess = mutexTypeExpr + or + baseTypeAccess = mutexTypeExpr.(BinaryBitwiseOperation).getAnOperand() + ) and + baseTypeAccess.getTarget() instanceof MutexTimed + ) + or + mutexTypeExpr.getValue().toInt() = any(MutexTimed m).getValue().toInt() + } + + Expr getMutexExpr() { result = mutexExpr } +} + +module MutexTimedlockFlowConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { + exists(MutexInitCall init | + node.asDefiningArgument() = init.getMutexExpr() and not init.isTimedMutexType() + ) + } + + predicate isSink(DataFlow::Node node) { + exists(FunctionCall fc | + fc.getTarget().hasName("mtx_timedlock") and + node.asIndirectExpr() = fc.getArgument(0) + ) + } +} + +module Flow = DataFlow::Global; + +import Flow::PathGraph + +from Flow::PathNode source, Flow::PathNode sink +where + not isExcluded(sink.getNode().asExpr(), + Concurrency7Package::timedlockOnInappropriateMutexTypeQuery()) and + Flow::flowPath(source, sink) +select sink.getNode(), source, sink, + "Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'.", source.getNode(), + "initialized" diff --git a/c/misra/src/rules/RULE-21-3/MemoryAllocDeallocFunctionsOfStdlibhUsed.ql b/c/misra/src/rules/RULE-21-3/MemoryAllocDeallocFunctionsOfStdlibhUsed.ql index ed3317b696..ab3ba3e328 100644 --- a/c/misra/src/rules/RULE-21-3/MemoryAllocDeallocFunctionsOfStdlibhUsed.ql +++ b/c/misra/src/rules/RULE-21-3/MemoryAllocDeallocFunctionsOfStdlibhUsed.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-21-3 * correctness * security + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-21-4/StandardHeaderFileUsedSetjmph.ql b/c/misra/src/rules/RULE-21-4/StandardHeaderFileUsedSetjmph.ql index 6de73499c0..88ad0aa6db 100644 --- a/c/misra/src/rules/RULE-21-4/StandardHeaderFileUsedSetjmph.ql +++ b/c/misra/src/rules/RULE-21-4/StandardHeaderFileUsedSetjmph.ql @@ -7,6 +7,7 @@ * @problem.severity error * @tags external/misra/id/rule-21-4 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-21-5/StandardHeaderFileUsedSignalh.ql b/c/misra/src/rules/RULE-21-5/StandardHeaderFileUsedSignalh.ql index 004060b5a5..d22ee55742 100644 --- a/c/misra/src/rules/RULE-21-5/StandardHeaderFileUsedSignalh.ql +++ b/c/misra/src/rules/RULE-21-5/StandardHeaderFileUsedSignalh.ql @@ -7,6 +7,7 @@ * @problem.severity error * @tags external/misra/id/rule-21-5 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-21-6/StandardLibraryInputoutputFunctionsUsed.ql b/c/misra/src/rules/RULE-21-6/StandardLibraryInputoutputFunctionsUsed.ql index 6ef8c84cfe..6395ddc5ac 100644 --- a/c/misra/src/rules/RULE-21-6/StandardLibraryInputoutputFunctionsUsed.ql +++ b/c/misra/src/rules/RULE-21-6/StandardLibraryInputoutputFunctionsUsed.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-21-6 * security * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-21-7/AtofAtoiAtolAndAtollOfStdlibhUsed.ql b/c/misra/src/rules/RULE-21-7/AtofAtoiAtolAndAtollOfStdlibhUsed.ql index f834201cbd..ce781403b1 100644 --- a/c/misra/src/rules/RULE-21-7/AtofAtoiAtolAndAtollOfStdlibhUsed.ql +++ b/c/misra/src/rules/RULE-21-7/AtofAtoiAtolAndAtollOfStdlibhUsed.ql @@ -8,18 +8,16 @@ * @problem.severity error * @tags external/misra/id/rule-21-7 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra +import codingstandards.cpp.rules.atofatoiatolandatollused.AtofAtoiAtolAndAtollUsed -private string atoi() { result = ["atof", "atoi", "atol", "atoll"] } - -from FunctionCall fc, Function f -where - not isExcluded(fc, BannedPackage::atofAtoiAtolAndAtollOfStdlibhUsedQuery()) and - f = fc.getTarget() and - f.getName() = atoi() and - f.getFile().getBaseName() = "stdlib.h" -select fc, "Call to banned function " + f.getName() + "." +class AtofAtoiAtolAndAtollOfStdlibhUsedQuery extends AtofAtoiAtolAndAtollUsedSharedQuery { + AtofAtoiAtolAndAtollOfStdlibhUsedQuery() { + this = BannedPackage::atofAtoiAtolAndAtollOfStdlibhUsedQuery() + } +} diff --git a/c/misra/src/rules/RULE-21-8/TerminationFunctionsOfStdlibhUsed.ql b/c/misra/src/rules/RULE-21-8/TerminationFunctionsOfStdlibhUsed.ql index 3414e82ab2..cbc7dd5a92 100644 --- a/c/misra/src/rules/RULE-21-8/TerminationFunctionsOfStdlibhUsed.ql +++ b/c/misra/src/rules/RULE-21-8/TerminationFunctionsOfStdlibhUsed.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-21-8 * correctness * security + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-21-8/TerminationMacrosOfStdlibhUsed.ql b/c/misra/src/rules/RULE-21-8/TerminationMacrosOfStdlibhUsed.ql index 2f83ec6b70..7a911c1525 100644 --- a/c/misra/src/rules/RULE-21-8/TerminationMacrosOfStdlibhUsed.ql +++ b/c/misra/src/rules/RULE-21-8/TerminationMacrosOfStdlibhUsed.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-21-8 * correctness * security + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-21-9/BsearchAndQsortOfStdlibhUsed.ql b/c/misra/src/rules/RULE-21-9/BsearchAndQsortOfStdlibhUsed.ql index b446b7f3f6..6759fa93d1 100644 --- a/c/misra/src/rules/RULE-21-9/BsearchAndQsortOfStdlibhUsed.ql +++ b/c/misra/src/rules/RULE-21-9/BsearchAndQsortOfStdlibhUsed.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-21-9 * security * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-22-1/CloseFileHandleWhenNoLongerNeededMisra.ql b/c/misra/src/rules/RULE-22-1/CloseFileHandleWhenNoLongerNeededMisra.ql index c756bc2526..d888d87b6c 100644 --- a/c/misra/src/rules/RULE-22-1/CloseFileHandleWhenNoLongerNeededMisra.ql +++ b/c/misra/src/rules/RULE-22-1/CloseFileHandleWhenNoLongerNeededMisra.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-22-1 * correctness * security + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-22-1/FreeMemoryWhenNoLongerNeededMisra.ql b/c/misra/src/rules/RULE-22-1/FreeMemoryWhenNoLongerNeededMisra.ql index 1650590559..ca5853dac9 100644 --- a/c/misra/src/rules/RULE-22-1/FreeMemoryWhenNoLongerNeededMisra.ql +++ b/c/misra/src/rules/RULE-22-1/FreeMemoryWhenNoLongerNeededMisra.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-22-1 * correctness * security + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-22-10/OnlyTestErrnoRightAfterErrnoSettingFunction.ql b/c/misra/src/rules/RULE-22-10/OnlyTestErrnoRightAfterErrnoSettingFunction.ql index eab5a0c089..50e5350936 100644 --- a/c/misra/src/rules/RULE-22-10/OnlyTestErrnoRightAfterErrnoSettingFunction.ql +++ b/c/misra/src/rules/RULE-22-10/OnlyTestErrnoRightAfterErrnoSettingFunction.ql @@ -9,6 +9,7 @@ * @problem.severity warning * @tags external/misra/id/rule-22-10 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-22-11/ThreadPreviouslyJoinedOrDetached.ql b/c/misra/src/rules/RULE-22-11/ThreadPreviouslyJoinedOrDetached.ql new file mode 100644 index 0000000000..1a6476b1a7 --- /dev/null +++ b/c/misra/src/rules/RULE-22-11/ThreadPreviouslyJoinedOrDetached.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/thread-previously-joined-or-detached + * @name RULE-22-11: A thread that was previously either joined or detached shall not be subsequently joined nor detached + * @description Joining or detaching a previously joined or detached thread can lead to undefined + * program behavior. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-22-11 + * external/misra/c/2012/amendment4 + * correctness + * concurrency + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.joinordetachthreadonlyonce.JoinOrDetachThreadOnlyOnce + +class ThreadPreviouslyJoinedOrDetachedQuery extends JoinOrDetachThreadOnlyOnceSharedQuery { + ThreadPreviouslyJoinedOrDetachedQuery() { + this = Concurrency6Package::threadPreviouslyJoinedOrDetachedQuery() + } +} diff --git a/c/misra/src/rules/RULE-22-12/NonstandardUseOfThreadingObject.ql b/c/misra/src/rules/RULE-22-12/NonstandardUseOfThreadingObject.ql new file mode 100644 index 0000000000..d92b4ccea6 --- /dev/null +++ b/c/misra/src/rules/RULE-22-12/NonstandardUseOfThreadingObject.ql @@ -0,0 +1,54 @@ +/** + * @id c/misra/nonstandard-use-of-threading-object + * @name RULE-22-12: Standard library threading objects (mutexes, threads, etc.) shall only be accessed by the appropriate Standard Library functions + * @description Thread objects, thread synchronization objects, and thread-specific storage pointers + * shall only be accessed by the appropriate Standard Library functions. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-22-12 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Concurrency +import codingstandards.cpp.Type + +predicate isThreadingObject(Type t) { t instanceof PossiblySpecified::Type } + +predicate validUseOfStdThreadObject(Expr e) { + e.getParent() instanceof AddressOfExpr + or + exists(Call c | + c.getTarget().hasName(["tss_get", "tss_set", "tss_delete"]) and + e = c.getArgument(0) + ) +} + +predicate isStdThreadObjectPtr(Type t) { isThreadingObject(t.(PointerType).getBaseType()) } + +predicate invalidStdThreadObjectUse(Expr e) { + // Invalid use of mtx_t, etc. + isThreadingObject(e.getType()) and + not validUseOfStdThreadObject(e) + or + // Invalid cast from mtx_t* to void*, etc. + isStdThreadObjectPtr(e.getType()) and + exists(Cast cast | + cast.getExpr() = e and + not isStdThreadObjectPtr(cast.getType()) + ) +} + +from Expr e +where + not isExcluded(e, Concurrency8Package::nonstandardUseOfThreadingObjectQuery()) and + invalidStdThreadObjectUse(e) and + // Deduplicate results: (mtx = mtx) is an expression of mtx type, but don't flag the equality + // check, only flag the two `mtx` references. + not invalidStdThreadObjectUse(e.getAChild+()) +select e, "Invalid usage of standard thread object type '" + e.getType().toString() + "'." diff --git a/c/misra/src/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.ql b/c/misra/src/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.ql new file mode 100644 index 0000000000..066cf3c295 --- /dev/null +++ b/c/misra/src/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.ql @@ -0,0 +1,31 @@ +/** + * @id c/misra/threading-object-with-invalid-storage-duration + * @name RULE-22-13: Threading objects (mutexes, threads, etc). shall have not have automatic or thread storage duration + * @description Thread objects, thread synchronization objects, and thread specific storage pointers + * shall have appropriate storage duration. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-22-13 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Objects +import codingstandards.cpp.Concurrency +import codingstandards.cpp.Type + +from ObjectIdentity obj, StorageDuration storageDuration, Type type +where + not isExcluded(obj, Concurrency8Package::threadingObjectWithInvalidStorageDurationQuery()) and + storageDuration = obj.getStorageDuration() and + not storageDuration.isStatic() and + type = obj.getASubObjectType() and + type instanceof PossiblySpecified::Type +select obj, + "Object of type '" + obj.getType().getName() + "' has invalid storage duration type '" + + storageDuration.getStorageTypeName() + "'." diff --git a/c/misra/src/rules/RULE-22-14/MutexInitWithInvalidMutexType.ql b/c/misra/src/rules/RULE-22-14/MutexInitWithInvalidMutexType.ql new file mode 100644 index 0000000000..a122a0bec4 --- /dev/null +++ b/c/misra/src/rules/RULE-22-14/MutexInitWithInvalidMutexType.ql @@ -0,0 +1,36 @@ +/** + * @id c/misra/mutex-init-with-invalid-mutex-type + * @name RULE-22-14: Mutexes shall be initialized with a valid mutex type + * @description Mutexes shall be initialized with a valid mutex type. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-22-14 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Concurrency + +predicate isBaseMutexType(EnumConstantAccess access) { + access.getTarget().hasName(["mtx_plain", "mtx_timed"]) +} + +predicate isValidMutexType(Expr expr) { + isBaseMutexType(expr) + or + exists(BinaryBitwiseOperation binOr | binOr = expr | + isBaseMutexType(binOr.getLeftOperand()) and + binOr.getRightOperand().(EnumConstantAccess).getTarget().hasName("mtx_recursive") + ) +} + +from C11MutexSource init +where + not isExcluded(init, Concurrency8Package::mutexInitWithInvalidMutexTypeQuery()) and + not isValidMutexType(init.getMutexTypeExpr()) +select init, "Mutex initialized with incorrect type expression." diff --git a/c/misra/src/rules/RULE-22-14/MutexInitializedInsideThread.ql b/c/misra/src/rules/RULE-22-14/MutexInitializedInsideThread.ql new file mode 100644 index 0000000000..497fdaf14d --- /dev/null +++ b/c/misra/src/rules/RULE-22-14/MutexInitializedInsideThread.ql @@ -0,0 +1,26 @@ +/** + * @id c/misra/mutex-initialized-inside-thread + * @name RULE-22-14: Thread synchronization objects shall be initialized deterministically + * @description Mutex and condition objects initialized inside of threads may result in + * indeterministic state. + * @kind problem + * @precision high + * @problem.severity recommendation + * @tags external/misra/id/rule-22-14 + * readability + * maintainability + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Concurrency + +from C11MutexSource mutexCreate, ThreadedFunction thread +where + not isExcluded(mutexCreate, Concurrency8Package::mutexInitializedInsideThreadQuery()) and + thread.calls*(mutexCreate.getEnclosingFunction()) +select mutexCreate, "Mutex initialization reachable from threaded function '$@'.", thread, + thread.getName() diff --git a/c/misra/src/rules/RULE-22-14/MutexNotInitializedBeforeUse.ql b/c/misra/src/rules/RULE-22-14/MutexNotInitializedBeforeUse.ql new file mode 100644 index 0000000000..f78c25f981 --- /dev/null +++ b/c/misra/src/rules/RULE-22-14/MutexNotInitializedBeforeUse.ql @@ -0,0 +1,78 @@ +/** + * @id c/misra/mutex-not-initialized-before-use + * @name RULE-22-14: Thread synchronization objects shall be initialized before being accessed + * @description Mutex and condition objects shall be initialized with the standard library functions + * before using them. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-22-14 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Objects +import codingstandards.cpp.Concurrency +import codingstandards.cpp.Type +import codingstandards.c.initialization.GlobalInitializationAnalysis + +module MutexInitializationConfig implements GlobalInitializationAnalysisConfigSig { + ObjectIdentity getAnInitializedObject(Expr e) { + e.(C11MutexSource).getMutexExpr() = result.getASubobjectAddressExpr() + } + + ObjectIdentity getAUsedObject(Expr e) { + result.getASubobjectAddressExpr() = e and + ( + exists(CMutexFunctionCall mutexUse | e = mutexUse.getLockExpr()) + or + exists(CConditionOperation condOp | e = condOp.getMutexExpr()) + ) + } +} + +module ConditionInitializationConfig implements GlobalInitializationAnalysisConfigSig { + ObjectIdentity getAnInitializedObject(Expr e) { + exists(CConditionOperation condOp | + e = condOp and + condOp.isInit() and + condOp.getConditionExpr() = result.getASubobjectAddressExpr() + ) + } + + ObjectIdentity getAUsedObject(Expr e) { + result.getASubobjectAddressExpr() = e and + exists(CConditionOperation condOp | + condOp.isUse() and + e = condOp.getConditionExpr() + ) + } +} + +import GlobalInitalizationAnalysis as MutexInitAnalysis +import GlobalInitalizationAnalysis as CondInitAnalysis + +from Expr objUse, ObjectIdentity obj, Function callRoot, string typeString, string description +where + not isExcluded(objUse, Concurrency8Package::mutexNotInitializedBeforeUseQuery()) and + ( + MutexInitAnalysis::uninitializedFrom(objUse, obj, callRoot) and + typeString = "Mutex" + or + CondInitAnalysis::uninitializedFrom(objUse, obj, callRoot) and + typeString = "Condition" + ) and + ( + if + obj.getType() instanceof PossiblySpecified::Type or + obj.getType() instanceof PossiblySpecified::Type + then description = typeString + else description = typeString + " in object" + ) +select objUse, + description + " '$@' possibly used before initialization, from entry point function '$@'.", obj, + obj.toString(), callRoot, callRoot.getName() diff --git a/c/misra/src/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.ql b/c/misra/src/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.ql new file mode 100644 index 0000000000..ec4631ef1b --- /dev/null +++ b/c/misra/src/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.ql @@ -0,0 +1,113 @@ +/** + * @id c/misra/thread-resource-disposed-before-threads-joined + * @name RULE-22-15: Thread synchronization objects and thread-specific storage pointers shall not be disposed unsafely + * @description Thread synchronization objects and thread-specific storage pointers shall not be + * destroyed until after all threads accessing them have terminated. + * @kind problem + * @precision medium + * @problem.severity error + * @tags external/misra/id/rule-22-15 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.SubObjects +import codingstandards.cpp.Concurrency + +newtype TThreadKind = + TSpawned(C11ThreadCreateCall tcc) or + TMainThread() + +TThreadKind getThreadKind(FunctionCall operation) { + if + not exists(C11ThreadCreateCall tcc | + getAThreadContextAwareSuccessor(tcc.getFunction().getEntryPoint()) = operation + ) + then result = TMainThread() + else + exists(C11ThreadCreateCall tcc | + getAThreadContextAwareSuccessor(tcc.getFunction().getEntryPoint()) = operation and + result = TSpawned(tcc) + ) +} + +bindingset[tcc, thread] +predicate followsMainThreadTcc(C11ThreadCreateCall tcc, TThreadKind thread) { + thread = TMainThread() + or + exists(C11ThreadCreateCall tcc2 | + getAThreadContextAwareSuccessor(tcc) = tcc2 and + thread = TSpawned(tcc2) + ) +} + +string describeThread(TThreadKind thread) { + thread = TMainThread() and + result = "main thread" + or + exists(C11ThreadCreateCall tcc2 | + thread = TSpawned(tcc2) and + result = tcc2.getFunction().getName() + ) +} + +bindingset[alternative] +Element elementOr(TThreadKind thread, Element alternative) { + thread = TMainThread() and + result = alternative + or + exists(C11ThreadCreateCall tcc2 | + thread = TSpawned(tcc2) and + result = tcc2 + ) +} + +from + FunctionCall dispose, FunctionCall use, C11ThreadCreateCall tcc, TThreadKind disposeThread, + TThreadKind useThread, SubObject usedAndDestroyed +where + not isExcluded(dispose, Concurrency9Package::threadResourceDisposedBeforeThreadsJoinedQuery()) and + // `tcc` may be the thread that uses the resource, or the thread that disposes it. What matters + // for the query is that `tcc` is before the use and the dispose. + dispose = getAThreadContextAwareSuccessor(tcc) and + ( + // Lock and dispose of mtx_t: + exists(CMutexFunctionCall mfc, C11MutexDestroyer md | dispose = md and use = mfc | + mfc = getAThreadContextAwareSuccessor(tcc) and + mfc.getLockExpr() = usedAndDestroyed.getAnAddressOfExpr() and + md.getMutexExpr() = usedAndDestroyed.getAnAddressOfExpr() + ) + or + // Read/store and dispose of tss_t: + exists(ThreadSpecificStorageFunctionCall tssfc, TSSDeleteFunctionCall td | + dispose = td and use = tssfc + | + tssfc = getAThreadContextAwareSuccessor(tcc) and + tssfc.getKey() = usedAndDestroyed.getAnAddressOfExpr() and + td.getKey() = usedAndDestroyed.getAnAddressOfExpr() + ) + or + // Wait and dispose of cnd_t: + exists(CConditionOperation cndop, C11ConditionDestroyer cd | dispose = cd and use = cndop | + cndop = getAThreadContextAwareSuccessor(tcc) and + cndop.getConditionExpr() = usedAndDestroyed.getAnAddressOfExpr() and + cd.getConditionExpr() = usedAndDestroyed.getAnAddressOfExpr() + ) + ) and + // Dispose could be in the main thread or in a spawned thread. + disposeThread = getThreadKind(dispose) and + // Dispose could be in the main thread or in a spawned thread. + useThread = getThreadKind(use) and + // Exclude a thread that does not concurrently share the resource it disposed (unlikely). + not useThread = disposeThread and + followsMainThreadTcc(tcc, useThread) and + followsMainThreadTcc(tcc, disposeThread) and + // If there is a join between the use and the dispose, the code is compliant. + not getAThreadContextAwarePredecessor(elementOr(useThread, use), dispose) instanceof C11ThreadWait +select dispose, "Thread resource $@ disposed before joining thread $@ which uses it.", + usedAndDestroyed.getRootIdentity(), usedAndDestroyed.toString(), elementOr(useThread, use), + describeThread(useThread) diff --git a/c/misra/src/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.ql b/c/misra/src/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.ql new file mode 100644 index 0000000000..c86c9b9d9d --- /dev/null +++ b/c/misra/src/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.ql @@ -0,0 +1,52 @@ +/** + * @id c/misra/mutex-objects-not-always-unlocked + * @name RULE-22-16: All mutex objects locked by a thread shall be explicitly unlocked by the same thread + * @description Mutex not unlocked by thread on all execution paths in current thread after being + * locked. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-22-16 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Concurrency +import codingstandards.cpp.resources.ResourceLeakAnalysis + +module MutexLeakConfig implements ResourceLeakConfigSig { + predicate isAllocate(ControlFlowNode allocPoint, DataFlow::Node node) { + exists(MutexFunctionCall lock | + allocPoint = lock and + lock.isLock() and + node.asDefiningArgument() = lock.getLockExpr() + ) + } + + predicate isFree(ControlFlowNode node, DataFlow::Node resource) { + exists(MutexFunctionCall mfc | + node = mfc and + mfc.isUnlock() and + mfc.getLockExpr() = resource.asExpr() + ) + } +} + +string describeMutex(Expr mutexExpr) { + if mutexExpr instanceof AddressOfExpr + then result = mutexExpr.(AddressOfExpr).getOperand().toString() + else result = mutexExpr.toString() +} + +from MutexFunctionCall lockCall, string mutexDescription +where + not isExcluded(lockCall, Concurrency8Package::mutexObjectsNotAlwaysUnlockedQuery()) and + //lockCall.getLockExpr() = mutexNode.asDefiningArgument() and + exists(ResourceLeak::getALeak(lockCall)) and + mutexDescription = describeMutex(lockCall.getLockExpr()) +select lockCall, + "Mutex '" + mutexDescription + "' is locked here and may not always be subsequently unlocked." diff --git a/c/misra/src/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.ql b/c/misra/src/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.ql new file mode 100644 index 0000000000..d85183a831 --- /dev/null +++ b/c/misra/src/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.ql @@ -0,0 +1,67 @@ +/** + * @id c/misra/invalid-operation-on-unlocked-mutex + * @name RULE-22-17: No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it has not locked + * @description No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it + * has not locked before. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-22-17 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.SubObjects +import codingstandards.cpp.Concurrency +import codingstandards.cpp.dominance.BehavioralSet + +/* A call to mtx_unlock() or cnd_wait() or cnd_timedwait(), which require a locked mutex */ +class RequiresLockOperation extends FunctionCall { + SubObject mutex; + + RequiresLockOperation() { + exists(CMutexFunctionCall mutexCall | this = mutexCall | + mutexCall.isUnlock() and + mutex.getAnAddressOfExpr() = mutexCall.getLockExpr() + ) + or + exists(CConditionOperation condOp | this = condOp | + mutex.getAnAddressOfExpr() = condOp.getMutexExpr() + ) + } + + SubObject getMutex() { result = mutex } +} + +/* A config to search for a dominating set that locks the mutex before the operation */ +module LockDominatingSetConfig implements DominatingSetConfigSig { + predicate isTargetBehavior(ControlFlowNode node, RequiresLockOperation op) { + exists(CMutexFunctionCall mutexCall | node = mutexCall | + mutexCall.isLock() and + mutexCall.getLockExpr() = op.getMutex().getAnAddressOfExpr() + ) + } + + predicate isBlockingBehavior(ControlFlowNode node, RequiresLockOperation op) { + // If we find a branch that explicitly unlocks the mutex, we should not look for an earlier + // call to lock that mutex. + exists(CMutexFunctionCall mutexCall | node = mutexCall | + mutexCall.isUnlock() and + mutexCall.getLockExpr() = op.getMutex().getAnAddressOfExpr() + ) + } +} + +import DominatingBehavioralSet as DominatingSet + +from RequiresLockOperation operation, SubObject mutex +where + not isExcluded(operation, Concurrency9Package::invalidOperationOnUnlockedMutexQuery()) and + mutex = operation.getMutex() and + not DominatingSet::isDominatedByBehavior(operation) +select operation, "Invalid operation on mutex '$@' not locked by the current thread.", + mutex.getRootIdentity(), mutex.toString() diff --git a/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.ql b/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.ql new file mode 100644 index 0000000000..17762b3eee --- /dev/null +++ b/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.ql @@ -0,0 +1,37 @@ +/** + * @id c/misra/non-recursive-mutex-recursively-locked + * @name RULE-22-18: Non-recursive mutexes shall not be recursively locked + * @description Mutexes initialized with mtx_init() without mtx_recursive shall not be locked by a + * thread that has previously locked it. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-22-18 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.SubObjects +import codingstandards.cpp.Concurrency +import codingstandards.cpp.Type + +from + LockProtectedControlFlowNode n, CMutexFunctionCall lockCall, SubObject mutex, + CMutexFunctionCall coveredByLock +where + not isExcluded(n, Concurrency9Package::nonRecursiveMutexRecursivelyLockedQuery()) and + lockCall = n and + coveredByLock = n.coveredByLock() and + not coveredByLock = lockCall and + mutex.isPrecise() and + coveredByLock.getLockExpr() = mutex.getAnAddressOfExpr() and + lockCall.getLockExpr() = mutex.getAnAddressOfExpr() and + forex(C11MutexSource init | init.getMutexExpr() = mutex.getAnAddressOfExpr() | + not init.isRecursive() + ) +select n, "Non-recursive mutex " + mutex.toString() + " locked after it is $@.", coveredByLock, + "already locked" diff --git a/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql b/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql new file mode 100644 index 0000000000..7e002585b6 --- /dev/null +++ b/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql @@ -0,0 +1,60 @@ +/** + * @id c/misra/non-recursive-mutex-recursively-locked-audit + * @name RULE-22-18: (Audit) Non-recursive mutexes shall not be recursively locked + * @description Mutexes that may be initialized without mtx_recursive shall not be locked by a + * thread that may have previously locked it. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-22-18 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/audit + * external/misra/obligation/required + */ + +import cpp +import codeql.util.Boolean +import codingstandards.c.misra +import codingstandards.c.SubObjects +import codingstandards.cpp.Concurrency +import codingstandards.cpp.Type + +predicate isTrackableMutex(CMutexFunctionCall lockCall, Boolean recursive) { + exists(SubObject mutex | + lockCall.getLockExpr() = mutex.getAnAddressOfExpr() and + mutex.isPrecise() and + forex(C11MutexSource init | init.getMutexExpr() = mutex.getAnAddressOfExpr() | + if init.isRecursive() then recursive = true else recursive = false + ) + ) +} + +predicate definitelyDifferentMutexes(CMutexFunctionCall lockCall, CMutexFunctionCall coveredByLock) { + exists(SubObject a, SubObject b | + lockCall.getLockExpr() = a.getAnAddressOfExpr() and + coveredByLock.getLockExpr() = b.getAnAddressOfExpr() and + not a = b + ) +} + +from LockProtectedControlFlowNode n, CMutexFunctionCall lockCall, CMutexFunctionCall coveredByLock +where + not isExcluded(n, Concurrency9Package::nonRecursiveMutexRecursivelyLockedAuditQuery()) and + lockCall = n and + coveredByLock = n.coveredByLock() and + not coveredByLock = lockCall and + // If mutexes are provably different objects, they do not need to be audited + not definitelyDifferentMutexes(lockCall, coveredByLock) and + ( + // If either mutex is not trackable, it should be audited + not isTrackableMutex(lockCall, _) or + not isTrackableMutex(coveredByLock, _) + ) and + not ( + // If either mutex is definitely recursive, it does not need to be audited + isTrackableMutex(lockCall, true) or + isTrackableMutex(coveredByLock, true) + ) +select n, "Mutex locked after it was already $@.", coveredByLock, "previously locked" diff --git a/c/misra/src/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.ql b/c/misra/src/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.ql new file mode 100644 index 0000000000..0d5aa5399f --- /dev/null +++ b/c/misra/src/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.ql @@ -0,0 +1,69 @@ +/** + * @id c/misra/condition-variable-used-with-multiple-mutexes + * @name RULE-22-19: A condition variable shall be associated with at most one mutex object + * @description Standard library functions cnd_wait() and cnd_timedwait() shall specify the same + * mutex object for each condition object in all calls. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-22-19 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.SubObjects +import codingstandards.cpp.Concurrency + +bindingset[cond, mutex] +int countMutexesForConditionVariable(SubObject cond, SubObject mutex) { + result = + count(CConditionOperation call | + call.getConditionExpr() = cond.getAnAddressOfExpr() and + call.getMutexExpr() = mutex.getAnAddressOfExpr() + ) +} + +bindingset[cond, mutex] +predicate conditionVariableUsesMutex(SubObject cond, SubObject mutex) { + countMutexesForConditionVariable(cond, mutex) > 0 +} + +bindingset[cond, n] +SubObject nthMutexForConditionVariable(SubObject cond, int n) { + result = + rank[n](SubObject mutex | + conditionVariableUsesMutex(cond, mutex) + | + mutex order by countMutexesForConditionVariable(cond, mutex), mutex.toString() + ) +} + +bindingset[cond, mutex] +CConditionOperation firstCallForConditionMutex(SubObject cond, SubObject mutex) { + result = + rank[1](CConditionOperation call | + call.getConditionExpr() = cond.getAnAddressOfExpr() and + call.getMutexExpr() = mutex.getAnAddressOfExpr() + | + call order by call.getFile().getAbsolutePath(), call.getLocation().getStartLine() + ) +} + +from + SubObject cond, CConditionOperation useOne, SubObject mutexOne, CConditionOperation useTwo, + SubObject mutexTwo +where + not isExcluded(cond.getRootIdentity(), + Concurrency9Package::conditionVariableUsedWithMultipleMutexesQuery()) and + mutexOne = nthMutexForConditionVariable(cond, 1) and + mutexTwo = nthMutexForConditionVariable(cond, 2) and + useOne = firstCallForConditionMutex(cond, mutexOne) and + useTwo = firstCallForConditionMutex(cond, mutexOne) +select useOne, + "Condition variable $@ associated with multiple mutexes, operation uses mutex $@ while $@ uses other mutex $@.", + cond.getRootIdentity(), cond.toString(), mutexOne.getRootIdentity(), mutexOne.toString(), useTwo, + "another operation", mutexTwo.getRootIdentity(), mutexTwo.toString() diff --git a/c/misra/src/rules/RULE-22-2/OnlyFreeMemoryAllocatedDynamicallyMisra.ql b/c/misra/src/rules/RULE-22-2/OnlyFreeMemoryAllocatedDynamicallyMisra.ql index a149103c9a..cdbe8e2c16 100644 --- a/c/misra/src/rules/RULE-22-2/OnlyFreeMemoryAllocatedDynamicallyMisra.ql +++ b/c/misra/src/rules/RULE-22-2/OnlyFreeMemoryAllocatedDynamicallyMisra.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-22-2 * correctness * security + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/mandatory */ diff --git a/c/misra/src/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.ql b/c/misra/src/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.ql new file mode 100644 index 0000000000..1edf4aa9c3 --- /dev/null +++ b/c/misra/src/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.ql @@ -0,0 +1,44 @@ +/** + * @id c/misra/thread-storage-not-initialized-before-use + * @name RULE-22-20: Thread-specific storage pointers shall be created before being accessed + * @description Thread specific storage pointers shall be initialized with the standard library + * functions before using them. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-22-20 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Objects +import codingstandards.cpp.Concurrency +import codingstandards.cpp.Type +import codingstandards.c.initialization.GlobalInitializationAnalysis + +module ThreadStoreInitializationConfig implements GlobalInitializationAnalysisConfigSig { + ObjectIdentity getAnInitializedObject(Expr e) { + e.(TSSCreateFunctionCall).getKey() = result.getASubobjectAddressExpr() + } + + ObjectIdentity getAUsedObject(Expr e) { + result.getASubobjectAddressExpr() = e and + exists(ThreadSpecificStorageFunctionCall use | + not use instanceof TSSCreateFunctionCall and e = use.getKey() + ) + } +} + +import GlobalInitalizationAnalysis as InitAnalysis + +from Expr objUse, ObjectIdentity obj, Function callRoot +where + not isExcluded(objUse, Concurrency9Package::threadStorageNotInitializedBeforeUseQuery()) and + InitAnalysis::uninitializedFrom(objUse, obj, callRoot) +select objUse, + "Thread specific storage pointer '$@' used before initialization from entry point function '$@'.", + obj, obj.toString(), callRoot, callRoot.getName() diff --git a/c/misra/src/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.ql b/c/misra/src/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.ql new file mode 100644 index 0000000000..3c40ea7116 --- /dev/null +++ b/c/misra/src/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.ql @@ -0,0 +1,27 @@ +/** + * @id c/misra/thread-storage-pointer-initialized-inside-thread + * @name RULE-22-20: Thread specific storage pointers shall be initialized deterministically + * @description Thread specific storage pointers initialized inside of threads may result in + * indeterministic state. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-22-20 + * readability + * maintainability + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Concurrency + +from TSSCreateFunctionCall tssCreate, ThreadedFunction thread +where + not isExcluded(tssCreate, Concurrency8Package::mutexInitializedInsideThreadQuery()) and + thread.calls*(tssCreate.getEnclosingFunction()) +select tssCreate, + "Thread specific storage object initialization reachable from threaded function '$@'.", thread, + thread.getName() diff --git a/c/misra/src/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.ql b/c/misra/src/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.ql index c01afea39f..642813bbab 100644 --- a/c/misra/src/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.ql +++ b/c/misra/src/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.ql @@ -8,13 +8,14 @@ * @problem.severity error * @tags external/misra/id/rule-22-3 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra import codingstandards.cpp.standardlibrary.FileAccess -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.valuenumbering.GlobalValueNumbering import semmle.code.cpp.controlflow.SubBasicBlocks diff --git a/c/misra/src/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.ql b/c/misra/src/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.ql index 6dc3b3ee71..2439d4ca47 100644 --- a/c/misra/src/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.ql +++ b/c/misra/src/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.ql @@ -7,13 +7,14 @@ * @problem.severity error * @tags external/misra/id/rule-22-4 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/mandatory */ import cpp import codingstandards.c.misra import codingstandards.cpp.standardlibrary.FileAccess -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow module FileDFConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { diff --git a/c/misra/src/rules/RULE-22-5/PointerToAFileObjectDereferenced.ql b/c/misra/src/rules/RULE-22-5/PointerToAFileObjectDereferenced.ql index 86e0b76e21..05cc4e3433 100644 --- a/c/misra/src/rules/RULE-22-5/PointerToAFileObjectDereferenced.ql +++ b/c/misra/src/rules/RULE-22-5/PointerToAFileObjectDereferenced.ql @@ -7,6 +7,7 @@ * @problem.severity error * @tags external/misra/id/rule-22-5 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/mandatory */ diff --git a/c/misra/src/rules/RULE-22-6/FileUsedAfterClosed.ql b/c/misra/src/rules/RULE-22-6/FileUsedAfterClosed.ql index 78c5063ddd..64318dbedd 100644 --- a/c/misra/src/rules/RULE-22-6/FileUsedAfterClosed.ql +++ b/c/misra/src/rules/RULE-22-6/FileUsedAfterClosed.ql @@ -7,6 +7,7 @@ * @problem.severity error * @tags external/misra/id/rule-22-6 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/mandatory */ diff --git a/c/misra/src/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.ql b/c/misra/src/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.ql index 307357a93a..1da495ca28 100644 --- a/c/misra/src/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.ql +++ b/c/misra/src/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.ql @@ -8,12 +8,14 @@ * @problem.severity error * @tags external/misra/id/rule-22-7 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra import codingstandards.cpp.ReadErrorsAndEOF +import semmle.code.cpp.dataflow.DataFlow /** * The getchar() return value propagates directly to a check against EOF macro diff --git a/c/misra/src/rules/RULE-22-8/ErrnoSetToZeroPriorToCall.ql b/c/misra/src/rules/RULE-22-8/ErrnoSetToZeroPriorToCall.ql index de9a083545..6a39070ef0 100644 --- a/c/misra/src/rules/RULE-22-8/ErrnoSetToZeroPriorToCall.ql +++ b/c/misra/src/rules/RULE-22-8/ErrnoSetToZeroPriorToCall.ql @@ -9,6 +9,7 @@ * @problem.severity error * @tags external/misra/id/rule-22-8 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-22-9/ErrnoSetToZeroAfterCall.ql b/c/misra/src/rules/RULE-22-9/ErrnoSetToZeroAfterCall.ql index da4504b75b..274bf5b2ae 100644 --- a/c/misra/src/rules/RULE-22-9/ErrnoSetToZeroAfterCall.ql +++ b/c/misra/src/rules/RULE-22-9/ErrnoSetToZeroAfterCall.ql @@ -8,6 +8,7 @@ * @problem.severity error * @tags external/misra/id/rule-22-9 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.ql b/c/misra/src/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.ql new file mode 100644 index 0000000000..1a76339f50 --- /dev/null +++ b/c/misra/src/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.ql @@ -0,0 +1,27 @@ +/** + * @id c/misra/generic-selection-doesnt-depend-on-macro-argument + * @name RULE-23-1: A generic selection should depend on the type of a macro argument + * @description A generic selection should depend on the type of a macro argument. + * @kind problem + * @precision high + * @problem.severity warning + * @tags external/misra/id/rule-23-1 + * correctness + * maintainability + * external/misra/c/2012/amendment3 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Generic + +from ParsedGenericMacro macro, string ctrlExpr +where + not isExcluded(macro, GenericsPackage::genericSelectionDoesntDependOnMacroArgumentQuery()) and + ctrlExpr = macro.getControllingExprString() and + // No parameter exists that is expanded in the controlling expression one or more times + not exists(string parameter | macro.expansionsInsideControllingExpr(parameter) > 0) +select macro, + "Generic macro " + macro.getName() + " doesn't refer to a macro parameter in controlling expr '" + + ctrlExpr + "'." diff --git a/c/misra/src/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.ql b/c/misra/src/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.ql new file mode 100644 index 0000000000..603c44e8e1 --- /dev/null +++ b/c/misra/src/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/generic-selection-not-expanded-from-a-macro + * @name RULE-23-1: A generic selection should only be expanded from a macro + * @description A generic selection should only be expanded from a macro. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-23-1 + * maintainability + * external/misra/c/2012/amendment3 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra + +from C11GenericExpr generic, Expr ctrlExpr +where + not isExcluded(generic, GenericsPackage::genericSelectionNotExpandedFromAMacroQuery()) and + ctrlExpr = generic.getControllingExpr() and + not exists(MacroInvocation mi | mi.getAGeneratedElement() = generic.getExpr()) +select generic, "$@ in generic expression does not expand a macro parameter.", ctrlExpr, + "Controlling expression" diff --git a/c/misra/src/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.ql b/c/misra/src/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.ql new file mode 100644 index 0000000000..d7fcb13d76 --- /dev/null +++ b/c/misra/src/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.ql @@ -0,0 +1,88 @@ +/** + * @id c/misra/generic-selection-not-from-macro-with-side-effects + * @name RULE-23-2: A generic selection shall not contain side-effects if it is not expanded from a macro + * @description A generic selection that is not expanded from a macro shall not contain potential + * side effects in the controlling expression. + * @kind problem + * @precision high + * @problem.severity warning + * @tags external/misra/id/rule-23-2 + * maintainability + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Generic +import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.DefaultEffects +import codingstandards.cpp.alertreporting.DeduplicateMacroResults + +class GenericWithNonMacroSideEffect extends C11GenericExpr { + SideEffect sideEffect; + + GenericWithNonMacroSideEffect() { + not exists(MacroInvocation mi | + mi.getAGeneratedElement() = getExpr() and + mi.getMacro().(GenericMacro).hasControllingExprFromMacroParameter() + ) and + sideEffect = getASideEffect(getControllingExpr()) + } + + SideEffect getASideEffect() { result = sideEffect } +} + +module GenericSideEffectConfig implements DeduplicateMacroConfigSig { + string describe(GenericWithNonMacroSideEffect e) { + result = "side effect '" + e.getASideEffect() + "'" + } +} + +module GenericSideEffectReportConfig implements MacroReportConfigSig { + /* Create a message to describe this macro, with a string describing its `ResultElement`. */ + bindingset[description] + string getMessageSameResultInAllExpansions(Macro m, string description) { + result = + "Generic selection macro " + m.getName() + " contains a " + description + + ", which is not from macro invocation arguments." + } + + /* Create a message to describe this macro, using '$@' to describe an example `ResultElement`. */ + string getMessageVariedResultInAllExpansions(Macro m) { + result = + "Generic selection in macro " + m.getName() + + " contains an invocation-dependent side effect which is not from macro invocation arguments, for example $@." + } + + /** + * Create a message to describe this macro expansion which produces a `ResultElement`, using '$@' + * to describe the relevant macro. + */ + string getMessageResultInIsolatedExpansion(GenericWithNonMacroSideEffect element) { + // A result in an isolated expansion indicates that the side effect is not always present when + // macro is expanded, and therefore the side-effect is not in the macro definition but rather + // originates in one of the macro arguments. + none() + } + + /** + * Create a message to describe a `ResultElement` which is not generated by a macro expansion. + */ + string getMessageNotInMacro( + GenericWithNonMacroSideEffect element, Locatable optLoc1, string optStr1 + ) { + // Generics which are not expanded from a macro aren't applicable to this rule. + none() + } +} + +import DeduplicateMacroResults as Deduplicate +import Deduplicate::Report as Report + +from Report::ReportResult res +where + not isExcluded(res.getPrimaryElement(), + GenericsPackage::genericSelectionNotFromMacroWithSideEffectsQuery()) +select res.getPrimaryElement(), res.getMessage(), res.getOptionalPlaceholderLocatable(), + res.getOptionalPlaceholderMessage() diff --git a/c/misra/src/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.ql b/c/misra/src/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.ql new file mode 100644 index 0000000000..dc4ab081d3 --- /dev/null +++ b/c/misra/src/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.ql @@ -0,0 +1,36 @@ +/** + * @id c/misra/generic-without-non-default-association + * @name RULE-23-3: A generic selection should contain at least one non-default association + * @description A generic selection should contain at least one non-default association. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-23-3 + * correctness + * maintainability + * external/misra/c/2012/amendment3 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.AlertReporting + +class InvalidGeneric extends C11GenericExpr { + InvalidGeneric() { + not exists(Type t | + t = getAnAssociationType() and + not t instanceof VoidType + ) + } +} + +from InvalidGeneric generic, Element primaryElement +where + not isExcluded(primaryElement, GenericsPackage::genericWithoutNonDefaultAssociationQuery()) and + not exists(Type t | + t = generic.getAnAssociationType() and + not t instanceof VoidType + ) and + primaryElement = MacroUnwrapper::unwrapElement(generic) +select primaryElement, "Generic selection contains no non-default association." diff --git a/c/misra/src/rules/RULE-23-4/GenericAssociationWithUnselectableType.ql b/c/misra/src/rules/RULE-23-4/GenericAssociationWithUnselectableType.ql new file mode 100644 index 0000000000..2d707548fa --- /dev/null +++ b/c/misra/src/rules/RULE-23-4/GenericAssociationWithUnselectableType.ql @@ -0,0 +1,111 @@ +/** + * @id c/misra/generic-association-with-unselectable-type + * @name RULE-23-4: A generic association shall list an appropriate type + * @description Generic selections undergo lvalue conversion before type comparison, leading to + * certain types being impossible to select. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-23-4 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.types.LvalueConversion +import codingstandards.cpp.types.Graph +import codingstandards.cpp.alertreporting.DeduplicateMacroResults + +/** + * Check if a type contains an unmatchable anonymous struct or union. + * + * Anonymous structs and unions are only equal to themselves. So any anonymous struct, or compound + * type containing an anonymous struct, is unmatchable. + * + * However, there is an exception if the anonymous struct is behind a typedef. All uses of that + * typedef will resolve to the same anonymous struct, and so the typedef is matchable. + */ +predicate containsAnonymousType(Type t) { + t.(Struct).isAnonymous() + or + not t instanceof TypedefType and + exists(Type next | typeGraph(t, next) | containsAnonymousType(next)) +} + +predicate invalidType(Type t, string reason) { + containsAnonymousType(t) and + reason = "containing an anonymous struct or union type" + or + exists(performLvalueConversion(t, reason)) +} + +class InvalidSelection extends Expr { + Type selectionType; + int idx; + C11GenericExpr generic; + string reason; + + InvalidSelection() { + this = generic.getAssociationExpr(idx) and + selectionType = generic.getAssociationType(idx) and + invalidType(selectionType, reason) + } + + Type getSelectionType() { result = selectionType } + + string getReason() { result = reason } +} + +module InvalidSelectionConfig implements DeduplicateMacroConfigSig { + string describe(InvalidSelection e) { + result = "'" + e.getSelectionType().toString() + "', due to " + e.getReason() + } +} + +import InvalidSelectionConfig + +module InvalidSelectionReportConfig implements MacroReportConfigSig { + /* Create a message to describe this macro, with a string describing its `ResultElement`. */ + bindingset[description] + string getMessageSameResultInAllExpansions(Macro m, string description) { + result = "Generic in macro " + m.getName() + " has unselectable type " + description + "." + } + + /* Create a message to describe this macro, using '$@' to describe an example `ResultElement`. */ + string getMessageVariedResultInAllExpansions(Macro m) { + result = + "Generic in macro " + m.getName() + + " has an invocation-dependent unselectable type, for example $@." + } + + /** + * Create a message to describe this macro expansion which produces a `ResultElement`, using '$@' + * to describe the relevant macro. + */ + string getMessageResultInIsolatedExpansion(InvalidSelection element) { + result = + "Generic resulting from invocation of macro $@ contains an unselectable type " + + describe(element) + "." + } + + /** + * Create a message to describe a `ResultElement` which is not generated by a macro expansion. + */ + string getMessageNotInMacro(InvalidSelection element, Locatable optLoc1, string optStr1) { + result = "Generic selection uses unselectable type " + describe(element) + "'." and + optLoc1 = element and + optStr1 = "side effect" + } +} + +import DeduplicateMacroResults as Deduplicate +import Deduplicate::Report as Report + +from Report::ReportResult res +where + not isExcluded(res.getPrimaryElement(), + GenericsPackage::genericSelectionNotFromMacroWithSideEffectsQuery()) +select res.getPrimaryElement(), res.getMessage(), res.getOptionalPlaceholderLocatable(), + res.getOptionalPlaceholderMessage() diff --git a/c/misra/src/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.ql b/c/misra/src/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.ql new file mode 100644 index 0000000000..f2961e2638 --- /dev/null +++ b/c/misra/src/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.ql @@ -0,0 +1,74 @@ +/** + * @id c/misra/dangerous-default-selection-for-pointer-in-generic + * @name RULE-23-5: A generic selection should not depend on implicit pointer type conversion + * @description Pointer types in a generic selection do not undergo pointer conversions and should + * not counterintuitively fall through to the default association. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-23-5 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.AlertReporting +import codingstandards.cpp.types.Compatible +import codingstandards.cpp.types.LvalueConversion +import codingstandards.cpp.types.SimpleAssignment + +predicate typesCompatible(Type t1, Type t2) { + TypeEquivalence::equalTypes(t1, t2) +} + +predicate relevantTypes(Type a, Type b) { + exists(C11GenericExpr g | + a = g.getAnAssociationType() and + b = getLvalueConverted(g.getControllingExpr().getFullyConverted().getType()) + ) +} + +predicate missesOnPointerConversion(Type provided, Type expected) { + // The provided type is not compatible with the expected type: + not typesCompatible(provided, expected) and + // But 6.5.16.1 simple assignment constraints would have been satisfied: + ( + // Check as if the controlling expr is assigned to the expected type: + SimpleAssignment::satisfiesSimplePointerAssignment(expected, provided) + or + // Since developers typically rely on the compiler to catch const/non-const assignment + // errors, don't assume a const-to-non-const generic selection miss was intentional. + SimpleAssignment::satisfiesSimplePointerAssignment(provided, expected) + ) +} + +from + C11GenericExpr generic, Expr controllingExpr, Type providedType, Type missedType, + Type lvalueConverted, Element extraElement, string extraString, string extraElementName +where + not isExcluded(generic, GenericsPackage::dangerousDefaultSelectionForPointerInGenericQuery()) and + controllingExpr = generic.getControllingExpr() and + providedType = generic.getControllingExpr().getFullyConverted().getType() and + // The controlling expression undergoes lvalue conversion: + lvalueConverted = getLvalueConverted(providedType) and + // There is no perfect match + not typesCompatible(lvalueConverted, generic.getAnAssociationType()) and + // There is a default selector. + exists(VoidType default | default = generic.getAnAssociationType()) and + missedType = generic.getAnAssociationType() and + missesOnPointerConversion(lvalueConverted, missedType) and + extraElement = MacroUnwrapper::unwrapElement(generic) and + ( + if extraElement instanceof Macro + then ( + extraString = " in generic macro $@" and extraElementName = extraElement.(Macro).getName() + ) else ( + extraString = "" and extraElementName = "" + ) + ) +select generic, + "Generic matched default selection, as controlling argument type " + lvalueConverted.toString() + + " does not undergo pointer conversion to " + missedType.toString() + extraString + ".", + extraElement, extraElementName diff --git a/c/misra/src/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.ql b/c/misra/src/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.ql new file mode 100644 index 0000000000..f02f92b45a --- /dev/null +++ b/c/misra/src/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.ql @@ -0,0 +1,64 @@ +/** + * @id c/misra/generic-expression-with-incorrect-essential-type + * @name RULE-23-6: The controlling expression of a generic selection shall have an essential type that matches its standard type + * @description The controlling expression of a generic selection shall have an essential type that + * matches its standard type. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-23-6 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.misra.EssentialTypes +import codingstandards.cpp.Cpp14Literal +import codingstandards.cpp.AlertReporting + +predicate allowedByException(Expr expr, Type essentialType) { + // Constant expressions + exists(expr.getValue()) and + ( + // with essentially signed or unsigned type + getEssentialTypeCategory(essentialType) = EssentiallySignedType() + or + getEssentialTypeCategory(essentialType) = EssentiallyUnsignedType() + ) and + // with lower rank than `int` + essentialType.getSize() < any(IntType t).getSize() and + // and not a character constant + not expr instanceof Cpp14Literal::CharLiteral +} + +from + C11GenericExpr generic, Expr ctrlExpr, Type ctrlType, Type ctrlEssentialType, + Element extraElement, string extraString, string extraMessage +where + not isExcluded(ctrlExpr, GenericsPackage::genericExpressionWithIncorrectEssentialTypeQuery()) and + ctrlExpr = generic.getControllingExpr() and + ctrlType = ctrlExpr.getFullyConverted().getType() and + ctrlEssentialType = getEssentialType(ctrlExpr) and + // Exclude lvalue conversion on const structs + exists(getEssentialTypeCategory(ctrlEssentialType)) and + ( + not ctrlEssentialType = ctrlType + or + getEssentialTypeCategory(ctrlEssentialType) = EssentiallyEnumType() + ) and + not allowedByException(ctrlExpr, ctrlEssentialType) and + extraElement = MacroUnwrapper::unwrapElement(generic) and + ( + if extraElement instanceof Macro + then ( + extraMessage = "macro $@ " and extraString = extraElement.(Macro).getName() + ) else ( + extraMessage = "" and extraString = "" + ) + ) +select generic, + "Controlling expression in generic " + extraMessage + "has standard type " + ctrlType.toString() + + ", which doesn't match its essential type " + ctrlEssentialType.toString() + ".", extraElement, + extraString diff --git a/c/misra/src/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.ql b/c/misra/src/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.ql new file mode 100644 index 0000000000..04952ae960 --- /dev/null +++ b/c/misra/src/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.ql @@ -0,0 +1,60 @@ +/** + * @id c/misra/invalid-generic-macro-argument-evaluation + * @name RULE-23-7: A generic selection that is expanded from a macro should evaluate its argument only once + * @description A generic selection that is expanded from a macro should evaluate its argument only + * once. + * @kind problem + * @precision medium + * @problem.severity warning + * @tags external/misra/id/rule-23-7 + * correctness + * maintainability + * external/misra/c/2012/amendment3 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Generic + +predicate allowedByException(string parameter, ParsedGenericMacro genericMacro) { + genericMacro.expansionsOutsideExpr(parameter) = 0 and + not genericMacro.expansionsInsideAssociation(parameter, _) > 0 and + forall(MacroInvocation mi, C11GenericExpr expr | + mi.getMacro() = genericMacro and + mi.getAGeneratedElement() = expr + | + forall(Expr assoc | assoc = expr.getAnAssociationExpr() | exists(assoc.getValue())) + ) +} + +from ParsedGenericMacro genericMacro, string parameter, string reason +where + not isExcluded(genericMacro, GenericsPackage::invalidGenericMacroArgumentEvaluationQuery()) and + parameter = genericMacro.getAParameter() and + genericMacro.expansionsInsideControllingExpr(parameter) > 0 and + ( + genericMacro.expansionsOutsideExpr(parameter) > 1 and + reason = "expanded multiple times outside the generic selection" + or + genericMacro.expansionsOutsideExpr(parameter) = 1 and + genericMacro.expansionsInsideAssociation(parameter, _) > 0 and + reason = "expanded outside the generic selection and inside the generic selection" + or + genericMacro.expansionsOutsideExpr(parameter) = 0 and + exists(int i | + genericMacro.expansionsInsideAssociation(parameter, i) > 1 and + reason = "expanded in generic selection " + i.toString() + " more than once" + ) + or + genericMacro.expansionsOutsideExpr(parameter) = 0 and + exists(int i | + genericMacro.expansionsInsideAssociation(parameter, i) = 0 and + reason = "not expanded in generic selection " + i.toString() + ) and + not allowedByException(parameter, genericMacro) + ) and + not genericMacro.getBody().matches(["%sizeof%", "%__alignof%", "%typeof%", "%offsetof%"]) +select genericMacro, + "Generic macro " + genericMacro.getName() + " may have unexpected behavior from side effects " + + "in parameter " + parameter + ", as it is " + reason + "." diff --git a/c/misra/src/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.ql b/c/misra/src/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.ql new file mode 100644 index 0000000000..6e443bd162 --- /dev/null +++ b/c/misra/src/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.ql @@ -0,0 +1,96 @@ +/** + * @id c/misra/default-generic-selection-not-first-or-last + * @name RULE-23-8: A default association shall appear as either the first or the last association of a generic + * @description A default association shall appear as either the first or the last association of a + * generic selection. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-23-8 + * maintainability + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.alertreporting.DeduplicateMacroResults + +class GenericWithMisplacedDefault extends C11GenericExpr { + int defaultIdx; + + GenericWithMisplacedDefault() { + getAssociationType(defaultIdx) instanceof VoidType and + not defaultIdx = 0 and + not defaultIdx = max(int i | exists(getAssociationType(i))) + } + + int getDefaultIdx() { result = defaultIdx } +} + +module GenericWithMisplacedDefaultConfig implements + DeduplicateMacroConfigSig +{ + string describe(GenericWithMisplacedDefault e) { + exists(int i | i = e.getDefaultIdx() + 1 | + i = 1 and result = "1st" + or + i = 2 and result = "2nd" + or + i = 3 and result = "3rd" + or + i > 3 and result = i.toString() + "th" + ) + } +} + +import GenericWithMisplacedDefaultConfig + +module GenericMisplacedDefaultReportConfig implements + MacroReportConfigSig +{ + /* Create a message to describe this macro, with a string describing its `ResultElement`. */ + bindingset[description] + string getMessageSameResultInAllExpansions(Macro m, string description) { + result = + "Generic macro " + m.getName() + " has default as " + description + + " association, which is not first or last." + } + + /* Create a message to describe this macro, using '$@' to describe an example `ResultElement`. */ + string getMessageVariedResultInAllExpansions(Macro m) { + result = + "Generic macro " + m.getName() + + " has a default association which is not first or last, for example $@." + } + + /** + * Create a message to describe this macro expansion which produces a `ResultElement`, using '$@' + * to describe the relevant macro. + */ + string getMessageResultInIsolatedExpansion(GenericWithMisplacedDefault element) { + result = + "Generic macro $@, in this expansion, has default as " + describe(element) + + " association, which is not first or last." + } + + /** + * Create a message to describe a `ResultElement` which is not generated by a macro expansion. + */ + string getMessageNotInMacro(GenericWithMisplacedDefault element, Locatable optLoc1, string optStr1) { + result = + "Generic has default as " + describe(element) + " association, which is not first or last." and + optLoc1 = element and + optStr1 = "" + } +} + +import DeduplicateMacroResults as Deduplicate +import Deduplicate::Report as Report + +from Report::ReportResult res +where + not isExcluded(res.getPrimaryElement(), + GenericsPackage::defaultGenericSelectionNotFirstOrLastQuery()) +select res.getPrimaryElement(), res.getMessage(), res.getOptionalPlaceholderLocatable(), + res.getOptionalPlaceholderMessage() diff --git a/c/misra/src/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.ql b/c/misra/src/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.ql index f59606a0ac..af05bfe4bc 100644 --- a/c/misra/src/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.ql +++ b/c/misra/src/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.ql @@ -9,33 +9,45 @@ * @tags external/misra/id/rule-3-1 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra -class IllegalCCommentCharacter extends string { - IllegalCCommentCharacter() { - this = "/*" or - this = "//" - } +/* Character sequence is banned from all comment types */ +class IllegalCommentSequence extends string { + IllegalCommentSequence() { this = "/*" } } -class IllegalCPPCommentCharacter extends string { - IllegalCPPCommentCharacter() { this = "/*" } +/* A regexp to check for illegal C-style comments */ +class IllegalCCommentRegexp extends string { + IllegalCCommentRegexp() { + // Regexp to match "//" in C-style comments, which do not appear to be URLs. General format + // uses negative lookahead/lookbehind to match like `.*(? 0 + exists(IllegalCommentSequence c | illegalSequence = c | + comment.getContents().indexOf(illegalSequence) > 1 ) or - exists(IllegalCPPCommentCharacter c | illegalSequence = c | - comment.(CppStyleComment).getContents().indexOf(illegalSequence) > 0 + exists(IllegalCCommentRegexp c | illegalSequence = c.getDescription() | + comment.(CStyleComment).getContents().regexpMatch(c) ) ) select comment, "Comment contains an illegal sequence '" + illegalSequence + "'" diff --git a/c/misra/src/rules/RULE-3-2/LineSplicingUsedInComments.ql b/c/misra/src/rules/RULE-3-2/LineSplicingUsedInComments.ql index cf6a2bb547..f1fd85b129 100644 --- a/c/misra/src/rules/RULE-3-2/LineSplicingUsedInComments.ql +++ b/c/misra/src/rules/RULE-3-2/LineSplicingUsedInComments.ql @@ -10,6 +10,7 @@ * maintainability * readability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.ql b/c/misra/src/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.ql index a7fdf080a7..0f04a7362b 100644 --- a/c/misra/src/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.ql +++ b/c/misra/src/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.ql @@ -10,39 +10,17 @@ * maintainability * readability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra +import codingstandards.cpp.rules.nonterminatedescapesequences.NonTerminatedEscapeSequences -bindingset[s] -predicate isOctalEscape(string s) { - s.charAt(0) = "\\" and - exists(int i | i = [0 .. 7] | i.toString() = s.charAt(1)) +class OctalAndHexadecimalEscapeSequencesNotTerminatedQuery extends NonTerminatedEscapeSequencesSharedQuery +{ + OctalAndHexadecimalEscapeSequencesNotTerminatedQuery() { + this = SyntaxPackage::octalAndHexadecimalEscapeSequencesNotTerminatedQuery() + } } - -bindingset[s] -predicate isHexEscape(string s) { s.indexOf("\\x") = 0 } - -from Literal l, string escapeKind, string s -where - not isExcluded(l, SyntaxPackage::octalAndHexadecimalEscapeSequencesNotTerminatedQuery()) and - exists(int idx, string sl | - sl = l.getValueText() and - idx = sl.indexOf("\\") and - s = sl.substring(idx, sl.length()) and - // Note: Octal representations must be 1-3 digits. There is no limitation on a - // Hex literal as long as the characters are valid. This query does not consider - // if the hex literal being constructed will overflow. - ( - isHexEscape(s) and - not s.regexpMatch("^((\\\\x[0-9A-F]+(?=[\"'\\\\])))[\\s\\S]*") and - escapeKind = "hexadecimal" - or - isOctalEscape(s) and - not s.regexpMatch("^(((\\\\[0-7]{1,3})(?=[\"'\\\\])))[\\s\\S]*") and - escapeKind = "octal" - ) - ) -select l, "Invalid " + escapeKind + " escape in string literal at '" + s + "'." diff --git a/c/misra/src/rules/RULE-5-1/ExternalIdentifiersNotDistinct.ql b/c/misra/src/rules/RULE-5-1/ExternalIdentifiersNotDistinct.ql index fa7190c39b..2c2c302bc0 100644 --- a/c/misra/src/rules/RULE-5-1/ExternalIdentifiersNotDistinct.ql +++ b/c/misra/src/rules/RULE-5-1/ExternalIdentifiersNotDistinct.ql @@ -9,6 +9,7 @@ * correctness * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-5-2/IdentifiersDeclaredInTheSameScopeNotDistinct.ql b/c/misra/src/rules/RULE-5-2/IdentifiersDeclaredInTheSameScopeNotDistinct.ql index 682d7538c5..eb24d1c094 100644 --- a/c/misra/src/rules/RULE-5-2/IdentifiersDeclaredInTheSameScopeNotDistinct.ql +++ b/c/misra/src/rules/RULE-5-2/IdentifiersDeclaredInTheSameScopeNotDistinct.ql @@ -9,6 +9,7 @@ * correctness * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-5-3/IdentifierHidingC.ql b/c/misra/src/rules/RULE-5-3/IdentifierHidingC.ql index 3463d08e1c..1c54b70147 100644 --- a/c/misra/src/rules/RULE-5-3/IdentifierHidingC.ql +++ b/c/misra/src/rules/RULE-5-3/IdentifierHidingC.ql @@ -10,6 +10,7 @@ * @tags external/misra/id/rule-5-3 * readability * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-5-4/MacroIdentifierNotDistinctFromParameter.ql b/c/misra/src/rules/RULE-5-4/MacroIdentifierNotDistinctFromParameter.ql index 886e05f0ea..d8a78cb680 100644 --- a/c/misra/src/rules/RULE-5-4/MacroIdentifierNotDistinctFromParameter.ql +++ b/c/misra/src/rules/RULE-5-4/MacroIdentifierNotDistinctFromParameter.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-5-4 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-5-4/MacroIdentifiersNotDistinct.ql b/c/misra/src/rules/RULE-5-4/MacroIdentifiersNotDistinct.ql index 5b3683bdc4..36b946491b 100644 --- a/c/misra/src/rules/RULE-5-4/MacroIdentifiersNotDistinct.ql +++ b/c/misra/src/rules/RULE-5-4/MacroIdentifiersNotDistinct.ql @@ -9,13 +9,62 @@ * correctness * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra +import codingstandards.cpp.Macro +import codingstandards.cpp.Includes +import codingstandards.cpp.PreprocessorDirective -from Macro m, Macro m2 +/** + * Gets a top level element that this macro is expanded to, e.g. an element which does not also have + * an enclosing element in the macro. + */ +Element getATopLevelElement(MacroInvocation mi) { + result = mi.getAnExpandedElement() and + not result.getEnclosingElement() = mi.getAnExpandedElement() and + not result instanceof Conversion +} + +/** + * Gets a link target that this macro is expanded in. + */ +LinkTarget getALinkTarget(Macro m) { + exists(MacroInvocation mi, Element e | + mi = m.getAnInvocation() and + e = getATopLevelElement(mi) + | + result = e.(Expr).getEnclosingFunction().getALinkTarget() + or + result = e.(Stmt).getEnclosingFunction().getALinkTarget() + or + exists(GlobalOrNamespaceVariable g | + result = g.getALinkTarget() and + g = e.(Expr).getEnclosingDeclaration() + ) + ) +} + +/** + * Holds if the m1 and m2 are unconditionally included from a common file. + * + * Extracted out for performance reasons - otherwise the call to determine the file path for the + * message was specializing the calls to `getAnUnconditionallyIncludedFile*(..)` and causing + * slow performance. + */ +bindingset[m1, m2] +pragma[inline_late] +private predicate isIncludedUnconditionallyFromCommonFile(Macro m1, Macro m2) { + exists(File f | + getAnUnconditionallyIncludedFile*(f) = m1.getFile() and + getAnUnconditionallyIncludedFile*(f) = m2.getFile() + ) +} + +from Macro m, Macro m2, string message where not isExcluded(m, Declarations1Package::macroIdentifiersNotDistinctQuery()) and not m = m2 and @@ -24,12 +73,40 @@ where //C90 states the first 31 characters of macro identifiers are significant and is not currently considered by this rule //ie an identifier differing on the 32nd character would be indistinct for C90 but distinct for C99 //and is currently not reported by this rule - if m.getName().length() >= 64 - then m.getName().prefix(63) = m2.getName().prefix(63) - else m.getName() = m2.getName() + if m.getName().length() >= 64 and not m.getName() = m2.getName() + then ( + m.getName().prefix(63) = m2.getName().prefix(63) and + message = + "Macro identifer " + m.getName() + " is nondistinct in first 63 characters, compared to $@." + ) else ( + m.getName() = m2.getName() and + message = + "Definition of macro " + m.getName() + + " is not distinct from alternative definition of $@ in " + + m2.getLocation().getFile().getRelativePath() + "." + ) ) and //reduce double report since both macros are in alert, arbitrary ordering - m.getLocation().getStartLine() >= m2.getLocation().getStartLine() -select m, - "Macro identifer " + m.getName() + " is nondistinct in first 63 characters, compared to $@.", m2, - m2.getName() + m.getLocation().getStartLine() >= m2.getLocation().getStartLine() and + // Not within an #ifndef MACRO_NAME + not exists(PreprocessorIfndef ifBranch | + m.getAGuard() = ifBranch or + m2.getAGuard() = ifBranch + | + ifBranch.getHead() = m.getName() + ) and + // Must be included unconditionally from the same file, otherwise m1 may not be defined + // when m2 is defined + isIncludedUnconditionallyFromCommonFile(m, m2) and + // Macros can't be mutually exclusive + not mutuallyExclusiveBranchDirectiveMacros(m, m2) and + not mutuallyExclusiveBranchDirectiveMacros(m2, m) and + // If at least one invocation exists for at least one of the macros, then they must share a link + // target - i.e. must both be expanded in the same context + ( + (exists(m.getAnInvocation()) and exists(m2.getAnInvocation())) + implies + // Must share a link target - e.g. must both be expanded in the same context + getALinkTarget(m) = getALinkTarget(m2) + ) +select m, message, m2, m2.getName() diff --git a/c/misra/src/rules/RULE-5-5/IdentifiersNotDistinctFromMacroNames.ql b/c/misra/src/rules/RULE-5-5/IdentifiersNotDistinctFromMacroNames.ql index a63d9656b8..da6b725ab5 100644 --- a/c/misra/src/rules/RULE-5-5/IdentifiersNotDistinctFromMacroNames.ql +++ b/c/misra/src/rules/RULE-5-5/IdentifiersNotDistinctFromMacroNames.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-5-5 * readability * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-5-6/TypedefNameNotUnique.ql b/c/misra/src/rules/RULE-5-6/TypedefNameNotUnique.ql index 2e9126d3af..1398df6a4d 100644 --- a/c/misra/src/rules/RULE-5-6/TypedefNameNotUnique.ql +++ b/c/misra/src/rules/RULE-5-6/TypedefNameNotUnique.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-5-6 * readability * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-5-7/TagNameNotUnique.ql b/c/misra/src/rules/RULE-5-7/TagNameNotUnique.ql index 1c8a7a6b34..fa6560ab49 100644 --- a/c/misra/src/rules/RULE-5-7/TagNameNotUnique.ql +++ b/c/misra/src/rules/RULE-5-7/TagNameNotUnique.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-5-7 * readability * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-5-8/IdentifiersWithExternalLinkageNotUnique.ql b/c/misra/src/rules/RULE-5-8/IdentifiersWithExternalLinkageNotUnique.ql index 7406f05f14..fa1b2b1fad 100644 --- a/c/misra/src/rules/RULE-5-8/IdentifiersWithExternalLinkageNotUnique.ql +++ b/c/misra/src/rules/RULE-5-8/IdentifiersWithExternalLinkageNotUnique.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-5-8 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ @@ -41,7 +42,25 @@ class NotUniqueExternalIdentifier extends ExternalIdentifiers { Declaration getAConflictingDeclaration() { not result = this and - isConflictingDeclaration(result, getName()) + isConflictingDeclaration(result, getName()) and + // We only consider a declaration to be conflicting if it shares a link target with the external + // identifier. This avoids reporting false positives where multiple binaries or libraries are + // built in the same CodeQL database, but are not intended to be linked together. + exists(LinkTarget lt | + // External declaration can only be a function or global variable + lt = this.(Function).getALinkTarget() or + lt = this.(GlobalVariable).getALinkTarget() + | + lt = result.(Function).getALinkTarget() + or + lt = result.(GlobalVariable).getALinkTarget() + or + exists(Class c | c.getAMember() = result and c.getALinkTarget() = lt) + or + result.(LocalVariable).getFunction().getALinkTarget() = lt + or + result.(Class).getALinkTarget() = lt + ) } } diff --git a/c/misra/src/rules/RULE-5-9/IdentifiersWithInternalLinkageNotUnique.ql b/c/misra/src/rules/RULE-5-9/IdentifiersWithInternalLinkageNotUnique.ql index 45f63a3207..fcba48f2fd 100644 --- a/c/misra/src/rules/RULE-5-9/IdentifiersWithInternalLinkageNotUnique.ql +++ b/c/misra/src/rules/RULE-5-9/IdentifiersWithInternalLinkageNotUnique.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-5-9 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.ql b/c/misra/src/rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.ql index fce1d9ad1a..078c2c48b7 100644 --- a/c/misra/src/rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.ql +++ b/c/misra/src/rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.ql @@ -7,38 +7,17 @@ * @precision very-high * @problem.severity error * @tags external/misra/id/rule-6-1 + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.cpp.Compiler +import codingstandards.cpp.rules.bitfieldshallhaveanappropriatetype.BitFieldShallHaveAnAppropriateType -Type getSupportedBitFieldType(Compiler compiler) { - compiler instanceof UnsupportedCompiler and - ( - result instanceof IntType and - ( - result.(IntegralType).isExplicitlySigned() or - result.(IntegralType).isExplicitlyUnsigned() - ) - or - result instanceof BoolType - ) - or - (compiler instanceof Gcc or compiler instanceof Clang) and - ( - result instanceof IntegralOrEnumType - or - result instanceof BoolType - ) +class BitFieldsShallOnlyBeDeclaredWithAnAppropriateTypeQuery extends BitFieldShallHaveAnAppropriateTypeSharedQuery +{ + BitFieldsShallOnlyBeDeclaredWithAnAppropriateTypeQuery() { + this = BitfieldTypesPackage::bitFieldsShallOnlyBeDeclaredWithAnAppropriateTypeQuery() + } } - -from BitField bitField -where - not isExcluded(bitField, - BitfieldTypesPackage::bitFieldsShallOnlyBeDeclaredWithAnAppropriateTypeQuery()) and - /* A violation would neither be an appropriate primitive type nor an appropriate typedef. */ - not getSupportedBitFieldType(getCompiler(bitField.getFile())) = - bitField.getType().resolveTypedefs() -select bitField, "Bit-field '" + bitField + "' is declared on type '" + bitField.getType() + "'." diff --git a/c/misra/src/rules/RULE-6-2/SingleBitNamedBitFieldsOfASignedType.ql b/c/misra/src/rules/RULE-6-2/SingleBitNamedBitFieldsOfASignedType.ql index d4be3d6dd2..142a0b542d 100644 --- a/c/misra/src/rules/RULE-6-2/SingleBitNamedBitFieldsOfASignedType.ql +++ b/c/misra/src/rules/RULE-6-2/SingleBitNamedBitFieldsOfASignedType.ql @@ -7,28 +7,17 @@ * @precision very-high * @problem.severity error * @tags external/misra/id/rule-6-2 + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra +import codingstandards.cpp.rules.namedbitfieldswithsignedintegertype.NamedBitFieldsWithSignedIntegerType -/* - * Check if the DECLARED bit-fields is a single bit, because Rule 6.2 also intends to catch confusion on the programmers' part. Consider: - * - * struct S { - * int32_t x: 1; - * } - * - * In this case, field x is essentially of 32 bits, but is declared as 1 bit and its type int32_t is signed. Therefore, it indicates confusion by the programmer, which is exactly what this rule intends to find. - */ - -from BitField bitField -where - not isExcluded(bitField, BitfieldTypesPackage::singleBitNamedBitFieldsOfASignedTypeQuery()) and - bitField.getDeclaredNumBits() = 1 and // Single-bit, - not bitField.isAnonymous() and // named, - bitField.getType().(IntegralType).isSigned() // but its type is signed. -select bitField, - "Single-bit bit-field named " + bitField.toString() + " has a signed type " + bitField.getType() + - "." +class SingleBitNamedBitFieldsOfASignedTypeQuery extends NamedBitFieldsWithSignedIntegerTypeSharedQuery +{ + SingleBitNamedBitFieldsOfASignedTypeQuery() { + this = BitfieldTypesPackage::singleBitNamedBitFieldsOfASignedTypeQuery() + } +} diff --git a/c/misra/src/rules/RULE-6-3/BitFieldDeclaredAsMemberOfAUnion.ql b/c/misra/src/rules/RULE-6-3/BitFieldDeclaredAsMemberOfAUnion.ql new file mode 100644 index 0000000000..4befbb9dd6 --- /dev/null +++ b/c/misra/src/rules/RULE-6-3/BitFieldDeclaredAsMemberOfAUnion.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/bit-field-declared-as-member-of-a-union + * @name RULE-6-3: A bit field shall not be declared as a member of a union + * @description Type punning on a union with bit fields relies on implementation-specific alignment + * behavior. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-6-3 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from BitField field, Union u +where + not isExcluded(field, BitfieldTypes2Package::bitFieldDeclaredAsMemberOfAUnionQuery()) and + u.getAField() = field +select field, + "Union member " + field.getName() + + " is declared as a bit field which relies on implementation-specific behavior." diff --git a/c/misra/src/rules/RULE-7-1/OctalConstantsUsed.ql b/c/misra/src/rules/RULE-7-1/OctalConstantsUsed.ql index d4a6c332a7..9934e80487 100644 --- a/c/misra/src/rules/RULE-7-1/OctalConstantsUsed.ql +++ b/c/misra/src/rules/RULE-7-1/OctalConstantsUsed.ql @@ -10,6 +10,7 @@ * readability * correctness * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.ql b/c/misra/src/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.ql index b1dca9ac4a..c02e0e2aca 100644 --- a/c/misra/src/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.ql +++ b/c/misra/src/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-7-2 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ @@ -19,6 +20,13 @@ from Literal l where not isExcluded(l, SyntaxPackage::uOrUSuffixRepresentedInUnsignedTypeQuery()) and not l instanceof StringLiteral and - l.getImplicitlyConverted().getType().(IntegralType).isUnsigned() and - not exists(l.getValueText().toUpperCase().indexOf("U")) -select l, "Unsigned literal does not explicitly express sign with a 'U' or 'u' suffix." + // Determine if the extractor deduced that the literal is unsigned, based on the C rules + l.getType().(IntegralType).isUnsigned() and + // And report if the literal does not contain a 'U' or 'u' suffix, e.g. explicitly unsigned + not exists(l.getValueText().toUpperCase().indexOf("U")) and + // Exclude constants generated by macro expansions, because the suffix information is lost in this + // case, so can cause false positives. + not l.isInMacroExpansion() +select l, + "Unsigned literal " + l.getValueText() + + " does not explicitly express sign with a 'U' or 'u' suffix." diff --git a/c/misra/src/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.ql b/c/misra/src/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.ql index 4fc257578b..0b38b26eea 100644 --- a/c/misra/src/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.ql +++ b/c/misra/src/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.ql @@ -9,12 +9,13 @@ * @tags external/misra/id/rule-7-3 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.c.Literals +import codingstandards.cpp.Literals from IntegerLiteral l where diff --git a/c/misra/src/rules/RULE-7-4/StringLiteralAssignedToNonConstChar.ql b/c/misra/src/rules/RULE-7-4/StringLiteralAssignedToNonConstChar.ql index c93740139b..bc2fa5f5bf 100644 --- a/c/misra/src/rules/RULE-7-4/StringLiteralAssignedToNonConstChar.ql +++ b/c/misra/src/rules/RULE-7-4/StringLiteralAssignedToNonConstChar.ql @@ -7,6 +7,7 @@ * @precision very-high * @problem.severity error * @tags external/misra/id/rule-7-4 + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql new file mode 100644 index 0000000000..1fe052aaae --- /dev/null +++ b/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql @@ -0,0 +1,46 @@ +/** + * @id c/misra/incorrectly-sized-integer-constant-macro-argument + * @name RULE-7-5: The argument of an integer constant macro shall have an appropriate size + * @description Integer constant macros argument values should be values of a compatible size. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-5 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.IntegerConstantMacro +import codingstandards.cpp.Literals + +predicate matchesSign(IntegerConstantMacro macro, PossiblyNegativeLiteral literal) { + literal.isNegative() implies macro.isSigned() +} + +bindingset[literal] +predicate matchesSize(IntegerConstantMacro macro, PossiblyNegativeLiteral literal) { + literal.getRawValue() <= macro.maxValue() and + literal.getRawValue() >= macro.minValue() +} + +from + PossiblyNegativeLiteral literal, MacroInvocation invoke, IntegerConstantMacro macro, + string explanation +where + not isExcluded(invoke, Types2Package::incorrectlySizedIntegerConstantMacroArgumentQuery()) and + invoke.getMacro() = macro and + literal = invoke.getExpr() and + ( + not matchesSign(macro, literal) and + explanation = " cannot be negative" + or + matchesSign(macro, literal) and + // Wait for BigInt support to check 64 bit macro types. + macro.getSize() < 64 and + not matchesSize(macro, literal) and + explanation = " is outside of the allowed range " + macro.getRangeString() + ) +select literal, "Value provided to integer constant macro " + macro.getName() + explanation diff --git a/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql b/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql new file mode 100644 index 0000000000..84fb1a9872 --- /dev/null +++ b/c/misra/src/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql @@ -0,0 +1,35 @@ +/** + * @id c/misra/integer-constant-macro-argument-uses-suffix + * @name RULE-7-5: The argument of an integer constant macro shall not use literal suffixes u, l, or ul + * @description Integer constant macros should be used integer literal values with no u/l suffix. + * @kind problem + * @precision high + * @problem.severity warning + * @tags external/misra/id/rule-7-5 + * readability + * maintainability + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.IntegerConstantMacro +import codingstandards.cpp.Literals + +string argumentSuffix(MacroInvocation invoke) { + // Extractor strips the suffix unless we look at the unexpanded argument text. + // Unexpanded argument text can be malformed in all sorts of ways, so make + // this match relatively strict, to be safe. + result = invoke.getUnexpandedArgument(0).regexpCapture("([0-9]+|0[xX][0-9A-F]+)([uUlL]+)$", 2) +} + +from MacroInvocation invoke, PossiblyNegativeLiteral argument, string suffix +where + not isExcluded(invoke, Types2Package::integerConstantMacroArgumentUsesSuffixQuery()) and + invoke.getMacro() instanceof IntegerConstantMacro and + invoke.getExpr() = argument and + suffix = argumentSuffix(invoke) +select argument, + "Value suffix '" + suffix + "' is not allowed on provided argument to integer constant macro " + + invoke.getMacroName() + "." diff --git a/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql new file mode 100644 index 0000000000..4c750e32d8 --- /dev/null +++ b/c/misra/src/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql @@ -0,0 +1,30 @@ +/** + * @id c/misra/invalid-integer-constant-macro-argument + * @name RULE-7-5: The argument of an integer constant macro shall be a literal + * @description Integer constant macros should be given a literal value as an argument. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-7-5 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.IntegerConstantMacro +import codingstandards.cpp.Literals +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis + +from MacroInvocation invoke, IntegerConstantMacro macro +where + not isExcluded(invoke, Types2Package::invalidIntegerConstantMacroArgumentQuery()) and + invoke.getMacro() = macro and + ( + not invoke.getExpr() instanceof PossiblyNegativeLiteral + or + any(MacroInvocation inner).getParentInvocation() = invoke + ) +select invoke.getExpr(), + "Argument to integer constant macro " + macro.getName() + " must be an integer literal." diff --git a/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql new file mode 100644 index 0000000000..e4e660c628 --- /dev/null +++ b/c/misra/src/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql @@ -0,0 +1,77 @@ +/** + * @id c/misra/invalid-literal-for-integer-constant-macro-argument + * @name RULE-7-5: The argument of an integer constant macro shall be a decimal, hex, or octal literal + * @description Integer constant macro arguments should be a decimal, hex, or octal literal. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-5 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.IntegerConstantMacro +import codingstandards.cpp.Literals + +/** + * Floating point literals are not allowed. Neither are char or string + * literals, although those are not `NumericLiteral`s and therefore detected in + * `InvalidIntegerConstantMacroArgument.ql`. + */ +predicate validLiteralType(PossiblyNegativeLiteral literal) { + literal.getBaseLiteral() instanceof Cpp14Literal::DecimalLiteral or + literal.getBaseLiteral() instanceof Cpp14Literal::OctalLiteral or + literal.getBaseLiteral() instanceof Cpp14Literal::HexLiteral or + // Ignore cases where the AST/extractor don't give us enough information: + literal.getBaseLiteral() instanceof Cpp14Literal::UnrecognizedNumericLiteral +} + +/** + * Clang accepts `xINTsize_C(0b01)`, and expands the argument into a decimal + * literal. Binary literals are not standard c nor are they allowed by rule 7-5. + * Detect this pattern before macro expansion. + */ +predicate seemsBinaryLiteral(MacroInvocation invoke) { + invoke.getUnexpandedArgument(0).regexpMatch("-?0[bB][01]+") +} + +/** + * Extractor converts `xINTsize_C('a')` to a decimal literal. Therefore, detect + * this pattern before macro expansion. + */ +predicate seemsCharLiteral(MacroInvocation invoke) { + invoke.getUnexpandedArgument(0).regexpMatch("-?'\\\\?.'") +} + +string explainIncorrectArgument(MacroInvocation invoke) { + if seemsBinaryLiteral(invoke) + then result = "binary literal" + else + if seemsCharLiteral(invoke) + then result = "char literal" + else + exists(PossiblyNegativeLiteral literal | + literal = invoke.getExpr() and + if literal.getBaseLiteral() instanceof Cpp14Literal::FloatingLiteral + then result = "floating point literal" + else result = "invalid literal" + ) +} + +from MacroInvocation invoke, PossiblyNegativeLiteral literal +where + not isExcluded(invoke, Types2Package::invalidLiteralForIntegerConstantMacroArgumentQuery()) and + invoke.getMacro() instanceof IntegerConstantMacro and + literal = invoke.getExpr() and + ( + not validLiteralType(literal) or + seemsBinaryLiteral(invoke) or + seemsCharLiteral(invoke) + ) +select literal, + "Integer constant macro " + invoke.getMacroName() + " used with " + + explainIncorrectArgument(invoke) + + " argument, only decimal, octal, or hex integer literal allowed." diff --git a/c/misra/src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql b/c/misra/src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql new file mode 100644 index 0000000000..47e88196d5 --- /dev/null +++ b/c/misra/src/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/use-of-banned-small-integer-constant-macro + * @name RULE-7-6: The small integer variants of the minimum-width integer constant macros shall not be used + * @description Small integer constant macros expression are promoted to type int, which can lead to + * unexpected results. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-7-6 + * readability + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.IntegerConstantMacro + +from MacroInvocation macroInvoke, IntegerConstantMacro macro +where + not isExcluded(macroInvoke, Types2Package::useOfBannedSmallIntegerConstantMacroQuery()) and + macroInvoke.getMacro() = macro and + macro.isSmall() +select macroInvoke, "Usage of small integer constant macro " + macro.getName() + " is not allowed." diff --git a/c/misra/src/rules/RULE-8-1/ExplicitlyDeclareTypes.ql b/c/misra/src/rules/RULE-8-1/ExplicitlyDeclareTypes.ql index bfcbac4435..6484372f5b 100644 --- a/c/misra/src/rules/RULE-8-1/ExplicitlyDeclareTypes.ql +++ b/c/misra/src/rules/RULE-8-1/ExplicitlyDeclareTypes.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-8-1 * correctness * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-8-10/InlineFunctionNotDeclaredStaticStorage.ql b/c/misra/src/rules/RULE-8-10/InlineFunctionNotDeclaredStaticStorage.ql index 47e80912af..250c00ca2e 100644 --- a/c/misra/src/rules/RULE-8-10/InlineFunctionNotDeclaredStaticStorage.ql +++ b/c/misra/src/rules/RULE-8-10/InlineFunctionNotDeclaredStaticStorage.ql @@ -8,6 +8,7 @@ * @problem.severity error * @tags external/misra/id/rule-8-10 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-8-11/ArrayExternalLinkageSizeExplicitlySpecified.ql b/c/misra/src/rules/RULE-8-11/ArrayExternalLinkageSizeExplicitlySpecified.ql index ada18c805d..d14e236755 100644 --- a/c/misra/src/rules/RULE-8-11/ArrayExternalLinkageSizeExplicitlySpecified.ql +++ b/c/misra/src/rules/RULE-8-11/ArrayExternalLinkageSizeExplicitlySpecified.ql @@ -10,6 +10,7 @@ * @tags external/misra/id/rule-8-11 * correctness * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-8-12/ValueImplicitEnumerationConstantNotUnique.ql b/c/misra/src/rules/RULE-8-12/ValueImplicitEnumerationConstantNotUnique.ql index 0772da9b05..6ebabc3810 100644 --- a/c/misra/src/rules/RULE-8-12/ValueImplicitEnumerationConstantNotUnique.ql +++ b/c/misra/src/rules/RULE-8-12/ValueImplicitEnumerationConstantNotUnique.ql @@ -9,30 +9,17 @@ * @tags external/misra/id/rule-8-12 * correctness * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra +import codingstandards.cpp.rules.nonuniqueenumerationconstant.NonUniqueEnumerationConstant -/** - * An `EnumConstant` that has an implicitly specified value: - * `enum e { explicit = 1, implicit }` - */ -class ImplicitlySpecifiedEnumConstant extends EnumConstant { - ImplicitlySpecifiedEnumConstant() { - //implicitly specified have an initializer with location: `file://:0:0:0:0` - not this.getInitializer().getLocation().getFile() = this.getFile() +class ValueImplicitEnumerationConstantNotUniqueQuery extends NonUniqueEnumerationConstantSharedQuery +{ + ValueImplicitEnumerationConstantNotUniqueQuery() { + this = Declarations7Package::valueImplicitEnumerationConstantNotUniqueQuery() } } - -from EnumConstant exp, ImplicitlySpecifiedEnumConstant imp -where - not isExcluded(exp, Declarations7Package::valueImplicitEnumerationConstantNotUniqueQuery()) and - not isExcluded(imp, Declarations7Package::valueImplicitEnumerationConstantNotUniqueQuery()) and - not exp = imp and - imp.getValue() = exp.getValue() and - imp.getDeclaringEnum() = exp.getDeclaringEnum() and - //can technically be the same declared enum across multiple headers but those are not relevant to this rule - imp.getFile() = exp.getFile() -select imp, "Nonunique value of enum constant compared to $@", exp, exp.getName() diff --git a/c/misra/src/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.ql b/c/misra/src/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.ql index 5e63e74e2c..6a2c123907 100644 --- a/c/misra/src/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.ql +++ b/c/misra/src/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.ql @@ -10,36 +10,62 @@ * correctness * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ import cpp import codingstandards.c.misra -import codingstandards.c.Pointers +import codingstandards.cpp.types.Pointers import codingstandards.cpp.SideEffect +import codingstandards.cpp.alertreporting.HoldsForAllCopies -from Variable ptr, PointerOrArrayType type +class NonConstPointerVariableCandidate extends Variable { + NonConstPointerVariableCandidate() { + // Ignore parameters in functions without bodies + (this instanceof Parameter implies exists(this.(Parameter).getFunction().getBlock())) and + // Ignore variables in functions that use ASM commands + not exists(AsmStmt a | + a.getEnclosingFunction() = this.(LocalScopeVariable).getFunction() + or + // In a type declared locally + this.(Field).getDeclaringType+().getEnclosingFunction() = a.getEnclosingFunction() + ) and + exists(PointerOrArrayType type | + // include only pointers which point to a const-qualified type + this.getType() = type and + not type.isDeeplyConstBelow() + ) and + // exclude pointers passed as arguments to functions which take a + // parameter that points to a non-const-qualified type + not exists(FunctionCall fc, int i | + fc.getArgument(i) = this.getAnAccess() and + not fc.getTarget().getParameter(i).getType().isDeeplyConstBelow() + ) and + // exclude any pointers which have their underlying data modified + not exists(VariableEffect effect | + effect.getTarget() = this and + // but not pointers that are only themselves modified + not effect.(AssignExpr).getLValue() = this.getAnAccess() and + not effect.(CrementOperation).getOperand() = this.getAnAccess() + ) and + // exclude pointers assigned to another pointer to a non-const-qualified type + not exists(Variable a | + a.getAnAssignedValue() = this.getAnAccess() and + not a.getType().(PointerOrArrayType).isDeeplyConstBelow() + ) + } +} + +/** + * Ensure that all copies of a variable are considered to be missing const qualification to avoid + * false positives where a variable is only used/modified in a single copy. + */ +class NonConstPointerVariable = + HoldsForAllCopies::LogicalResultElement; + +from NonConstPointerVariable ptr where - not isExcluded(ptr, Pointers1Package::pointerShouldPointToConstTypeWhenPossibleQuery()) and - // include only pointers which point to a const-qualified type - ptr.getType() = type and - not type.isDeeplyConstBelow() and - // exclude pointers passed as arguments to functions which take a - // parameter that points to a non-const-qualified type - not exists(FunctionCall fc, int i | - fc.getArgument(i) = ptr.getAnAccess() and - not fc.getTarget().getParameter(i).getType().isDeeplyConstBelow() - ) and - // exclude any pointers which have their underlying data modified - not exists(VariableEffect effect | - effect.getTarget() = ptr and - // but not pointers that are only themselves modified - not effect.(AssignExpr).getLValue() = effect.getAnAccess() and - not effect.(CrementOperation).getOperand() = effect.getAnAccess() - ) and - // exclude pointers assigned to another pointer to a non-const-qualified type - not exists(Variable a | - a.getAnAssignedValue() = ptr.getAnAccess() and - not a.getType().(PointerOrArrayType).isDeeplyConstBelow() - ) -select ptr, "$@ points to a non-const-qualified type.", ptr, ptr.getName() + not isExcluded(ptr.getAnElementInstance(), + Pointers1Package::pointerShouldPointToConstTypeWhenPossibleQuery()) +select ptr, "$@ points to a non-const-qualified type.", ptr, ptr.getAnElementInstance().getName() diff --git a/c/misra/src/rules/RULE-8-14/RestrictTypeQualifierUsed.ql b/c/misra/src/rules/RULE-8-14/RestrictTypeQualifierUsed.ql index 1969947753..cff7d0df5c 100644 --- a/c/misra/src/rules/RULE-8-14/RestrictTypeQualifierUsed.ql +++ b/c/misra/src/rules/RULE-8-14/RestrictTypeQualifierUsed.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-8-14 * correctness * security + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql new file mode 100644 index 0000000000..dc82f63d10 --- /dev/null +++ b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql @@ -0,0 +1,36 @@ +/** + * @id c/misra/redeclaration-of-object-with-unmatched-alignment + * @name RULE-8-15: Alignment should match between all declarations of an object + * @description All declarations of an object with an explicit alignment specification shall specify + * the same alignment. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-15 + * external/misra/c/2012/amendment3 + * readability + * maintainability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import semmle.code.cpp.valuenumbering.HashCons + +predicate lexicallyEqual(AttributeArgument a, AttributeArgument b) { + hashCons(a.getValueConstant()) = hashCons(b.getValueConstant()) or + a.getValueType() = b.getValueType() +} + +from Attribute alignment, Attribute mismatched, string variable +where + not isExcluded(alignment, AlignmentPackage::redeclarationOfObjectWithUnmatchedAlignmentQuery()) and + alignment.hasName("_Alignas") and + mismatched.hasName("_Alignas") and + exists(Variable v | + v.getAnAttribute() = alignment and v.getAnAttribute() = mismatched and v.getName() = variable + ) and + not lexicallyEqual(alignment.getArgument(0), mismatched.getArgument(0)) +select alignment, + "Variable " + variable + " declared with lexically different _Alignof() values '$@' and '$@'.", + alignment, alignment.getArgument(0).toString(), mismatched, mismatched.getArgument(0).toString() diff --git a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql new file mode 100644 index 0000000000..df9f3f2d1c --- /dev/null +++ b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql @@ -0,0 +1,96 @@ +/** + * @id c/misra/redeclaration-of-object-without-alignment + * @name RULE-8-15: Alignment should match between all declarations of an object + * @description An object declared with an explicit alignment shall be explicitly aligned in all + * declarations. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-15 + * external/misra/c/2012/amendment3 + * readability + * maintainability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +/** + * Performance optimization; start query by joining attributes to declarations + * rather than locations. + * + * Including the entry location also speeds up search. + */ +newtype TAttributeDeclLocation = + TAttributeDeclLocationInfo(Attribute attribute, DeclarationEntry entry, Location entryLocation) { + entry.getDeclaration().(Variable).getAnAttribute() = attribute and + entryLocation = entry.getLocation() + } + +/** + * Get a DeclarationEntry along with its explicitly declared Attributes. + * + * DeclarationEntry does not have a method for getting Attributes by default, + * because an attribute declared on any DeclarationEntry affects all others, + * and attributes really belong to the declared variable rather than the + * declaration itself. + * + * In order to support this rule, we find for each attribute + * - A declaration entry which + * - corresponds to a variable associated with this attribute + * - is in the same file as this attribute + * - has identifier location after the attribute declaration + * - has no other declaration entry between this one and the attribute. + * + * This should give us a highly reliable means of finding which attributes are + * associated with which `DeclarationEntry`s. + * + * One note of caution: the location of the associated `Variable` must be + * treated with caution, as calls to `getLocation()` on a redeclared `Variable` + * can return multiple results. This class must act on `DeclarationEntry`s to + * deliver reliable results. + */ +class DeclarationEntryAttribute extends Attribute { + DeclarationEntry declarationEntry; + Location location; + Location declLocation; + File file; + TAttributeDeclLocation locInfo; + + DeclarationEntryAttribute() { + locInfo = TAttributeDeclLocationInfo(this, declarationEntry, declLocation) and + file = getFile() and + location = getLocation() and + declLocation = declarationEntry.getLocation() and + declarationEntry.getDeclaration().(Variable).getAnAttribute() = this and + declarationEntry.getFile() = file and + location.isBefore(declLocation, _) and + not exists(TAttributeDeclLocation blocInfo, DeclarationEntry betterFit, Location blocation | + blocInfo = TAttributeDeclLocationInfo(this, betterFit, blocation) and + not betterFit = declarationEntry and + blocation = betterFit.getLocation() and + betterFit.getFile() = file and + betterFit.getDeclaration() = declarationEntry.getDeclaration() and + blocation.isBefore(declLocation, _) and + location.isBefore(blocation, _) + ) + } + + DeclarationEntry getDeclarationEntry() { result = declarationEntry } +} + +from DeclarationEntry unaligned, DeclarationEntry aligned, DeclarationEntryAttribute attribute +where + not isExcluded(unaligned, AlignmentPackage::redeclarationOfObjectWithoutAlignmentQuery()) and + attribute.hasName("_Alignas") and + attribute.getDeclarationEntry() = aligned and + aligned.getDeclaration() = unaligned.getDeclaration() and + not exists(DeclarationEntryAttribute matchingAlignment | + matchingAlignment.hasName("_Alignas") and + matchingAlignment.getDeclarationEntry() = unaligned + ) +select unaligned, + "Variable " + unaligned.getName() + + " declared without explicit alignment to match $@ with alignment $@.", aligned, + "other definition", attribute, attribute.toString() diff --git a/c/misra/src/rules/RULE-8-16/AlignmentWithSizeZero.ql b/c/misra/src/rules/RULE-8-16/AlignmentWithSizeZero.ql new file mode 100644 index 0000000000..4a0cd9d50b --- /dev/null +++ b/c/misra/src/rules/RULE-8-16/AlignmentWithSizeZero.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/alignment-with-size-zero + * @name RULE-8-16: The alignment specification of zero should not appear in an object declaration + * @description A declaration shall not have an alignment of size zero. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-16 + * external/misra/c/2012/amendment3 + * readability + * maintainability + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra + +from Attribute a, Variable v +where + not isExcluded(a, AlignmentPackage::alignmentWithSizeZeroQuery()) and + a.hasName("_Alignas") and + a.getArgument(0).getValueInt() = 0 and + v.getAnAttribute() = a +select a.getArgument(0), "Invalid alignof() size set to zero for variable $@.", v, v.getName() diff --git a/c/misra/src/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql b/c/misra/src/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql new file mode 100644 index 0000000000..f4e0d93d92 --- /dev/null +++ b/c/misra/src/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql @@ -0,0 +1,38 @@ +/** + * @id c/misra/more-than-one-alignment-specifier-on-declaration + * @name RULE-8-17: At most one explicit alignment specifier should appear in an object declaration + * @description While C permits the usage of multiple alignment specifiers, doing so reduces + * readability and may obscure the intent of the declaration. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-17 + * external/misra/c/2012/amendment3 + * readability + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra + +from Variable v, Attribute first, Attribute last +where + not isExcluded(v, AlignmentPackage::moreThanOneAlignmentSpecifierOnDeclarationQuery()) and + first = v.getAnAttribute() and + last = v.getAnAttribute() and + not first = last and + first.hasName("_Alignas") and + last.hasName("_Alignas") and + // Handle double reporting: the first Attribute should really be first, and the last Attribute + // should really be last. This implies the first is before the last. This approach also ensures + // a single result for variables that have more than two alignment specifiers. + not exists(Attribute beforeFirst | + beforeFirst.getLocation().isBefore(first.getLocation(), _) and + v.getAnAttribute() = beforeFirst + ) and + not exists(Attribute afterLast | + last.getLocation().isBefore(afterLast.getLocation(), _) and + v.getAnAttribute() = afterLast + ) +select v, "Variable " + v.getName() + " contains more than one alignment specifier, $@ and $@", + first, first.toString(), last, last.toString() diff --git a/c/misra/src/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.ql b/c/misra/src/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.ql index e46085750d..1136dd714e 100644 --- a/c/misra/src/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.ql +++ b/c/misra/src/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.ql @@ -8,51 +8,16 @@ * @problem.severity error * @tags external/misra/id/rule-8-2 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.cpp.Identifiers +import codingstandards.cpp.rules.functiontypesnotinprototypeformshared.FunctionTypesNotInPrototypeFormShared -/** - * `Parameter`s without names - */ -class UnnamedParameter extends Parameter { - UnnamedParameter() { not this.isNamed() } +class FunctionTypesNotInPrototypeFormQuery extends FunctionTypesNotInPrototypeFormSharedSharedQuery { + FunctionTypesNotInPrototypeFormQuery() { + this = Declarations4Package::functionTypesNotInPrototypeFormQuery() + } } - -/* - * This is a copy of the private `hasZeroParamDecl` predicate from the standard set of - * queries as of the `codeql-cli/2.11.2` tag in `github/codeql`. - */ - -predicate hasZeroParamDecl(Function f) { - exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | - not fde.isImplicit() and - not fde.hasVoidParamList() and - fde.getNumberOfParameters() = 0 and - not fde.isDefinition() - ) -} - -from Function f, string msg -where - not isExcluded(f, Declarations4Package::functionTypesNotInPrototypeFormQuery()) and - f instanceof InterestingIdentifiers and - ( - f.getAParameter() instanceof UnnamedParameter and - msg = "Function " + f + " declares parameter that is unnamed." - or - hasZeroParamDecl(f) and - msg = "Function " + f + " does not specify void for no parameters present." - or - //parameters declared in declaration list (not in function signature) - //have placeholder file location associated only - exists(Parameter p | - p.getFunction() = f and - not p.getFile() = f.getFile() and - msg = "Function " + f + " declares parameter in unsupported declaration list." - ) - ) -select f, msg diff --git a/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql b/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql index 6803af9380..fe0ae81ab1 100644 --- a/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql +++ b/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql @@ -8,14 +8,20 @@ * @problem.severity error * @tags external/misra/id/rule-8-3 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.cpp.Compatible +import codingstandards.cpp.types.Compatible -from FunctionDeclarationEntry f1, FunctionDeclarationEntry f2, string case +predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { + not f1 = f2 and + f1.getDeclaration() = f2.getDeclaration() +} + +from FunctionDeclarationEntry f1, FunctionDeclarationEntry f2, string case, string pluralDo where not isExcluded(f1, Declarations4Package::declarationsOfAFunctionSameNameAndTypeQuery()) and not isExcluded(f2, Declarations4Package::declarationsOfAFunctionSameNameAndTypeQuery()) and @@ -23,16 +29,22 @@ where f1.getDeclaration() = f2.getDeclaration() and //return type check ( - not typesCompatible(f1.getType(), f2.getType()) and - case = "return type" + not FunctionDeclarationTypeEquivalence::equalReturnTypes(f1, + f2) and + case = "return type" and + pluralDo = "does" or //parameter type check - parameterTypesIncompatible(f1, f2) and - case = "parameter types" + not FunctionDeclarationTypeEquivalence::equalParameterTypes(f1, + f2) and + case = "parameter types" and + pluralDo = "do" or //parameter name check - parameterNamesIncompatible(f1, f2) and - case = "parameter names" + parameterNamesUnmatched(f1, f2) and + case = "parameter names" and + pluralDo = "do" ) -select f1, "The " + case + " of re-declaration of $@ is not compatible with declaration $@", f1, - f1.getName(), f2, f2.getName() +select f1, + "The " + case + " of re-declaration of $@ " + pluralDo + + " not use the same type names as declaration $@", f1, f1.getName(), f2, f2.getName() diff --git a/c/misra/src/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.ql b/c/misra/src/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.ql index dfd9d622e9..36a84b3b9c 100644 --- a/c/misra/src/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.ql +++ b/c/misra/src/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.ql @@ -8,22 +8,48 @@ * @problem.severity error * @tags external/misra/id/rule-8-3 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.cpp.Compatible +import codingstandards.cpp.types.Compatible + +predicate relevantPair(VariableDeclarationEntry decl1, VariableDeclarationEntry decl2) { + not decl1 = decl2 and + not decl1.getVariable().getDeclaringType().isAnonymous() and + // Declarations are for the same qualified name + // Note: decl1.getVariable() = decl2.getVariable() does not work for common cases where an aliased + // type is used. + decl1.getVariable().getQualifiedName() = decl2.getVariable().getQualifiedName() and + // As we use qualified name, require that they share a common link target to ensure they are + // for the same object + ( + decl1.getVariable().(GlobalVariable).getALinkTarget() = + decl2.getVariable().(GlobalVariable).getALinkTarget() + or + decl1.getVariable().(Field).getDeclaringType().(Class).getALinkTarget() = + decl2.getVariable().(Field).getDeclaringType().(Class).getALinkTarget() + ) +} + +predicate relevantTypes(Type a, Type b) { + exists(VariableDeclarationEntry varA, VariableDeclarationEntry varB | + a = varA.getType() and + b = varB.getType() and + relevantPair(varA, varB) + ) +} from VariableDeclarationEntry decl1, VariableDeclarationEntry decl2 where not isExcluded(decl1, Declarations4Package::declarationsOfAnObjectSameNameAndTypeQuery()) and not isExcluded(decl2, Declarations4Package::declarationsOfAnObjectSameNameAndTypeQuery()) and - not decl1 = decl2 and - not decl1.getVariable().getDeclaringType().isAnonymous() and - decl1.getVariable().getQualifiedName() = decl2.getVariable().getQualifiedName() and - not typesCompatible(decl1.getType(), decl2.getType()) + relevantPair(decl1, decl2) and + not TypeEquivalence::equalTypes(decl1.getType(), + decl2.getType()) select decl1, "The object $@ of type " + decl1.getType().toString() + - " is not compatible with re-declaration $@ of type " + decl2.getType().toString(), decl1, - decl1.getName(), decl2, decl2.getName() + " does not use the same type names as re-declaration $@ of type " + decl2.getType().toString(), + decl1, decl1.getName(), decl2, decl2.getName() diff --git a/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql b/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql index c87e5b556c..e7eba7e42a 100644 --- a/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql +++ b/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql @@ -10,13 +10,26 @@ * readability * maintainability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra import codingstandards.cpp.Identifiers -import codingstandards.cpp.Compatible +import codingstandards.cpp.types.Compatible + +predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { + f1.getDeclaration() instanceof ExternalIdentifiers and + f1.isDefinition() and + f1.getDeclaration() = f2.getDeclaration() and + not f2.isDefinition() and + not f1.isFromTemplateInstantiation(_) and + not f2.isFromTemplateInstantiation(_) +} + +module FunDeclEquiv = + FunctionDeclarationTypeEquivalence; from FunctionDeclarationEntry f1 where @@ -32,18 +45,16 @@ where or //or one exists that is close but incompatible in some way exists(FunctionDeclarationEntry f2 | - f1.getName() = f2.getName() and - not f2.isDefinition() and - f2.getDeclaration() = f1.getDeclaration() and - //return types differ + interestedInFunctions(f1, f2) and ( - not typesCompatible(f1.getType(), f2.getType()) + //return types differ + not FunDeclEquiv::equalReturnTypes(f1, f2) or //parameter types differ - parameterTypesIncompatible(f1, f2) + not FunDeclEquiv::equalParameterTypes(f1, f2) or //parameter names differ - parameterNamesIncompatible(f1, f2) + parameterNamesUnmatched(f1, f2) ) ) ) diff --git a/c/misra/src/rules/RULE-8-4/CompatibleDeclarationObjectDefined.ql b/c/misra/src/rules/RULE-8-4/CompatibleDeclarationObjectDefined.ql index 433597cf4a..bed30d673c 100644 --- a/c/misra/src/rules/RULE-8-4/CompatibleDeclarationObjectDefined.ql +++ b/c/misra/src/rules/RULE-8-4/CompatibleDeclarationObjectDefined.ql @@ -10,13 +10,23 @@ * readability * maintainability * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra import codingstandards.cpp.Identifiers -import codingstandards.cpp.Compatible +import codingstandards.cpp.types.Compatible + +predicate relevantTypes(Type a, Type b) { + exists(VariableDeclarationEntry varA, VariableDeclarationEntry varB | + not varA = varB and + varA.getDeclaration() = varB.getDeclaration() and + a = varA.getType() and + b = varB.getType() + ) +} from VariableDeclarationEntry decl1 where @@ -27,6 +37,7 @@ where not exists(VariableDeclarationEntry decl2 | not decl2.isDefinition() and decl1.getDeclaration() = decl2.getDeclaration() and - typesCompatible(decl1.getType(), decl2.getType()) + TypeEquivalence::equalTypes(decl1.getType(), + decl2.getType()) ) select decl1, "No separate compatible declaration found for this definition." diff --git a/c/misra/src/rules/RULE-8-5/ExternalObjectOrFunctionNotDeclaredInOneFile.ql b/c/misra/src/rules/RULE-8-5/ExternalObjectOrFunctionNotDeclaredInOneFile.ql index 56e1d742a6..9a3f1c7900 100644 --- a/c/misra/src/rules/RULE-8-5/ExternalObjectOrFunctionNotDeclaredInOneFile.ql +++ b/c/misra/src/rules/RULE-8-5/ExternalObjectOrFunctionNotDeclaredInOneFile.ql @@ -7,6 +7,7 @@ * @problem.severity warning * @tags external/misra/id/rule-8-5 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-8-6/IdentifierWithExternalLinkageOneDefinition.ql b/c/misra/src/rules/RULE-8-6/IdentifierWithExternalLinkageOneDefinition.ql index 1a85775236..0781eef539 100644 --- a/c/misra/src/rules/RULE-8-6/IdentifierWithExternalLinkageOneDefinition.ql +++ b/c/misra/src/rules/RULE-8-6/IdentifierWithExternalLinkageOneDefinition.ql @@ -8,6 +8,7 @@ * @problem.severity error * @tags external/misra/id/rule-8-6 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql b/c/misra/src/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql index 824a4cf1cf..9cdd6532a9 100644 --- a/c/misra/src/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql +++ b/c/misra/src/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql @@ -12,6 +12,7 @@ * correctness * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ @@ -39,17 +40,22 @@ predicate isReferencedInTranslationUnit( ExternalIdentifiers e, ExternalIdentifierReference r, TranslationUnit t ) { r.getExternalIdentifierTarget() = e and - r.getFile() = t + // Used within the translation unit or an included header + r.getFile() = t.getAUserFile() } from ExternalIdentifiers e, ExternalIdentifierReference a1, TranslationUnit t1 where not isExcluded(e, Declarations6Package::shouldNotBeDefinedWithExternalLinkageQuery()) and + // Only report external identifiers where we see the definition + e.hasDefinition() and isReferencedInTranslationUnit(e, a1, t1) and // Not referenced in any other translation unit not exists(TranslationUnit t2 | isReferencedInTranslationUnit(e, _, t2) and not t1 = t2 - ) + ) and + // Definition is also in the same translation unit + e.getDefinition().getFile() = t1.getAUserFile() select e, "Declaration with external linkage is accessed in only one translation unit $@.", a1, a1.toString() diff --git a/c/misra/src/rules/RULE-8-8/MissingStaticSpecifierFunctionRedeclarationC.ql b/c/misra/src/rules/RULE-8-8/MissingStaticSpecifierFunctionRedeclarationC.ql index c210273cd1..c3a5ce897f 100644 --- a/c/misra/src/rules/RULE-8-8/MissingStaticSpecifierFunctionRedeclarationC.ql +++ b/c/misra/src/rules/RULE-8-8/MissingStaticSpecifierFunctionRedeclarationC.ql @@ -8,6 +8,7 @@ * @problem.severity warning * @tags external/misra/id/rule-8-8 * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.ql b/c/misra/src/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.ql index 2cb65c4fda..877ef19d2a 100644 --- a/c/misra/src/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.ql +++ b/c/misra/src/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.ql @@ -8,20 +8,17 @@ * @problem.severity warning * @tags external/misra/id/rule-8-8 * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ import cpp import codingstandards.c.misra +import codingstandards.cpp.rules.missingstaticspecifierobjectredeclarationshared.MissingStaticSpecifierObjectRedeclarationShared -from VariableDeclarationEntry redeclaration, VariableDeclarationEntry de -where - not isExcluded(redeclaration, - Declarations5Package::missingStaticSpecifierObjectRedeclarationCQuery()) and - //following implies de != redeclaration - de.hasSpecifier("static") and - not redeclaration.hasSpecifier("static") and - de.getDeclaration().isTopLevel() and - redeclaration.getDeclaration() = de.getDeclaration() -select redeclaration, "The redeclaration of $@ with internal linkage misses the static specifier.", - de, de.getName() +class MissingStaticSpecifierObjectRedeclarationCQuery extends MissingStaticSpecifierObjectRedeclarationSharedSharedQuery +{ + MissingStaticSpecifierObjectRedeclarationCQuery() { + this = Declarations5Package::missingStaticSpecifierObjectRedeclarationCQuery() + } +} diff --git a/c/misra/src/rules/RULE-8-9/UnnecessaryExposedIdentifierDeclarationC.ql b/c/misra/src/rules/RULE-8-9/UnnecessaryExposedIdentifierDeclarationC.ql index 88cf72fdcd..5dc697e425 100644 --- a/c/misra/src/rules/RULE-8-9/UnnecessaryExposedIdentifierDeclarationC.ql +++ b/c/misra/src/rules/RULE-8-9/UnnecessaryExposedIdentifierDeclarationC.ql @@ -8,6 +8,7 @@ * @problem.severity warning * @tags external/misra/id/rule-8-9 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-9-1/ObjectWithAutoStorageDurationReadBeforeInit.ql b/c/misra/src/rules/RULE-9-1/ObjectWithAutoStorageDurationReadBeforeInit.ql index b9960fc886..f3204ef2e3 100644 --- a/c/misra/src/rules/RULE-9-1/ObjectWithAutoStorageDurationReadBeforeInit.ql +++ b/c/misra/src/rules/RULE-9-1/ObjectWithAutoStorageDurationReadBeforeInit.ql @@ -8,6 +8,7 @@ * @tags external/misra/id/rule-9-1 * correctness * security + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/mandatory */ diff --git a/c/misra/src/rules/RULE-9-2/InitializerForAggregateOrUnionNotEnclosedInBraces.ql b/c/misra/src/rules/RULE-9-2/InitializerForAggregateOrUnionNotEnclosedInBraces.ql index 02ee294036..c5a9ae4814 100644 --- a/c/misra/src/rules/RULE-9-2/InitializerForAggregateOrUnionNotEnclosedInBraces.ql +++ b/c/misra/src/rules/RULE-9-2/InitializerForAggregateOrUnionNotEnclosedInBraces.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-9-2 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-9-3/PartiallyInitializedArrayWithExplicitInitializers.ql b/c/misra/src/rules/RULE-9-3/PartiallyInitializedArrayWithExplicitInitializers.ql index 231520ce50..d10c8315e1 100644 --- a/c/misra/src/rules/RULE-9-3/PartiallyInitializedArrayWithExplicitInitializers.ql +++ b/c/misra/src/rules/RULE-9-3/PartiallyInitializedArrayWithExplicitInitializers.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-9-3 * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-9-4/RepeatedInitializationOfAggregateObjectElement.ql b/c/misra/src/rules/RULE-9-4/RepeatedInitializationOfAggregateObjectElement.ql index 3566835ae3..dfe3fd8fff 100644 --- a/c/misra/src/rules/RULE-9-4/RepeatedInitializationOfAggregateObjectElement.ql +++ b/c/misra/src/rules/RULE-9-4/RepeatedInitializationOfAggregateObjectElement.ql @@ -10,6 +10,7 @@ * correctness * maintainability * readability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ @@ -61,25 +62,15 @@ int getMaxDepth(ArrayAggregateLiteral al) { // internal recursive predicate for `hasMultipleInitializerExprsForSameIndex` predicate hasMultipleInitializerExprsForSameIndexInternal( - ArrayAggregateLiteral al1, ArrayAggregateLiteral al2, Expr out_al1_expr, Expr out_al2_expr + ArrayAggregateLiteral root, Expr e1, Expr e2 ) { - exists(int shared_index, Expr al1_expr, Expr al2_expr | - // an `Expr` initializing an element of the same index in both `al1` and `al2` - shared_index = [0 .. al1.getArraySize() - 1] and - al1_expr = al1.getAnElementExpr(shared_index) and - al2_expr = al2.getAnElementExpr(shared_index) and - // but not the same `Expr` - not al1_expr = al2_expr and - ( - // case A - the children are not aggregate literals - // holds if `al1` and `al2` both hold for .getElement[sharedIndex] - not al1_expr instanceof ArrayAggregateLiteral and - out_al1_expr = al1_expr and - out_al2_expr = al2_expr - or - // case B - `al1` and `al2` both have an aggregate literal child at the same index, so recurse - hasMultipleInitializerExprsForSameIndexInternal(al1_expr, al2_expr, out_al1_expr, out_al2_expr) - ) + root = e1 and root = e2 + or + exists(ArrayAggregateLiteral parent1, ArrayAggregateLiteral parent2, int shared_index | + hasMultipleInitializerExprsForSameIndexInternal(root, parent1, parent2) and + shared_index = [0 .. parent1.getArraySize() - 1] and + e1 = parent1.getAnElementExpr(shared_index) and + e2 = parent2.getAnElementExpr(shared_index) ) } @@ -87,7 +78,15 @@ predicate hasMultipleInitializerExprsForSameIndexInternal( * Holds if `expr1` and `expr2` both initialize the same array element of `root`. */ predicate hasMultipleInitializerExprsForSameIndex(ArrayAggregateLiteral root, Expr expr1, Expr expr2) { - hasMultipleInitializerExprsForSameIndexInternal(root, root, expr1, expr2) + hasMultipleInitializerExprsForSameIndexInternal(root, expr1, expr2) and + not root = expr1 and + not root = expr2 and + not expr1 = expr2 and + ( + not expr1 instanceof ArrayAggregateLiteral + or + not expr2 instanceof ArrayAggregateLiteral + ) } /** diff --git a/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql b/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql new file mode 100644 index 0000000000..5f7fb803d6 --- /dev/null +++ b/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql @@ -0,0 +1,76 @@ +/** + * @id c/misra/uninitialized-atomic-object + * @name RULE-9-7: Atomic objects shall be appropriately initialized before being accessed + * @description Atomic objects that do not have static storage duration shall be initialized with a + * value or by using 'atomic_init()'. + * @kind problem + * @precision high + * @problem.severity warning + * @tags external/misra/id/rule-9-7 + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.StdFunctionOrMacro +import semmle.code.cpp.controlflow.Dominance + +class ThreadSpawningFunction extends Function { + ThreadSpawningFunction() { + this.hasName("pthread_create") + or + this.hasName("thrd_create") + or + exists(FunctionCall fc | + fc.getTarget() instanceof ThreadSpawningFunction and + fc.getEnclosingFunction() = this + ) + } +} + +class AtomicInitAddressOfExpr extends AddressOfExpr { + AtomicInitAddressOfExpr() { + // StdFunctionOrMacro arguments are not necessarily reliable, so we look for any AddressOfExpr + // that is an argument to a call to `atomic_init`. + exists(AtomicInitCall c | this = c.getAnArgument()) + } +} + +ControlFlowNode getARequiredInitializationPoint(LocalScopeVariable v) { + result = v.getParentScope().(BlockStmt).getFollowingStmt() + or + exists(DeclStmt decl | + decl.getADeclaration() = v and + result = + any(FunctionCall fc | + fc.getTarget() instanceof ThreadSpawningFunction and + fc.getEnclosingBlock().getEnclosingBlock*() = v.getParentScope() and + fc.getAPredecessor*() = decl + ) + ) +} + +from VariableDeclarationEntry decl, Variable v +where + not isExcluded(decl, Concurrency7Package::uninitializedAtomicObjectQuery()) and + v = decl.getVariable() and + v.getUnderlyingType().hasSpecifier("atomic") and + not v.isTopLevel() and + not exists(v.getInitializer()) and + exists(ControlFlowNode missingInitPoint | + missingInitPoint = getARequiredInitializationPoint(v) and + // Check for `atomic_init(&v)` + not exists(AtomicInitAddressOfExpr initialization | + initialization.getOperand().(VariableAccess).getTarget() = v and + dominates(initialization, missingInitPoint) + ) and + // Check for `unknown_func(&v)` which may call `atomic_init` on `v`. + not exists(FunctionCall fc | + fc.getAnArgument().(AddressOfExpr).getOperand().(VariableAccess).getTarget() = v and + dominates(fc, missingInitPoint) + ) + ) +select decl, + "Atomic object '" + v.getName() + "' has no initializer or corresponding use of 'atomic_init()'." diff --git a/c/misra/test/c/misra/EssentialTypes.expected b/c/misra/test/c/misra/EssentialTypes.expected index 8bf299bd63..95976fe2ab 100644 --- a/c/misra/test/c/misra/EssentialTypes.expected +++ b/c/misra/test/c/misra/EssentialTypes.expected @@ -1,3 +1,9 @@ +| file://:0:0:0:0 | 0 | signed char | signed char | essentially Signed type | +| file://:0:0:0:0 | 0 | signed char | signed char | essentially Signed type | +| file://:0:0:0:0 | 0 | signed char | signed char | essentially Signed type | +| file://:0:0:0:0 | 0 | signed char | signed char | essentially Signed type | +| file://:0:0:0:0 | 0 | signed char | signed char | essentially Signed type | +| file://:0:0:0:0 | 0 | signed char | signed char | essentially Signed type | | test.c:4:20:4:20 | 1 | signed char | signed char | essentially Signed type | | test.c:4:20:4:20 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | | test.c:5:23:5:23 | 1 | signed char | signed char | essentially Signed type | @@ -38,3 +44,397 @@ | test.c:26:3:26:3 | f | float | float | essentially Floating type | | test.c:27:3:27:5 | f32 | float32_t | float32_t | essentially Floating type | | test.c:28:3:28:6 | cf32 | float | float | essentially Floating type | +| test.c:32:3:32:3 | 1 | signed char | signed char | essentially Signed type | +| test.c:33:3:33:4 | 1 | unsigned char | unsigned char | essentially Unsigned type | +| test.c:34:3:34:5 | 1 | unsigned long | unsigned long | essentially Unsigned type | +| test.c:38:13:38:16 | 1 | bool | bool | essentially Boolean type | +| test.c:38:13:38:16 | (bool)... | bool | bool | essentially Boolean type | +| test.c:39:20:39:20 | 1 | signed char | signed char | essentially Signed type | +| test.c:39:20:39:20 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:40:23:40:23 | 1 | signed char | signed char | essentially Signed type | +| test.c:40:23:40:23 | (unsigned short)... | unsigned short | unsigned short | essentially Unsigned type | +| test.c:41:17:41:18 | 1 | signed char | signed char | essentially Signed type | +| test.c:42:21:42:21 | 1 | signed char | signed char | essentially Signed type | +| test.c:42:21:42:21 | (signed short)... | signed short | signed short | essentially Signed type | +| test.c:44:3:44:4 | ! ... | bool | bool | essentially Boolean type | +| test.c:44:4:44:4 | b | bool | bool | essentially Boolean type | +| test.c:45:3:45:4 | ! ... | bool | bool | essentially Boolean type | +| test.c:45:4:45:4 | u | unsigned int | unsigned int | essentially Unsigned type | +| test.c:46:3:46:5 | ! ... | bool | bool | essentially Boolean type | +| test.c:46:4:46:5 | us | unsigned short | unsigned short | essentially Unsigned type | +| test.c:47:3:47:4 | ! ... | bool | bool | essentially Boolean type | +| test.c:47:4:47:4 | s | signed int | signed int | essentially Signed type | +| test.c:48:3:48:5 | ! ... | bool | bool | essentially Boolean type | +| test.c:48:4:48:5 | ss | signed short | signed short | essentially Signed type | +| test.c:50:3:50:4 | ~ ... | int | int | essentially Signed type | +| test.c:50:4:50:4 | (int)... | int | int | essentially Signed type | +| test.c:50:4:50:4 | b | bool | bool | essentially Boolean type | +| test.c:51:3:51:4 | ~ ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:51:4:51:4 | u | unsigned int | unsigned int | essentially Unsigned type | +| test.c:52:3:52:5 | ~ ... | unsigned short | unsigned short | essentially Unsigned type | +| test.c:52:4:52:5 | (int)... | int | int | essentially Signed type | +| test.c:52:4:52:5 | us | unsigned short | unsigned short | essentially Unsigned type | +| test.c:53:3:53:4 | ~ ... | signed int | signed int | essentially Signed type | +| test.c:53:4:53:4 | s | signed int | signed int | essentially Signed type | +| test.c:54:3:54:5 | ~ ... | int | int | essentially Signed type | +| test.c:54:4:54:5 | (int)... | int | int | essentially Signed type | +| test.c:54:4:54:5 | ss | signed short | signed short | essentially Signed type | +| test.c:63:30:63:32 | ((unnamed enum))... | (unnamed enum) | (unnamed enum) | essentially Enum Type | +| test.c:63:30:63:32 | EC5 | (unnamed enum) | (unnamed enum) | essentially Enum Type | +| test.c:70:3:70:5 | EC1 | signed char | signed char | essentially Signed type | +| test.c:71:3:71:5 | EC2 | E1 | E1 | essentially Enum Type | +| test.c:72:3:72:5 | EC3 | (unnamed enum) | (unnamed enum) | essentially Enum Type | +| test.c:73:3:73:5 | EC4 | (unnamed enum) | (unnamed enum) | essentially Enum Type | +| test.c:74:3:74:5 | EC5 | (unnamed enum) | (unnamed enum) | essentially Enum Type | +| test.c:75:3:75:5 | EC6 | (unnamed enum) | (unnamed enum) | essentially Enum Type | +| test.c:79:3:79:5 | 97 | char | char | essentially Character type | +| test.c:80:3:80:6 | 10 | char | char | essentially Character type | +| test.c:81:3:81:6 | 0 | char | char | essentially Character type | +| test.c:87:16:87:16 | 0 | signed char | signed char | essentially Signed type | +| test.c:87:16:87:16 | (uint8_t)... | uint8_t | uint8_t | essentially Unsigned type | +| test.c:88:18:88:18 | 0 | signed char | signed char | essentially Signed type | +| test.c:88:18:88:18 | (uint16_t)... | uint16_t | uint16_t | essentially Unsigned type | +| test.c:89:18:89:18 | 0 | signed char | signed char | essentially Signed type | +| test.c:89:18:89:18 | (uint32_t)... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:90:15:90:15 | 0 | signed char | signed char | essentially Signed type | +| test.c:90:15:90:15 | (int8_t)... | int8_t | int8_t | essentially Signed type | +| test.c:91:17:91:17 | 0 | signed char | signed char | essentially Signed type | +| test.c:91:17:91:17 | (int16_t)... | int16_t | int16_t | essentially Signed type | +| test.c:92:16:92:17 | 0 | signed char | signed char | essentially Signed type | +| test.c:94:3:94:4 | (int)... | int | int | essentially Signed type | +| test.c:94:3:94:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:94:3:94:9 | ... & ... | uint8_t | uint8_t | essentially Unsigned type | +| test.c:94:8:94:9 | (int)... | int | int | essentially Signed type | +| test.c:94:8:94:9 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:95:3:95:5 | (int)... | int | int | essentially Signed type | +| test.c:95:3:95:5 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:95:3:95:10 | ... & ... | uint16_t | uint16_t | essentially Unsigned type | +| test.c:95:9:95:10 | (int)... | int | int | essentially Signed type | +| test.c:95:9:95:10 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:96:3:96:4 | (int)... | int | int | essentially Signed type | +| test.c:96:3:96:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:96:3:96:10 | ... & ... | uint16_t | uint16_t | essentially Unsigned type | +| test.c:96:8:96:10 | (int)... | int | int | essentially Signed type | +| test.c:96:8:96:10 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:97:3:97:5 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:97:3:97:10 | ... & ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:97:9:97:10 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:97:9:97:10 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:98:3:98:4 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:98:3:98:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:98:3:98:10 | ... & ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:98:8:98:10 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:99:3:99:5 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:99:3:99:11 | ... & ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:99:9:99:11 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:99:9:99:11 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:100:3:100:5 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:100:3:100:5 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:100:3:100:11 | ... & ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:100:9:100:11 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:102:3:102:4 | (int)... | int | int | essentially Signed type | +| test.c:102:3:102:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:102:3:102:9 | ... \| ... | uint8_t | uint8_t | essentially Unsigned type | +| test.c:102:8:102:9 | (int)... | int | int | essentially Signed type | +| test.c:102:8:102:9 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:103:3:103:5 | (int)... | int | int | essentially Signed type | +| test.c:103:3:103:5 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:103:3:103:10 | ... \| ... | uint16_t | uint16_t | essentially Unsigned type | +| test.c:103:9:103:10 | (int)... | int | int | essentially Signed type | +| test.c:103:9:103:10 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:104:3:104:4 | (int)... | int | int | essentially Signed type | +| test.c:104:3:104:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:104:3:104:10 | ... \| ... | uint16_t | uint16_t | essentially Unsigned type | +| test.c:104:8:104:10 | (int)... | int | int | essentially Signed type | +| test.c:104:8:104:10 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:105:3:105:5 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:105:3:105:10 | ... \| ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:105:9:105:10 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:105:9:105:10 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:106:3:106:4 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:106:3:106:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:106:3:106:10 | ... \| ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:106:8:106:10 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:107:3:107:5 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:107:3:107:11 | ... \| ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:107:9:107:11 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:107:9:107:11 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:108:3:108:5 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:108:3:108:5 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:108:3:108:11 | ... \| ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:108:9:108:11 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:110:3:110:4 | (int)... | int | int | essentially Signed type | +| test.c:110:3:110:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:110:3:110:9 | ... ^ ... | uint8_t | uint8_t | essentially Unsigned type | +| test.c:110:8:110:9 | (int)... | int | int | essentially Signed type | +| test.c:110:8:110:9 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:111:3:111:5 | (int)... | int | int | essentially Signed type | +| test.c:111:3:111:5 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:111:3:111:10 | ... ^ ... | uint16_t | uint16_t | essentially Unsigned type | +| test.c:111:9:111:10 | (int)... | int | int | essentially Signed type | +| test.c:111:9:111:10 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:112:3:112:4 | (int)... | int | int | essentially Signed type | +| test.c:112:3:112:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:112:3:112:10 | ... ^ ... | uint16_t | uint16_t | essentially Unsigned type | +| test.c:112:8:112:10 | (int)... | int | int | essentially Signed type | +| test.c:112:8:112:10 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:113:3:113:5 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:113:3:113:10 | ... ^ ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:113:9:113:10 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:113:9:113:10 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:114:3:114:4 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:114:3:114:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:114:3:114:10 | ... ^ ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:114:8:114:10 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:115:3:115:5 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:115:3:115:11 | ... ^ ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:115:9:115:11 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:115:9:115:11 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:116:3:116:5 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:116:3:116:5 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:116:3:116:11 | ... ^ ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:116:9:116:11 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:118:3:118:4 | (int)... | int | int | essentially Signed type | +| test.c:118:3:118:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:118:3:118:9 | ... & ... | int8_t | int8_t | essentially Signed type | +| test.c:118:8:118:9 | (int)... | int | int | essentially Signed type | +| test.c:118:8:118:9 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:119:3:119:5 | (int)... | int | int | essentially Signed type | +| test.c:119:3:119:5 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:119:3:119:10 | ... & ... | int16_t | int16_t | essentially Signed type | +| test.c:119:9:119:10 | (int)... | int | int | essentially Signed type | +| test.c:119:9:119:10 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:120:3:120:4 | (int)... | int | int | essentially Signed type | +| test.c:120:3:120:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:120:3:120:10 | ... & ... | int16_t | int16_t | essentially Signed type | +| test.c:120:8:120:10 | (int)... | int | int | essentially Signed type | +| test.c:120:8:120:10 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:121:3:121:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:121:3:121:10 | ... & ... | int32_t | int32_t | essentially Signed type | +| test.c:121:9:121:10 | (int)... | int | int | essentially Signed type | +| test.c:121:9:121:10 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:122:3:122:4 | (int)... | int | int | essentially Signed type | +| test.c:122:3:122:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:122:3:122:10 | ... & ... | int32_t | int32_t | essentially Signed type | +| test.c:122:8:122:10 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:123:3:123:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:123:3:123:11 | ... & ... | int32_t | int32_t | essentially Signed type | +| test.c:123:9:123:11 | (int)... | int | int | essentially Signed type | +| test.c:123:9:123:11 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:124:3:124:5 | (int)... | int | int | essentially Signed type | +| test.c:124:3:124:5 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:124:3:124:11 | ... & ... | int32_t | int32_t | essentially Signed type | +| test.c:124:9:124:11 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:126:3:126:4 | (int)... | int | int | essentially Signed type | +| test.c:126:3:126:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:126:3:126:9 | ... \| ... | int8_t | int8_t | essentially Signed type | +| test.c:126:8:126:9 | (int)... | int | int | essentially Signed type | +| test.c:126:8:126:9 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:127:3:127:5 | (int)... | int | int | essentially Signed type | +| test.c:127:3:127:5 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:127:3:127:10 | ... \| ... | int16_t | int16_t | essentially Signed type | +| test.c:127:9:127:10 | (int)... | int | int | essentially Signed type | +| test.c:127:9:127:10 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:128:3:128:4 | (int)... | int | int | essentially Signed type | +| test.c:128:3:128:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:128:3:128:10 | ... \| ... | int16_t | int16_t | essentially Signed type | +| test.c:128:8:128:10 | (int)... | int | int | essentially Signed type | +| test.c:128:8:128:10 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:129:3:129:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:129:3:129:10 | ... \| ... | int32_t | int32_t | essentially Signed type | +| test.c:129:9:129:10 | (int)... | int | int | essentially Signed type | +| test.c:129:9:129:10 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:130:3:130:4 | (int)... | int | int | essentially Signed type | +| test.c:130:3:130:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:130:3:130:10 | ... \| ... | int32_t | int32_t | essentially Signed type | +| test.c:130:8:130:10 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:131:3:131:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:131:3:131:11 | ... \| ... | int32_t | int32_t | essentially Signed type | +| test.c:131:9:131:11 | (int)... | int | int | essentially Signed type | +| test.c:131:9:131:11 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:132:3:132:5 | (int)... | int | int | essentially Signed type | +| test.c:132:3:132:5 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:132:3:132:11 | ... \| ... | int32_t | int32_t | essentially Signed type | +| test.c:132:9:132:11 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:134:3:134:4 | (int)... | int | int | essentially Signed type | +| test.c:134:3:134:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:134:3:134:9 | ... ^ ... | int8_t | int8_t | essentially Signed type | +| test.c:134:8:134:9 | (int)... | int | int | essentially Signed type | +| test.c:134:8:134:9 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:135:3:135:5 | (int)... | int | int | essentially Signed type | +| test.c:135:3:135:5 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:135:3:135:10 | ... ^ ... | int16_t | int16_t | essentially Signed type | +| test.c:135:9:135:10 | (int)... | int | int | essentially Signed type | +| test.c:135:9:135:10 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:136:3:136:4 | (int)... | int | int | essentially Signed type | +| test.c:136:3:136:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:136:3:136:10 | ... ^ ... | int16_t | int16_t | essentially Signed type | +| test.c:136:8:136:10 | (int)... | int | int | essentially Signed type | +| test.c:136:8:136:10 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:137:3:137:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:137:3:137:10 | ... ^ ... | int32_t | int32_t | essentially Signed type | +| test.c:137:9:137:10 | (int)... | int | int | essentially Signed type | +| test.c:137:9:137:10 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:138:3:138:4 | (int)... | int | int | essentially Signed type | +| test.c:138:3:138:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:138:3:138:10 | ... ^ ... | int32_t | int32_t | essentially Signed type | +| test.c:138:8:138:10 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:139:3:139:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:139:3:139:11 | ... ^ ... | int32_t | int32_t | essentially Signed type | +| test.c:139:9:139:11 | (int)... | int | int | essentially Signed type | +| test.c:139:9:139:11 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:140:3:140:5 | (int)... | int | int | essentially Signed type | +| test.c:140:3:140:5 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:140:3:140:11 | ... ^ ... | int32_t | int32_t | essentially Signed type | +| test.c:140:9:140:11 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:142:3:142:5 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:142:3:142:11 | ... & ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:142:9:142:11 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:142:9:142:11 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:143:3:143:5 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:143:3:143:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:143:3:143:11 | ... & ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:143:9:143:11 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:144:3:144:4 | (int)... | int | int | essentially Signed type | +| test.c:144:3:144:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:144:3:144:10 | ... & ... | int | int | essentially Signed type | +| test.c:144:8:144:10 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:145:3:145:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:145:3:145:10 | ... & ... | int | int | essentially Signed type | +| test.c:145:9:145:10 | (int)... | int | int | essentially Signed type | +| test.c:145:9:145:10 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:146:3:146:4 | (int)... | int | int | essentially Signed type | +| test.c:146:3:146:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:146:3:146:9 | ... & ... | int | int | essentially Signed type | +| test.c:146:8:146:9 | (int)... | int | int | essentially Signed type | +| test.c:146:8:146:9 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:147:3:147:4 | (int)... | int | int | essentially Signed type | +| test.c:147:3:147:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:147:3:147:9 | ... & ... | int | int | essentially Signed type | +| test.c:147:8:147:9 | (int)... | int | int | essentially Signed type | +| test.c:147:8:147:9 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:149:3:149:5 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:149:3:149:11 | ... \| ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:149:9:149:11 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:149:9:149:11 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:150:3:150:5 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:150:3:150:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:150:3:150:11 | ... \| ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:150:9:150:11 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:151:3:151:4 | (int)... | int | int | essentially Signed type | +| test.c:151:3:151:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:151:3:151:10 | ... \| ... | int | int | essentially Signed type | +| test.c:151:8:151:10 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:152:3:152:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:152:3:152:10 | ... \| ... | int | int | essentially Signed type | +| test.c:152:9:152:10 | (int)... | int | int | essentially Signed type | +| test.c:152:9:152:10 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:153:3:153:4 | (int)... | int | int | essentially Signed type | +| test.c:153:3:153:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:153:3:153:9 | ... \| ... | int | int | essentially Signed type | +| test.c:153:8:153:9 | (int)... | int | int | essentially Signed type | +| test.c:153:8:153:9 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:154:3:154:4 | (int)... | int | int | essentially Signed type | +| test.c:154:3:154:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:154:3:154:9 | ... \| ... | int | int | essentially Signed type | +| test.c:154:8:154:9 | (int)... | int | int | essentially Signed type | +| test.c:154:8:154:9 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:156:3:156:5 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:156:3:156:11 | ... ^ ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:156:9:156:11 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:156:9:156:11 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:157:3:157:5 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:157:3:157:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:157:3:157:11 | ... ^ ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:157:9:157:11 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:158:3:158:4 | (int)... | int | int | essentially Signed type | +| test.c:158:3:158:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:158:3:158:10 | ... ^ ... | int | int | essentially Signed type | +| test.c:158:8:158:10 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:159:3:159:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:159:3:159:10 | ... ^ ... | int | int | essentially Signed type | +| test.c:159:9:159:10 | (int)... | int | int | essentially Signed type | +| test.c:159:9:159:10 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:160:3:160:4 | (int)... | int | int | essentially Signed type | +| test.c:160:3:160:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:160:3:160:9 | ... ^ ... | int | int | essentially Signed type | +| test.c:160:8:160:9 | (int)... | int | int | essentially Signed type | +| test.c:160:8:160:9 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:161:3:161:4 | (int)... | int | int | essentially Signed type | +| test.c:161:3:161:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:161:3:161:9 | ... ^ ... | int | int | essentially Signed type | +| test.c:161:8:161:9 | (int)... | int | int | essentially Signed type | +| test.c:161:8:161:9 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:165:16:165:17 | 1 | signed char | signed char | essentially Signed type | +| test.c:170:3:170:4 | 1 | unsigned char | unsigned char | essentially Unsigned type | +| test.c:170:3:170:9 | ... << ... | unsigned char | unsigned char | essentially Unsigned type | +| test.c:170:9:170:9 | 1 | signed char | signed char | essentially Signed type | +| test.c:171:3:171:6 | 256 | unsigned short | unsigned short | essentially Unsigned type | +| test.c:171:3:171:11 | ... << ... | unsigned short | unsigned short | essentially Unsigned type | +| test.c:171:11:171:11 | 1 | signed char | signed char | essentially Signed type | +| test.c:172:3:172:8 | 65536 | unsigned int | unsigned int | essentially Unsigned type | +| test.c:172:3:172:13 | ... << ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:172:13:172:13 | 1 | signed char | signed char | essentially Signed type | +| test.c:173:3:173:4 | 2 | unsigned char | unsigned char | essentially Unsigned type | +| test.c:173:3:173:9 | ... >> ... | unsigned char | unsigned char | essentially Unsigned type | +| test.c:173:9:173:9 | 1 | signed char | signed char | essentially Signed type | +| test.c:174:3:174:8 | 32768 | unsigned short | unsigned short | essentially Unsigned type | +| test.c:174:3:174:13 | ... >> ... | unsigned short | unsigned short | essentially Unsigned type | +| test.c:174:13:174:13 | 1 | signed char | signed char | essentially Signed type | +| test.c:175:3:175:13 | 2147483648 | unsigned int | unsigned int | essentially Unsigned type | +| test.c:175:3:175:18 | ... >> ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:175:18:175:18 | 1 | signed char | signed char | essentially Signed type | +| test.c:176:3:176:14 | 4294967295 | unsigned long | unsigned long | essentially Unsigned type | +| test.c:176:3:176:19 | ... << ... | unsigned long | unsigned long | essentially Unsigned type | +| test.c:176:3:176:19 | ... << ... | unsigned long | unsigned long long | essentially Unsigned type | +| test.c:176:3:176:19 | ... << ... | unsigned long long | unsigned long | essentially Unsigned type | +| test.c:176:3:176:19 | ... << ... | unsigned long long | unsigned long long | essentially Unsigned type | +| test.c:176:19:176:19 | 1 | signed char | signed char | essentially Signed type | +| test.c:181:3:181:6 | 256 | unsigned short | unsigned short | essentially Unsigned type | +| test.c:181:3:181:11 | ... >> ... | unsigned char | unsigned char | essentially Unsigned type | +| test.c:181:11:181:11 | 1 | signed char | signed char | essentially Signed type | +| test.c:182:3:182:8 | 65536 | unsigned int | unsigned int | essentially Unsigned type | +| test.c:182:3:182:13 | ... >> ... | unsigned short | unsigned short | essentially Unsigned type | +| test.c:182:13:182:13 | 1 | signed char | signed char | essentially Signed type | +| test.c:183:3:183:13 | 4294967296 | unsigned long | unsigned long | essentially Unsigned type | +| test.c:183:3:183:18 | ... >> ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:183:18:183:18 | 1 | signed char | signed char | essentially Signed type | +| test.c:184:3:184:6 | 255 | unsigned char | unsigned char | essentially Unsigned type | +| test.c:184:3:184:11 | ... << ... | unsigned short | unsigned short | essentially Unsigned type | +| test.c:184:11:184:11 | 1 | signed char | signed char | essentially Signed type | +| test.c:185:3:185:8 | 65535 | unsigned short | unsigned short | essentially Unsigned type | +| test.c:185:3:185:13 | ... << ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:185:13:185:13 | 1 | signed char | signed char | essentially Signed type | +| test.c:189:3:189:6 | 255 | unsigned char | unsigned char | essentially Unsigned type | +| test.c:189:3:189:13 | ... >> ... | unsigned char | unsigned char | essentially Unsigned type | +| test.c:189:11:189:13 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:190:3:190:8 | 65535 | unsigned short | unsigned short | essentially Unsigned type | +| test.c:190:3:190:15 | ... >> ... | unsigned short | unsigned short | essentially Unsigned type | +| test.c:190:13:190:15 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:191:3:191:13 | 4294967295 | unsigned int | unsigned int | essentially Unsigned type | +| test.c:191:3:191:20 | ... >> ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:191:18:191:20 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:192:3:192:6 | 255 | unsigned char | unsigned char | essentially Unsigned type | +| test.c:192:3:192:13 | ... << ... | unsigned char | unsigned char | essentially Unsigned type | +| test.c:192:11:192:13 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:193:3:193:8 | 65535 | unsigned short | unsigned short | essentially Unsigned type | +| test.c:193:3:193:15 | ... << ... | unsigned short | unsigned short | essentially Unsigned type | +| test.c:193:13:193:15 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:194:3:194:13 | 4294967295 | unsigned int | unsigned int | essentially Unsigned type | +| test.c:194:3:194:20 | ... << ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:194:18:194:20 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:197:3:197:5 | 257 | short | short | essentially Signed type | +| test.c:197:3:197:5 | 257 | short | signed short | essentially Signed type | +| test.c:197:3:197:5 | 257 | signed short | short | essentially Signed type | +| test.c:197:3:197:5 | 257 | signed short | signed short | essentially Signed type | +| test.c:197:3:197:10 | ... >> ... | int | int | essentially Signed type | +| test.c:197:10:197:10 | 1 | signed char | signed char | essentially Signed type | +| test.c:198:3:198:7 | 65537 | int | int | essentially Signed type | +| test.c:198:3:198:7 | 65537 | int | signed int | essentially Signed type | +| test.c:198:3:198:7 | 65537 | signed int | int | essentially Signed type | +| test.c:198:3:198:7 | 65537 | signed int | signed int | essentially Signed type | +| test.c:198:3:198:12 | ... >> ... | int | int | essentially Signed type | +| test.c:198:12:198:12 | 1 | signed char | signed char | essentially Signed type | +| test.c:199:3:199:12 | 4294967297 | long | long | essentially Signed type | +| test.c:199:3:199:17 | ... >> ... | long | long | essentially Signed type | +| test.c:199:17:199:17 | 1 | signed char | signed char | essentially Signed type | diff --git a/c/misra/test/c/misra/test.c b/c/misra/test/c/misra/test.c index 8788f7e93a..36a3eb0b10 100644 --- a/c/misra/test/c/misra/test.c +++ b/c/misra/test/c/misra/test.c @@ -26,4 +26,175 @@ void testCategoriesForComplexTypes() { f; // Should be essentially Floating type f32; // Should be essentially Floating type cf32; // Should be essentially Floating type +} + +void testConstants() { + 1; // Essentially signed char + 1U; // Essentially unsigned char + 1UL; // Essentially unsigned long +} + +void testUnary() { + _Bool b = true; + unsigned int u = 1; + unsigned short us = 1; + signed int s = 1; + signed short ss = 1; + + !b; // Should be boolean + !u; // Should be boolean + !us; // Should be boolean + !s; // Should be boolean + !ss; // Should be boolean + + ~b; // Should be essentially signed + ~u; // Should be essentially unsigned + ~us; // Should be essentially unsigned + ~s; // Should be essentially signed + ~ss; // Should be essentially signed +} + +enum { EC1 }; +enum E1 { EC2 }; +typedef enum { EC3 } E2; + +enum { EC4 } g; + +enum { EC5 } test() { return EC5; } + +struct S1 { + enum { EC6 } m; +}; + +void testEnums() { + EC1; // Should be essentially signed + EC2; // Should be essentially enum + EC3; // Should be essentially enum + EC4; // Should be essentially enum + EC5; // Should be essentially enum + EC6; // Should be essentially enum +} + +void testControlChar() { + 'a'; // Essentially char + '\n'; // Essentially char + '\0'; // Essentially char +} + +#include +// clang-format off +void testBitwise() { // Clang format disabled to avoid confusion with variable declarations + uint8_t u8 = 0; + uint16_t u16 = 0; + uint32_t u32 = 0; + int8_t s8 = 0; + int16_t s16 = 0; + int32_t s32 = 0; + + u8 & u8; // Essentially unsigned, char + u16 & u8; // Essentially unsigned, short + u8 & u16; // Essentially unsigned, short + u32 & u8; // Essentially unsigned, int + u8 & u32; // Essentially unsigned, int + u32 & u16; // Essentially unsigned, int + u16 & u32; // Essentially unsigned, int + + u8 | u8; // Essentially unsigned, char + u16 | u8; // Essentially unsigned, short + u8 | u16; // Essentially unsigned, short + u32 | u8; // Essentially unsigned, int + u8 | u32; // Essentially unsigned, int + u32 | u16; // Essentially unsigned, int + u16 | u32; // Essentially unsigned, int + + u8 ^ u8; // Essentially unsigned, char + u16 ^ u8; // Essentially unsigned, short + u8 ^ u16; // Essentially unsigned, short + u32 ^ u8; // Essentially unsigned, int + u8 ^ u32; // Essentially unsigned, int + u32 ^ u16; // Essentially unsigned, int + u16 ^ u32; // Essentially unsigned, int + + s8 & s8; // Essentially signed, char + s16 & s8; // Essentially signed, short + s8 & s16; // Essentially signed, short + s32 & s8; // Essentially signed, int + s8 & s32; // Essentially signed, int + s32 & s16; // Essentially signed, int + s16 & s32; // Essentially signed, int + + s8 | s8; // Essentially signed, char + s16 | s8; // Essentially signed, short + s8 | s16; // Essentially signed, short + s32 | s8; // Essentially signed, int + s8 | s32; // Essentially signed, int + s32 | s16; // Essentially signed, int + s16 | s32; // Essentially signed, int + + s8 ^ s8; // Essentially signed, char + s16 ^ s8; // Essentially signed, short + s8 ^ s16; // Essentially signed, short + s32 ^ s8; // Essentially signed, int + s8 ^ s32; // Essentially signed, int + s32 ^ s16; // Essentially signed, int + s16 ^ s32; // Essentially signed, int + + u32 & s32; // Essentially unsigned, int + s32 & u32; // Essentially unsigned, int + u8 & s32; // Essentially signed, int + s32 & u8; // Essentially signed, int + u8 & s8; // Essentially signed, int + s8 & u8; // Essentially signed, int + + u32 | s32; // Essentially signed, int + s32 | u32; // Essentially signed, int + u8 | s32; // Essentially signed, int + s32 | u8; // Essentially signed, int + u8 | s8; // Essentially signed, int + s8 | u8; // Essentially signed, int + + u32 ^ s32; // Essentially signed, int + s32 ^ u32; // Essentially signed, int + u8 ^ s32; // Essentially signed, int + s32 ^ u8; // Essentially signed, int + u8 ^ s8; // Essentially signed, int + s8 ^ u8; // Essentially signed, int +} +// clang-format on +void testShifts() { + int32_t s32 = 1; + + // Left hand is unsigned and both are constants, so UTLR + // In these cases the UTLR is the same as the essential type of + // the left operand + 1U << 1; // Essentially unsigned char + 256U << 1; // Essentially unsigned short + 65536U << 1; // Essentially unsigned int + 2U >> 1; // Essentially unsigned char + 32768U >> 1; // Essentially unsigned short - 2^15 >> 1 = 2^14 + 2147483648U >> 1; // Essentially unsigned int - 2^31 >> 1 = 2^30 + 4294967295LU << 1; // Essentially unsigned long + + // Left hand is unsigned and both are constants, so UTLR + // In these cases the UTLR is not the same as the essential type of + // the left operand + 256U >> 1; // Essentially unsigned char + 65536U >> 1; // Essentially unsigned short + 4294967296U >> 1; // Essentially unsigned int + 255U << 1; // Essentially unsigned short + 65535U << 1; // Essentially unsigned int + + // Left hand is unsigned, but left isn't a constant, so essential type of left + // operand + 255U >> s32; // Essentially unsigned char + 65535U >> s32; // Essentially unsigned short + 4294967295U >> s32; // Essentially unsigned int + 255U << s32; // Essentially unsigned char + 65535U << s32; // Essentially unsigned short + 4294967295U << s32; // Essentially unsigned int + + // Left hand operand signed int, so result is standard type + 257 >> 1; // Essentially signed int + 65537 >> 1; // Essentially signed int + 4294967297 >> 1; // Essentially signed long } \ No newline at end of file diff --git a/c/misra/test/codeql-pack.lock.yml b/c/misra/test/codeql-pack.lock.yml index 514e6963d0..a45ea8f438 100644 --- a/c/misra/test/codeql-pack.lock.yml +++ b/c/misra/test/codeql-pack.lock.yml @@ -2,13 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.9.3 + version: 4.0.3 codeql/dataflow: - version: 0.0.4 + version: 2.0.3 + codeql/mad: + version: 1.0.19 + codeql/rangeanalysis: + version: 1.0.19 codeql/ssa: - version: 0.1.5 + version: 1.0.19 codeql/tutorial: - version: 0.1.5 + version: 1.0.19 + codeql/typeflow: + version: 1.0.19 + codeql/typetracking: + version: 2.0.3 codeql/util: - version: 0.1.5 + version: 2.0.6 + codeql/xml: + version: 1.0.19 compiled: false diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index 5d19f0877f..5f22b18e91 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.32.0-dev +version: 2.52.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/misra/test/rules/DIR-4-11/CheckMathLibraryFunctionParameters.testref b/c/misra/test/rules/DIR-4-11/CheckMathLibraryFunctionParameters.testref new file mode 100644 index 0000000000..50cf3fcb51 --- /dev/null +++ b/c/misra/test/rules/DIR-4-11/CheckMathLibraryFunctionParameters.testref @@ -0,0 +1 @@ +c/common/test/rules/uncheckedrangedomainpoleerrors/UncheckedRangeDomainPoleErrors.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.expected b/c/misra/test/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.expected new file mode 100644 index 0000000000..d5d5892975 --- /dev/null +++ b/c/misra/test/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.expected @@ -0,0 +1,18 @@ +| test.c:32:5:32:7 | call to sin | Call to periodic trigonometric function sin with maximum argument absolute value of 31.4, which exceeds the recommended maximum of pi. | +| test.c:33:5:33:7 | call to cos | Call to periodic trigonometric function cos with maximum argument absolute value of 31.4, which exceeds the recommended maximum of pi. | +| test.c:34:5:34:7 | call to tan | Call to periodic trigonometric function tan with maximum argument absolute value of 31.4, which exceeds the recommended maximum of pi. | +| test.c:38:5:38:7 | call to sin | Call to periodic trigonometric function sin with maximum argument absolute value of 31.4, which exceeds the recommended maximum of pi. | +| test.c:39:5:39:7 | call to cos | Call to periodic trigonometric function cos with maximum argument absolute value of 31.4, which exceeds the recommended maximum of pi. | +| test.c:40:5:40:7 | call to tan | Call to periodic trigonometric function tan with maximum argument absolute value of 31.4, which exceeds the recommended maximum of pi. | +| test.c:49:5:49:7 | call to sin | Call to periodic trigonometric function sin with maximum argument absolute value of 314, which exceeds the recommended maximum of pi. | +| test.c:50:5:50:7 | call to cos | Call to periodic trigonometric function cos with maximum argument absolute value of 314, which exceeds the recommended maximum of pi. | +| test.c:51:5:51:7 | call to tan | Call to periodic trigonometric function tan with maximum argument absolute value of 314, which exceeds the recommended maximum of pi. | +| test.c:52:5:52:7 | call to sin | Call to periodic trigonometric function sin with maximum argument absolute value of 314, which exceeds the recommended maximum of 10 * pi. | +| test.c:53:5:53:7 | call to cos | Call to periodic trigonometric function cos with maximum argument absolute value of 314, which exceeds the recommended maximum of 10 * pi. | +| test.c:54:5:54:7 | call to tan | Call to periodic trigonometric function tan with maximum argument absolute value of 314, which exceeds the recommended maximum of 10 * pi. | +| test.c:55:5:55:7 | call to sin | Call to periodic trigonometric function sin with maximum argument absolute value of 314, which exceeds the recommended maximum of pi. | +| test.c:56:5:56:7 | call to cos | Call to periodic trigonometric function cos with maximum argument absolute value of 314, which exceeds the recommended maximum of pi. | +| test.c:57:5:57:7 | call to tan | Call to periodic trigonometric function tan with maximum argument absolute value of 314, which exceeds the recommended maximum of pi. | +| test.c:58:5:58:7 | call to sin | Call to periodic trigonometric function sin with maximum argument absolute value of 314, which exceeds the recommended maximum of 10 * pi. | +| test.c:59:5:59:7 | call to cos | Call to periodic trigonometric function cos with maximum argument absolute value of 314, which exceeds the recommended maximum of 10 * pi. | +| test.c:60:5:60:7 | call to tan | Call to periodic trigonometric function tan with maximum argument absolute value of 314, which exceeds the recommended maximum of 10 * pi. | diff --git a/c/misra/test/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.qlref b/c/misra/test/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.qlref new file mode 100644 index 0000000000..f7bd11b44d --- /dev/null +++ b/c/misra/test/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.qlref @@ -0,0 +1 @@ +rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-11/test.c b/c/misra/test/rules/DIR-4-11/test.c new file mode 100644 index 0000000000..dac34860ff --- /dev/null +++ b/c/misra/test/rules/DIR-4-11/test.c @@ -0,0 +1,62 @@ +#include +void f(int x) { + float f1 = 0.0f; + double d1 = 0.0f; + sin(f1); // COMPLIANT + cos(f1); // COMPLIANT + tan(f1); // COMPLIANT + sin(d1); // COMPLIANT + cos(d1); // COMPLIANT + tan(d1); // COMPLIANT + + if (x < 10) { + f1 += 3.14; + d1 += 3.14; + sin(f1); // COMPLIANT + cos(f1); // COMPLIANT + tan(f1); // COMPLIANT + sin(d1); // COMPLIANT + cos(d1); // COMPLIANT + tan(d1); // COMPLIANT + sin(-f1); // COMPLIANT + cos(-f1); // COMPLIANT + tan(-f1); // COMPLIANT + sin(-d1); // COMPLIANT + cos(-d1); // COMPLIANT + tan(-d1); // COMPLIANT + } + + if (x < 20) { + f1 = 3.14 * 10; + d1 = 3.14 * 10; + sin(f1); // NON-COMPLIANT + cos(f1); // NON-COMPLIANT + tan(f1); // NON-COMPLIANT + sin(d1); // COMPLIANT + cos(d1); // COMPLIANT + tan(d1); // COMPLIANT + sin(-f1); // NON-COMPLIANT + cos(-f1); // NON-COMPLIANT + tan(-f1); // NON-COMPLIANT + sin(-d1); // COMPLIANT + cos(-d1); // COMPLIANT + tan(-d1); // COMPLIANT + } + + if (x < 30) { + f1 = 3.14 * 100; + d1 = 3.14 * 100; + sin(f1); // NON-COMPLIANT + cos(f1); // NON-COMPLIANT + tan(f1); // NON-COMPLIANT + sin(d1); // NON-COMPLIANT + cos(d1); // NON-COMPLIANT + tan(d1); // NON-COMPLIANT + sin(-f1); // NON-COMPLIANT + cos(-f1); // NON-COMPLIANT + tan(-f1); // NON-COMPLIANT + sin(-d1); // NON-COMPLIANT + cos(-d1); // NON-COMPLIANT + tan(-d1); // NON-COMPLIANT + } +} \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.testref b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.testref new file mode 100644 index 0000000000..176855a83d --- /dev/null +++ b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.testref @@ -0,0 +1 @@ +c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.testref b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.testref new file mode 100644 index 0000000000..7cd2a4d431 --- /dev/null +++ b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.testref @@ -0,0 +1 @@ +c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-2/UsageOfAssemblyLanguageShouldBeDocumented.testref b/c/misra/test/rules/DIR-4-2/UsageOfAssemblyLanguageShouldBeDocumented.testref index ea9ce384ea..3b0dc2fe5a 100644 --- a/c/misra/test/rules/DIR-4-2/UsageOfAssemblyLanguageShouldBeDocumented.testref +++ b/c/misra/test/rules/DIR-4-2/UsageOfAssemblyLanguageShouldBeDocumented.testref @@ -1 +1 @@ -cpp/common/test/rules/usageofassemblernotdocumented/UsageOfAssemblerNotDocumented.ql \ No newline at end of file +c/common/test/rules/usageofassemblernotdocumented/UsageOfAssemblerNotDocumented.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-4/SectionsOfCodeShallNotBeCommentedOut.testref b/c/misra/test/rules/DIR-4-4/SectionsOfCodeShallNotBeCommentedOut.testref index 303a38a19b..4460b5ed53 100644 --- a/c/misra/test/rules/DIR-4-4/SectionsOfCodeShallNotBeCommentedOut.testref +++ b/c/misra/test/rules/DIR-4-4/SectionsOfCodeShallNotBeCommentedOut.testref @@ -1 +1 @@ -cpp/common/test/rules/sectionsofcodeshallnotbecommentedout/SectionsOfCodeShallNotBeCommentedOut.ql \ No newline at end of file +c/common/test/rules/sectionsofcodeshallnotbecommentedout/SectionsOfCodeShallNotBeCommentedOut.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-5/IdentifiersInTheSameNameSpaceUnambiguous.testref b/c/misra/test/rules/DIR-4-5/IdentifiersInTheSameNameSpaceUnambiguous.testref index dffdbb26b8..2dc788dd11 100644 --- a/c/misra/test/rules/DIR-4-5/IdentifiersInTheSameNameSpaceUnambiguous.testref +++ b/c/misra/test/rules/DIR-4-5/IdentifiersInTheSameNameSpaceUnambiguous.testref @@ -1 +1 @@ -cpp/common/test/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.ql \ No newline at end of file +c/common/test/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-6/PlainNumericalTypeUsedOverExplicitTypedef.expected b/c/misra/test/rules/DIR-4-6/PlainNumericalTypeUsedOverExplicitTypedef.expected index c7f1cba77a..49e0b1c34c 100644 --- a/c/misra/test/rules/DIR-4-6/PlainNumericalTypeUsedOverExplicitTypedef.expected +++ b/c/misra/test/rules/DIR-4-6/PlainNumericalTypeUsedOverExplicitTypedef.expected @@ -1,20 +1,24 @@ | test.c:14:5:14:10 | int4_t | The typedef type int4_t does not have its indicated size. | | test.c:16:5:16:11 | uint4_t | The typedef type uint4_t does not have its indicated size. | -| test.c:27:5:27:26 | _astronomical_number_t | The type _astronomical_number_t is not an alias to a fixed-width numeric type. | -| test.c:34:15:34:16 | c2 | The type signed char is not a fixed-width numeric type. | -| test.c:35:17:35:18 | c3 | The type unsigned char is not a fixed-width numeric type. | -| test.c:38:9:38:10 | s1 | The type short is not a fixed-width numeric type. | -| test.c:39:16:39:17 | s2 | The type signed short is not a fixed-width numeric type. | -| test.c:40:18:40:19 | s3 | The type unsigned short is not a fixed-width numeric type. | -| test.c:43:7:43:8 | i1 | The type int is not a fixed-width numeric type. | -| test.c:44:14:44:15 | i2 | The type signed int is not a fixed-width numeric type. | -| test.c:45:16:45:17 | i3 | The type unsigned int is not a fixed-width numeric type. | -| test.c:48:8:48:9 | l1 | The type long is not a fixed-width numeric type. | -| test.c:49:15:49:16 | l2 | The type signed long is not a fixed-width numeric type. | -| test.c:50:17:50:18 | l3 | The type unsigned long is not a fixed-width numeric type. | -| test.c:53:13:53:15 | ll1 | The type long long is not a fixed-width numeric type. | -| test.c:54:20:54:22 | ll2 | The type signed long long is not a fixed-width numeric type. | -| test.c:55:22:55:24 | ll3 | The type unsigned long long is not a fixed-width numeric type. | -| test.c:58:9:58:10 | f1 | The type float is not a fixed-width numeric type. | -| test.c:61:10:61:11 | d1 | The type double is not a fixed-width numeric type. | -| test.c:64:15:64:17 | ld1 | The type long double is not a fixed-width numeric type. | +| test.c:19:25:19:33 | float64_t | The typedef name float64_t does not indicate a complex type. | +| test.c:22:15:22:24 | cfloat32_t | The typedef type cfloat32_t is not a complex type. | +| test.c:24:25:24:35 | cfloat128_t | The typedef type cfloat128_t does not have its indicated real size. | +| test.c:31:5:31:26 | _astronomical_number_t | The type _astronomical_number_t is not an alias to a fixed-width numeric type. | +| test.c:38:15:38:16 | c2 | The type signed char is not a fixed-width numeric type. | +| test.c:39:17:39:18 | c3 | The type unsigned char is not a fixed-width numeric type. | +| test.c:42:9:42:10 | s1 | The type short is not a fixed-width numeric type. | +| test.c:43:16:43:17 | s2 | The type signed short is not a fixed-width numeric type. | +| test.c:44:18:44:19 | s3 | The type unsigned short is not a fixed-width numeric type. | +| test.c:47:7:47:8 | i1 | The type int is not a fixed-width numeric type. | +| test.c:48:14:48:15 | i2 | The type signed int is not a fixed-width numeric type. | +| test.c:49:16:49:17 | i3 | The type unsigned int is not a fixed-width numeric type. | +| test.c:52:8:52:9 | l1 | The type long is not a fixed-width numeric type. | +| test.c:53:15:53:16 | l2 | The type signed long is not a fixed-width numeric type. | +| test.c:54:17:54:18 | l3 | The type unsigned long is not a fixed-width numeric type. | +| test.c:57:13:57:15 | ll1 | The type long long is not a fixed-width numeric type. | +| test.c:58:20:58:22 | ll2 | The type signed long long is not a fixed-width numeric type. | +| test.c:59:22:59:24 | ll3 | The type unsigned long long is not a fixed-width numeric type. | +| test.c:62:9:62:10 | f1 | The type float is not a fixed-width numeric type. | +| test.c:65:10:65:11 | d1 | The type double is not a fixed-width numeric type. | +| test.c:68:15:68:17 | ld1 | The type long double is not a fixed-width numeric type. | +| test.c:71:18:71:20 | cf1 | The type _Complex float is not a fixed-width numeric type. | diff --git a/c/misra/test/rules/DIR-4-6/test.c b/c/misra/test/rules/DIR-4-6/test.c index db0842c4f6..0fc79faa2e 100644 --- a/c/misra/test/rules/DIR-4-6/test.c +++ b/c/misra/test/rules/DIR-4-6/test.c @@ -15,10 +15,14 @@ typedef signed long long typedef unsigned long long uint4_t; // NON_COMPLIANT: typedef does not have its indicated size -typedef float float32_t; // COMPLIANT: exception, typedefs are permitted -typedef double float64_t; // COMPLIANT: exception, typedefs are permitted +typedef float float32_t; // COMPLIANT: exception, typedefs are permitted +typedef double _Complex float64_t; // NON-COMPLIANT: not complex floating type typedef long double float128_t; // COMPLIANT: exception, typedefs are permitted +typedef float cfloat32_t; // NON-COMPLIANT: not a complex floating type +typedef double _Complex cfloat64_t; // COMPLIANT: correct complex floating type +typedef double _Complex cfloat128_t; // NON-COMPLIANT: incorrect complex size + typedef int8_t astronomical_number_t; // COMPLIANT: aliasing a fixed-width numeric typedef typedef uint8_t u_astronomical_number_t; // COMPLIANT: aliasing a fixed-width @@ -63,4 +67,7 @@ main(int argc, // COMPLIANT: exception, argc's type can be plain int long double ld1 = 1; // NON_COMPLIANT: int is a basic numeric type float128_t ld2 = 1; // COMPLIANT: typedef used instead + + float _Complex cf1 = 1; // NON_COMPLIANT: complex basic numeric type + cfloat64_t cf2 = 1; // COMPLIANT: typedef used instead } \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-7/FunctionErrorInformationUntested.testref b/c/misra/test/rules/DIR-4-7/FunctionErrorInformationUntested.testref new file mode 100644 index 0000000000..51bd5fbefb --- /dev/null +++ b/c/misra/test/rules/DIR-4-7/FunctionErrorInformationUntested.testref @@ -0,0 +1 @@ +c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-9/FunctionOverFunctionLikeMacro.testref b/c/misra/test/rules/DIR-4-9/FunctionOverFunctionLikeMacro.testref new file mode 100644 index 0000000000..fb033c44e4 --- /dev/null +++ b/c/misra/test/rules/DIR-4-9/FunctionOverFunctionLikeMacro.testref @@ -0,0 +1 @@ +c/common/test/rules/functionlikemacrosdefined/FunctionLikeMacrosDefined.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-9/test.c b/c/misra/test/rules/DIR-4-9/test.c index 50e6bdb042..304c4bd004 100644 --- a/c/misra/test/rules/DIR-4-9/test.c +++ b/c/misra/test/rules/DIR-4-9/test.c @@ -10,6 +10,7 @@ #define MACRO8(x) "NOP" // COMPLIANT #define MACRO9() printf_custom("output = %d", 7) // NON_COMPLIANT #define MACRO10(x) // COMPLIANT +#define MACRO11(x) _Generic((x), int : 1, default : 0) // COMPLIANT #define MY_ASSERT(X) assert(X) // NON_COMPLIANT[FALSE_NEGATIVE] const char a1[MACRO2(1, 1) + 6]; diff --git a/c/misra/test/rules/DIR-5-1/PossibleDataRaceBetweenThreads.expected b/c/misra/test/rules/DIR-5-1/PossibleDataRaceBetweenThreads.expected new file mode 100644 index 0000000000..e1c0e9389d --- /dev/null +++ b/c/misra/test/rules/DIR-5-1/PossibleDataRaceBetweenThreads.expected @@ -0,0 +1,24 @@ +| test.c:31:3:31:8 | ... = ... | Threaded write to object $@ from thread function $@ is not synchronized with $@ from thread function $@. | test.c:11:5:11:6 | g2 | g2 | test.c:30:6:30:29 | single_thread4_writes_g2 | single_thread4_writes_g2 | test.c:27:3:27:4 | g2 | concurrent read operation | test.c:26:6:26:28 | single_thread3_reads_g2 | single_thread3_reads_g2 | +| test.c:35:3:35:8 | ... = ... | Threaded write to object $@ not synchronized from thread function $@ spawned from a loop. | test.c:12:5:12:6 | g3 | g3 | test.c:34:6:34:27 | many_thread5_writes_g3 | many_thread5_writes_g3 | test.c:35:3:35:4 | g3 | concurrent read operation | test.c:34:6:34:27 | many_thread5_writes_g3 | many_thread5_writes_g3 | +| test.c:71:3:71:11 | ... = ... | Threaded write to object $@ from thread function $@ is not synchronized with $@ from thread function $@. | test.c:68:3:68:4 | g7 | g7.m1 | test.c:70:6:70:33 | single_thread11_writes_g7_m1 | single_thread11_writes_g7_m1 | test.c:75:6:75:7 | m1 | concurrent read operation | test.c:74:6:74:33 | single_thread12_writes_g7_m1 | single_thread12_writes_g7_m1 | +| test.c:75:3:75:11 | ... = ... | Threaded write to object $@ from thread function $@ is not synchronized with $@ from thread function $@. | test.c:68:3:68:4 | g7 | g7.m1 | test.c:74:6:74:33 | single_thread12_writes_g7_m1 | single_thread12_writes_g7_m1 | test.c:71:6:71:7 | m1 | concurrent read operation | test.c:70:6:70:33 | single_thread11_writes_g7_m1 | single_thread11_writes_g7_m1 | +| test.c:79:3:79:11 | call to setlocale | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:79:3:79:11 | call to setlocale | setlocale | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:79:3:79:11 | call to setlocale | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:80:3:80:8 | call to tmpnam | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:80:3:80:8 | call to tmpnam | tmpnam | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:80:3:80:8 | call to tmpnam | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:81:3:81:6 | call to rand | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:81:3:81:6 | call to rand | rand | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:81:3:81:6 | call to rand | concurrent call to non-reentrant function | 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 | 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: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 | +| test.c:89:3:89:8 | call to gmtime | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:89:3:89:8 | call to gmtime | gmtime | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:89:3:89:8 | call to gmtime | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:90:3:90:11 | call to localtime | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:90:3:90:11 | call to localtime | localtime | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:90:3:90:11 | call to localtime | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:91:3:91:10 | call to mbrtoc16 | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:91:3:91:10 | call to mbrtoc16 | mbrtoc16 | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:91:3:91:10 | call to mbrtoc16 | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:92:3:92:10 | call to mbrtoc32 | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:92:3:92:10 | call to mbrtoc32 | mbrtoc32 | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:92:3:92:10 | call to mbrtoc32 | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:93:3:93:10 | call to c16rtomb | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:93:3:93:10 | call to c16rtomb | c16rtomb | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:93:3:93:10 | call to c16rtomb | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:94:3:94:10 | call to c32rtomb | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:94:3:94:10 | call to c32rtomb | c32rtomb | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:94:3:94:10 | call to c32rtomb | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:95:3:95:8 | call to mbrlen | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:95:3:95:8 | call to mbrlen | mbrlen | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:95:3:95:8 | call to mbrlen | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:96:3:96:9 | call to mbrtowc | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:96:3:96:9 | call to mbrtowc | mbrtowc | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:96:3:96:9 | call to mbrtowc | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:97:3:97:9 | call to wcrtomb | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:97:3:97:9 | call to wcrtomb | wcrtomb | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:97:3:97:9 | call to wcrtomb | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:98:3:98:11 | call to mbsrtowcs | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:98:3:98:11 | call to mbsrtowcs | mbsrtowcs | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:98:3:98:11 | call to mbsrtowcs | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:99:3:99:11 | call to wcsrtombs | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:99:3:99:11 | call to wcsrtombs | wcsrtombs | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:99:3:99:11 | call to wcsrtombs | 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/test/rules/DIR-5-1/PossibleDataRaceBetweenThreads.qlref b/c/misra/test/rules/DIR-5-1/PossibleDataRaceBetweenThreads.qlref new file mode 100644 index 0000000000..737cf79505 --- /dev/null +++ b/c/misra/test/rules/DIR-5-1/PossibleDataRaceBetweenThreads.qlref @@ -0,0 +1 @@ +rules/DIR-5-1/PossibleDataRaceBetweenThreads.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-5-1/test.c b/c/misra/test/rules/DIR-5-1/test.c new file mode 100644 index 0000000000..5f392105e6 --- /dev/null +++ b/c/misra/test/rules/DIR-5-1/test.c @@ -0,0 +1,132 @@ +#include "locale.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "threads.h" +#include "time.h" +#include "uchar.h" +#include "wchar.h" + +int g1; +int g2; +int g3; +int g4; +mtx_t g4_lock; +int g5; +mtx_t g5_lock; + +void single_thread1_reads_g1(void *p) { + g1; // COMPLIANT +} + +void many_thread2_reads_g1(void *p) { + g1; // COMPLIANT +} + +void single_thread3_reads_g2(void *p) { + g2; // COMPLIANT +} + +void single_thread4_writes_g2(void *p) { + g2 = 1; // NON-COMPLIANT +} + +void many_thread5_writes_g3(void *p) { + g3 = 1; // NON-COMPLIANT +} + +void single_thread6_reads_g4_locked(void *p) { + mtx_lock(&g4_lock); + g4; // COMPLIANT +} + +void single_thread7_writes_g4_locked(void *p) { + mtx_lock(&g4_lock); + g4 = 1; // COMPLIANT +} + +void many_thread8_writes_g5_locked(void *p) { + mtx_lock(&g5_lock); + g5 = 1; // COMPLIANT +} + +struct { + int m1; + int m2; +} g6; + +void single_thread9_writes_g6_m1(void *p) { + g6.m1 = 1; // COMPLIANT +} + +void single_thread10_writes_g6_m2(void *p) { + g6.m2 = 1; // COMPLIANT +} + +struct { + int m1; +} g7; + +void single_thread11_writes_g7_m1(void *p) { + g7.m1 = 1; // NON-COMPLIANT +} + +void single_thread12_writes_g7_m1(void *p) { + g7.m1 = 1; // NON-COMPLIANT +} + +void many_thread13_calls_nonreentrant_funcs(void *p) { + setlocale(LC_ALL, "C"); // NON-COMPLIANT + tmpnam(""); // NON-COMPLIANT + rand(); // NON-COMPLIANT + srand(0); // NON-COMPLIANT + getenv("PATH"); // NON-COMPLIANT + getenv_s(NULL, NULL, 0, NULL); // NON-COMPLIANT + strtok("a", "b"); // NON-COMPLIANT + strerror(0); // NON-COMPLIANT + asctime(NULL); // NON-COMPLIANT + ctime(NULL); // NON-COMPLIANT + gmtime(NULL); // NON-COMPLIANT + localtime(NULL); // NON-COMPLIANT + mbrtoc16(NULL, NULL, 0, NULL); // NON-COMPLIANT + mbrtoc32(NULL, NULL, 0, NULL); // NON-COMPLIANT + c16rtomb(NULL, 0, NULL); // NON-COMPLIANT + c32rtomb(NULL, 0, NULL); // NON-COMPLIANT + mbrlen(NULL, 0, NULL); // NON-COMPLIANT + mbrtowc(NULL, NULL, 0, NULL); // NON-COMPLIANT + wcrtomb(NULL, 0, NULL); // NON-COMPLIANT + mbsrtowcs(NULL, NULL, 0, NULL); // NON-COMPLIANT + wcsrtombs(NULL, NULL, 0, NULL); // NON-COMPLIANT +} + +int main(int argc, char *argv[]) { + thrd_t single_thread1; + thrd_t many_thread2; + thrd_t single_thread3; + thrd_t single_thread4; + thrd_t many_thread5; + thrd_t single_thread6; + thrd_t single_thread7; + thrd_t many_thread8; + thrd_t single_thread9; + thrd_t single_thread10; + thrd_t single_thread11; + thrd_t single_thread12; + thrd_t many_thread13; + + thrd_create(&single_thread1, single_thread1_reads_g1, NULL); + thrd_create(&single_thread3, single_thread3_reads_g2, NULL); + thrd_create(&single_thread4, single_thread4_writes_g2, NULL); + thrd_create(&single_thread6, single_thread6_reads_g4_locked, NULL); + thrd_create(&single_thread7, single_thread7_writes_g4_locked, NULL); + thrd_create(&single_thread9, single_thread9_writes_g6_m1, NULL); + thrd_create(&single_thread10, single_thread10_writes_g6_m2, NULL); + thrd_create(&single_thread11, single_thread11_writes_g7_m1, NULL); + thrd_create(&single_thread12, single_thread12_writes_g7_m1, NULL); + for (;;) { + thrd_create(&many_thread2, many_thread2_reads_g1, NULL); + thrd_create(&many_thread5, many_thread5_writes_g3, NULL); + thrd_create(&many_thread8, many_thread8_writes_g5_locked, NULL); + thrd_create(&many_thread13, many_thread13_calls_nonreentrant_funcs, NULL); + } +} \ No newline at end of file diff --git a/c/misra/test/rules/DIR-5-2/NotNoDeadlocksBetweenThreads.testref b/c/misra/test/rules/DIR-5-2/NotNoDeadlocksBetweenThreads.testref new file mode 100644 index 0000000000..4625d1a24d --- /dev/null +++ b/c/misra/test/rules/DIR-5-2/NotNoDeadlocksBetweenThreads.testref @@ -0,0 +1 @@ +c/common/test/rules/preventdeadlockbylockinginpredefinedorder/PreventDeadlockByLockingInPredefinedOrder.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.expected b/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.expected new file mode 100644 index 0000000000..3bc3ab579a --- /dev/null +++ b/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.expected @@ -0,0 +1,16 @@ +| test.c:30:3:30:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:29:6:29:34 | make_threads_called_from_main | make_threads_called_from_main | +| test.c:31:3:31:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:29:6:29:34 | make_threads_called_from_main | make_threads_called_from_main | +| test.c:39:3:39:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:38:6:38:51 | make_threads_called_from_func_called_from_main | make_threads_called_from_func_called_from_main | +| test.c:40:3:40:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:38:6:38:51 | make_threads_called_from_func_called_from_main | make_threads_called_from_func_called_from_main | +| test.c:49:3:49:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:48:7:48:18 | pthread_func | pthread_func | +| test.c:50:3:50:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:48:7:48:18 | pthread_func | pthread_func | +| test.c:58:3:58:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:57:5:57:13 | thrd_func | thrd_func | +| test.c:59:3:59:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:57:5:57:13 | thrd_func | thrd_func | +| test.c:67:3:67:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:66:6:66:39 | make_threads_called_from_thrd_func | make_threads_called_from_thrd_func | +| test.c:68:3:68:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:66:6:66:39 | make_threads_called_from_thrd_func | make_threads_called_from_thrd_func | +| test.c:76:3:76:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:75:6:75:59 | make_threads_called_from_func_called_from_pthread_thrd | make_threads_called_from_func_called_from_pthread_thrd | +| test.c:77:3:77:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:75:6:75:59 | make_threads_called_from_func_called_from_pthread_thrd | make_threads_called_from_func_called_from_pthread_thrd | +| test.c:81:3:81:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:80:6:80:47 | make_threads_called_from_main_pthread_thrd | make_threads_called_from_main_pthread_thrd | +| test.c:82:3:82:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:80:6:80:47 | make_threads_called_from_main_pthread_thrd | make_threads_called_from_main_pthread_thrd | +| test.c:86:3:86:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:85:6:85:38 | make_threads_not_called_by_anyone | make_threads_not_called_by_anyone | +| test.c:87:3:87:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:85:6:85:38 | make_threads_not_called_by_anyone | make_threads_not_called_by_anyone | diff --git a/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.qlref b/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.qlref new file mode 100644 index 0000000000..16c9614cec --- /dev/null +++ b/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.qlref @@ -0,0 +1 @@ +rules/DIR-5-3/BannedDynamicThreadCreation.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.expected b/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.expected new file mode 100644 index 0000000000..b8dc2bfe4b --- /dev/null +++ b/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.expected @@ -0,0 +1,14 @@ +| test.c:49:3:49:13 | call to thrd_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:48:7:48:18 | pthread_func | pthread_func | test.c:19:3:19:16 | call to pthread_create | started as a thread | +| test.c:50:3:50:16 | call to pthread_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:48:7:48:18 | pthread_func | pthread_func | test.c:19:3:19:16 | call to pthread_create | started as a thread | +| test.c:58:3:58:13 | call to thrd_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:57:5:57:13 | thrd_func | thrd_func | test.c:18:3:18:13 | call to thrd_create | started as a thread | +| test.c:59:3:59:16 | call to pthread_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:57:5:57:13 | thrd_func | thrd_func | test.c:18:3:18:13 | call to thrd_create | started as a thread | +| test.c:67:3:67:13 | call to thrd_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:57:5:57:13 | thrd_func | thrd_func | test.c:18:3:18:13 | call to thrd_create | started as a thread | +| test.c:68:3:68:16 | call to pthread_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:57:5:57:13 | thrd_func | thrd_func | test.c:18:3:18:13 | call to thrd_create | started as a thread | +| test.c:76:3:76:13 | call to thrd_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:48:7:48:18 | pthread_func | pthread_func | test.c:19:3:19:16 | call to pthread_create | started as a thread | +| test.c:76:3:76:13 | call to thrd_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:57:5:57:13 | thrd_func | thrd_func | test.c:18:3:18:13 | call to thrd_create | started as a thread | +| test.c:77:3:77:16 | call to pthread_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:48:7:48:18 | pthread_func | pthread_func | test.c:19:3:19:16 | call to pthread_create | started as a thread | +| test.c:77:3:77:16 | call to pthread_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:57:5:57:13 | thrd_func | thrd_func | test.c:18:3:18:13 | call to thrd_create | started as a thread | +| test.c:81:3:81:13 | call to thrd_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:48:7:48:18 | pthread_func | pthread_func | test.c:19:3:19:16 | call to pthread_create | started as a thread | +| test.c:81:3:81:13 | call to thrd_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:57:5:57:13 | thrd_func | thrd_func | test.c:18:3:18:13 | call to thrd_create | started as a thread | +| test.c:82:3:82:16 | call to pthread_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:48:7:48:18 | pthread_func | pthread_func | test.c:19:3:19:16 | call to pthread_create | started as a thread | +| test.c:82:3:82:16 | call to pthread_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:57:5:57:13 | thrd_func | thrd_func | test.c:18:3:18:13 | call to thrd_create | started as a thread | diff --git a/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.qlref b/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.qlref new file mode 100644 index 0000000000..99cecb8311 --- /dev/null +++ b/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.qlref @@ -0,0 +1 @@ +rules/DIR-5-3/ThreadCreatedByThread.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-5-3/test.c b/c/misra/test/rules/DIR-5-3/test.c new file mode 100644 index 0000000000..16eb580276 --- /dev/null +++ b/c/misra/test/rules/DIR-5-3/test.c @@ -0,0 +1,88 @@ +#include "pthread.h" +#include "threads.h" + +thrd_t g1; // COMPLIANT +pthread_t g2; // COMPLIANT + +void *pthread_func(void *arg); +void *pthread_func_inner(void *arg); +int thrd_func(void *arg); +int thrd_func_inner(void *arg); + +void make_threads_called_from_main(void); +void func_called_from_main(void); +void make_threads_called_from_func_called_from_main(void); +void make_threads_called_from_main_pthread_thrd(void); + +int main(int argc, char *argv[]) { + thrd_create(&g1, &thrd_func, NULL); // COMPLIANT + pthread_create(&g2, NULL, &pthread_func, NULL); // COMPLIANT + + thrd_create(&g1, &thrd_func_inner, NULL); // COMPLIANT + pthread_create(&g2, NULL, &pthread_func_inner, NULL); // COMPLIANT + + make_threads_called_from_main(); + func_called_from_main(); + make_threads_called_from_main_pthread_thrd(); +} + +void make_threads_called_from_main() { + thrd_create(&g1, &thrd_func_inner, NULL); // COMPLIANT + pthread_create(&g2, NULL, &pthread_func_inner, NULL); // COMPLIANT +} + +void func_called_from_main() { + make_threads_called_from_func_called_from_main(); +} + +void make_threads_called_from_func_called_from_main() { + thrd_create(&g1, &thrd_func_inner, NULL); // COMPLIANT + pthread_create(&g2, NULL, &pthread_func_inner, NULL); // COMPLIANT +} + +void make_threads_called_from_pthread_func(void); +void make_threads_called_from_thrd_func(void); +void func_called_from_pthread_thrd(void); +void make_threads_called_from_func_called_from_pthread_thrd(void); + +void *pthread_func(void *arg) { + thrd_create(&g1, &thrd_func_inner, NULL); // NON-COMPLIANT + pthread_create(&g2, NULL, &pthread_func_inner, NULL); // NON-COMPLIANT + + make_threads_called_from_pthread_func(); + func_called_from_pthread_thrd(); + make_threads_called_from_main_pthread_thrd(); +} + +int thrd_func(void *arg) { + thrd_create(&g1, &thrd_func_inner, NULL); // NON-COMPLIANT + pthread_create(&g2, NULL, &pthread_func_inner, NULL); // NON-COMPLIANT + + make_threads_called_from_thrd_func(); + func_called_from_pthread_thrd(); + make_threads_called_from_main_pthread_thrd(); +} + +void make_threads_called_from_thrd_func(void) { + thrd_create(&g1, &thrd_func_inner, NULL); // NON-COMPLIANT + pthread_create(&g2, NULL, &pthread_func_inner, NULL); // NON-COMPLIANT +} + +void func_called_from_pthread_thrd(void) { + make_threads_called_from_func_called_from_pthread_thrd(); +} + +void make_threads_called_from_func_called_from_pthread_thrd(void) { + thrd_create(&g1, &thrd_func_inner, NULL); // NON-COMPLIANT + pthread_create(&g2, NULL, &pthread_func_inner, NULL); // NON-COMPLIANT +} + +void make_threads_called_from_main_pthread_thrd() { + thrd_create(&g1, &thrd_func_inner, NULL); // NON-COMPLIANT + pthread_create(&g2, NULL, &pthread_func_inner, NULL); // NON-COMPLIANT +} + +void make_threads_not_called_by_anyone() { + thrd_create(&g1, &thrd_func_inner, NULL); // COMPLIANT + pthread_create(&g2, NULL, &pthread_func_inner, NULL); // COMPLIANT +} diff --git a/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected b/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected index f9f034c980..0e2cbb26ee 100644 --- a/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected +++ b/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected @@ -1,51 +1,51 @@ -| test.c:34:1:34:23 | #define A __BASE_FILE__ | Is a compiler extension and is not portable to other compilers. | -| test.c:35:1:35:23 | #define B __FILE_NAME__ | Is a compiler extension and is not portable to other compilers. | -| test.c:36:1:36:21 | #define C __COUNTER__ | Is a compiler extension and is not portable to other compilers. | -| test.c:37:1:37:27 | #define D __INCLUDE_LEVEL__ | Is a compiler extension and is not portable to other compilers. | -| test.c:39:1:39:19 | #define F __clang__ | Is a compiler extension and is not portable to other compilers. | -| test.c:40:1:40:25 | #define G __clang_major__ | Is a compiler extension and is not portable to other compilers. | -| test.c:41:1:41:25 | #define H __clang_minor__ | Is a compiler extension and is not portable to other compilers. | -| test.c:42:1:42:30 | #define I __clang_patchlevel__ | Is a compiler extension and is not portable to other compilers. | -| test.c:43:1:43:27 | #define J __clang_version__ | Is a compiler extension and is not portable to other compilers. | -| test.c:44:1:44:36 | #define K __clang_literal_encoding__ | Is a compiler extension and is not portable to other compilers. | -| test.c:45:1:45:41 | #define L __clang_wide_literal_encoding__ | Is a compiler extension and is not portable to other compilers. | -| test.c:53:33:53:43 | vector_size | Is a compiler extension and is not portable to other compilers. | -| test.c:54:33:54:47 | vector_size | Is a compiler extension and is not portable to other compilers. | -| test.c:55:37:55:51 | ext_vector_type | Is a compiler extension and is not portable to other compilers. | -| test.c:56:37:56:51 | ext_vector_type | Is a compiler extension and is not portable to other compilers. | -| test.c:61:3:69:4 | (statement expression) | Is a compiler extension and is not portable to other compilers. | -| test.c:96:3:96:18 | call to __builtin_setjmp | Is a compiler extension and is not portable to other compilers. | -| test.c:97:3:97:19 | call to __builtin_longjmp | Is a compiler extension and is not portable to other compilers. | -| test.c:113:11:113:16 | ... ? ... : ... | Is a compiler extension and is not portable to other compilers. | -| test.c:124:12:124:12 | definition of a | Is a compiler extension and is not portable to other compilers. | -| test.c:128:17:128:17 | definition of a | Is a compiler extension and is not portable to other compilers. | -| test.c:165:8:165:15 | definition of contents | Is a compiler extension and is not portable to other compilers. | -| test.c:182:8:182:11 | gf19 | Is a compiler extension and is not portable to other compilers. | -| test.c:214:33:214:35 | declaration of out | Is a compiler extension and is not portable to other compilers. | -| test.c:215:25:215:26 | declaration of in | Is a compiler extension and is not portable to other compilers. | -| test.c:268:16:268:21 | access | Is a compiler extension and is not portable to other compilers. | -| test.c:271:27:271:31 | alias | Is a compiler extension and is not portable to other compilers. | -| test.c:274:23:274:29 | aligned | Is a compiler extension and is not portable to other compilers. | -| test.c:285:25:285:34 | deprecated | Is a compiler extension and is not portable to other compilers. | -| test.c:297:20:297:30 | fallthrough | Is a compiler extension and is not portable to other compilers. | -| test.c:321:3:321:22 | alignof() | Is a compiler extension and is not portable to other compilers. | -| test.c:340:3:340:31 | call to __builtin_extract_return_addr | Is a compiler extension and is not portable to other compilers. | -| test.c:341:3:341:28 | call to __builtin_frob_return_addr | Is a compiler extension and is not portable to other compilers. | -| test.c:342:3:342:25 | call to __builtin_frame_address | Is a compiler extension and is not portable to other compilers. | -| test.c:363:3:363:22 | call to __sync_fetch_and_add_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:364:3:364:22 | call to __sync_fetch_and_sub_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:365:3:365:21 | call to __sync_fetch_and_or_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:366:3:366:22 | call to __sync_fetch_and_and_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:367:3:367:22 | call to __sync_fetch_and_xor_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:368:3:368:23 | call to __sync_fetch_and_nand_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:369:3:369:22 | call to __sync_add_and_fetch_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:370:3:370:22 | call to __sync_sub_and_fetch_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:371:3:371:21 | call to __sync_or_and_fetch_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:372:3:372:22 | call to __sync_and_and_fetch_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:373:3:373:22 | call to __sync_xor_and_fetch_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:374:3:374:23 | call to __sync_nand_and_fetch_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:376:3:376:30 | call to __sync_bool_compare_and_swap_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:377:3:377:29 | call to __sync_val_compare_and_swap_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:378:3:378:26 | call to __sync_lock_test_and_set_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:379:3:379:21 | call to __sync_lock_release_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:407:3:407:18 | call to __builtin_alloca | Is a compiler extension and is not portable to other compilers. | +| test.c:34:1:34:23 | #define A __BASE_FILE__ | Use of builtin macro '__BASE_FILE__' is a compiler extension and is not portable to other compilers. | +| test.c:35:1:35:23 | #define B __FILE_NAME__ | Use of builtin macro '__FILE_NAME__' is a compiler extension and is not portable to other compilers. | +| test.c:36:1:36:21 | #define C __COUNTER__ | Use of builtin macro '__COUNTER__' is a compiler extension and is not portable to other compilers. | +| test.c:37:1:37:27 | #define D __INCLUDE_LEVEL__ | Use of builtin macro '__INCLUDE_LEVEL__' is a compiler extension and is not portable to other compilers. | +| test.c:39:1:39:19 | #define F __clang__ | Use of builtin macro '__clang__' is a compiler extension and is not portable to other compilers. | +| test.c:40:1:40:25 | #define G __clang_major__ | Use of builtin macro '__clang_major__' is a compiler extension and is not portable to other compilers. | +| test.c:41:1:41:25 | #define H __clang_minor__ | Use of builtin macro '__clang_minor__' is a compiler extension and is not portable to other compilers. | +| test.c:42:1:42:30 | #define I __clang_patchlevel__ | Use of builtin macro '__clang_patchlevel__' is a compiler extension and is not portable to other compilers. | +| test.c:43:1:43:27 | #define J __clang_version__ | Use of builtin macro '__clang_version__' is a compiler extension and is not portable to other compilers. | +| test.c:44:1:44:36 | #define K __clang_literal_encoding__ | Use of builtin macro '__clang_literal_encoding__' is a compiler extension and is not portable to other compilers. | +| test.c:45:1:45:41 | #define L __clang_wide_literal_encoding__ | Use of builtin macro '__clang_wide_literal_encoding__' is a compiler extension and is not portable to other compilers. | +| test.c:53:33:53:43 | vector_size | Use of attribute 'vector_size' is a compiler extension and is not portable to other compilers. | +| test.c:54:33:54:47 | vector_size | Use of attribute 'vector_size' is a compiler extension and is not portable to other compilers. | +| test.c:55:37:55:51 | ext_vector_type | Use of attribute 'ext_vector_type' is a compiler extension and is not portable to other compilers. | +| test.c:56:37:56:51 | ext_vector_type | Use of attribute 'ext_vector_type' is a compiler extension and is not portable to other compilers. | +| test.c:61:3:69:4 | (statement expression) | Statement expressions are a compiler extension and are not portable to other compilers. | +| test.c:96:3:96:18 | call to __builtin_setjmp | Call to builtin function '__builtin_setjmp' is a compiler extension and is not portable to other compilers. | +| test.c:97:3:97:19 | call to __builtin_longjmp | Call to builtin function '__builtin_longjmp' is a compiler extension and is not portable to other compilers. | +| test.c:113:11:113:16 | ... ? ... : ... | Ternaries with omitted middle operands are a compiler extension and is not portable to other compilers. | +| test.c:124:12:124:12 | definition of a | 128-bit integers are a compiler extension and are not portable to other compilers. | +| test.c:128:17:128:17 | definition of a | Double-Word integers are a compiler extension and are not portable to other compilers. | +| test.c:165:8:165:15 | definition of contents | Zero length arrays are a compiler extension and are not portable to other compilers. | +| test.c:182:8:182:11 | gf19 | Empty structures are a compiler extension and are not portable to other compilers. | +| test.c:216:9:216:10 | definition of x1 | Zero length arrays are a compiler extension and are not portable to other compilers. | +| test.c:266:16:266:21 | access | Use of attribute 'access' is a compiler extension and is not portable to other compilers. | +| test.c:269:27:269:31 | alias | Use of attribute 'alias' is a compiler extension and is not portable to other compilers. | +| test.c:272:23:272:29 | aligned | Use of attribute 'aligned' is a compiler extension and is not portable to other compilers. | +| test.c:283:25:283:34 | deprecated | Use of attribute 'deprecated' is a compiler extension and is not portable to other compilers. | +| test.c:295:20:295:30 | fallthrough | Use of attribute 'fallthrough' is a compiler extension and is not portable to other compilers. | +| test.c:319:3:319:22 | alignof() | '__alignof__' is a compiler extension and is not portable to other compilers. | +| test.c:338:3:338:31 | call to __builtin_extract_return_addr | Call to builtin function '__builtin_extract_return_addr' is a compiler extension and is not portable to other compilers. | +| test.c:339:3:339:28 | call to __builtin_frob_return_addr | Call to builtin function '__builtin_frob_return_addr' is a compiler extension and is not portable to other compilers. | +| test.c:340:3:340:25 | call to __builtin_frame_address | Call to builtin function '__builtin_frame_address' is a compiler extension and is not portable to other compilers. | +| test.c:361:3:361:22 | call to __sync_fetch_and_add_4 | Call to builtin function '__sync_fetch_and_add_4' is a compiler extension and is not portable to other compilers. | +| test.c:362:3:362:22 | call to __sync_fetch_and_sub_4 | Call to builtin function '__sync_fetch_and_sub_4' is a compiler extension and is not portable to other compilers. | +| test.c:363:3:363:21 | call to __sync_fetch_and_or_4 | Call to builtin function '__sync_fetch_and_or_4' is a compiler extension and is not portable to other compilers. | +| test.c:364:3:364:22 | call to __sync_fetch_and_and_4 | Call to builtin function '__sync_fetch_and_and_4' is a compiler extension and is not portable to other compilers. | +| test.c:365:3:365:22 | call to __sync_fetch_and_xor_4 | Call to builtin function '__sync_fetch_and_xor_4' is a compiler extension and is not portable to other compilers. | +| test.c:366:3:366:23 | call to __sync_fetch_and_nand_4 | Call to builtin function '__sync_fetch_and_nand_4' is a compiler extension and is not portable to other compilers. | +| test.c:367:3:367:22 | call to __sync_add_and_fetch_4 | Call to builtin function '__sync_add_and_fetch_4' is a compiler extension and is not portable to other compilers. | +| test.c:368:3:368:22 | call to __sync_sub_and_fetch_4 | Call to builtin function '__sync_sub_and_fetch_4' is a compiler extension and is not portable to other compilers. | +| test.c:369:3:369:21 | call to __sync_or_and_fetch_4 | Call to builtin function '__sync_or_and_fetch_4' is a compiler extension and is not portable to other compilers. | +| test.c:370:3:370:22 | call to __sync_and_and_fetch_4 | Call to builtin function '__sync_and_and_fetch_4' is a compiler extension and is not portable to other compilers. | +| test.c:371:3:371:22 | call to __sync_xor_and_fetch_4 | Call to builtin function '__sync_xor_and_fetch_4' is a compiler extension and is not portable to other compilers. | +| test.c:372:3:372:23 | call to __sync_nand_and_fetch_4 | Call to builtin function '__sync_nand_and_fetch_4' is a compiler extension and is not portable to other compilers. | +| test.c:374:3:374:30 | call to __sync_bool_compare_and_swap_4 | Call to builtin function '__sync_bool_compare_and_swap_4' is a compiler extension and is not portable to other compilers. | +| test.c:375:3:375:29 | call to __sync_val_compare_and_swap_4 | Call to builtin function '__sync_val_compare_and_swap_4' is a compiler extension and is not portable to other compilers. | +| test.c:376:3:376:26 | call to __sync_lock_test_and_set_4 | Call to builtin function '__sync_lock_test_and_set_4' is a compiler extension and is not portable to other compilers. | +| test.c:377:3:377:21 | call to __sync_lock_release_4 | Call to builtin function '__sync_lock_release_4' is a compiler extension and is not portable to other compilers. | +| test.c:405:3:405:18 | call to __builtin_alloca | Call to builtin function '__builtin_alloca' is a compiler extension and is not portable to other compilers. | +| test.c:409:1:411:8 | #define BUILTIN __builtin_alloca( 0) | Call to builtin function '__builtin_alloca' is a compiler extension and is not portable to other compilers. | diff --git a/c/misra/test/rules/RULE-1-2/test.c b/c/misra/test/rules/RULE-1-2/test.c index 86a3ae2f20..439df3733c 100644 --- a/c/misra/test/rules/RULE-1-2/test.c +++ b/c/misra/test/rules/RULE-1-2/test.c @@ -211,14 +211,12 @@ void gf24(int f, int g) { // Reference: // https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html#Variable-Length -void gf25t(int N, int M, double out[M][N], // NON_COMPLIANT - const double in[N][M]); // NON_COMPLIANT -void gf25() { - double x[3][2]; - double y[2][3]; - gf25t(3, 2, y, - x); // in ISO C the const qualifier is formally attached - // to the element type of the array and not the array itself +void gf25(int n) { + struct S1 { + int x1[n]; // NON_COMPLIANT + int x2[5]; // COMPLIANT + int x3[]; // COMPLIANT + }; } // Reference: @@ -406,4 +404,10 @@ void gf47() { // NON_COMPLIANT in versions < C11. void gf48() { __builtin_alloca( 0); // NON_COMPLIANT (all __builtin functions are non-compliant.) -} \ No newline at end of file +} + +#define BUILTIN \ + __builtin_alloca( \ + 0) // NON_COMPLIANT (all __builtin functions are non-compliant.) + +void gf49() { BUILTIN; } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-3/OccurrenceOfUndefinedBehavior.expected b/c/misra/test/rules/RULE-1-3/OccurrenceOfUndefinedBehavior.expected index 68216d500f..1e57f92e4a 100644 --- a/c/misra/test/rules/RULE-1-3/OccurrenceOfUndefinedBehavior.expected +++ b/c/misra/test/rules/RULE-1-3/OccurrenceOfUndefinedBehavior.expected @@ -1,5 +1,8 @@ -| test.c:8:6:8:35 | ____codeql_coding_standards_m2 | May result in undefined behavior. | -| test.c:11:5:11:34 | ____codeql_coding_standards_m3 | May result in undefined behavior. | -| test.c:15:5:15:34 | ____codeql_coding_standards_m4 | May result in undefined behavior. | -| test.c:19:5:19:34 | ____codeql_coding_standards_m5 | May result in undefined behavior. | -| test.c:23:5:23:34 | ____codeql_coding_standards_m6 | May result in undefined behavior. | +| test.c:4:6:4:38 | ____codeql_coding_standards_main1 | main function may trigger undefined behavior because it is not in one of the formats specified by the C standard. | +| test.c:8:5:8:37 | ____codeql_coding_standards_main2 | main function may trigger undefined behavior because it is not in one of the formats specified by the C standard. | +| test.c:27:5:27:37 | ____codeql_coding_standards_main6 | main function may trigger undefined behavior because it is not in one of the formats specified by the C standard. | +| test.c:32:6:32:38 | ____codeql_coding_standards_main7 | main function may trigger undefined behavior because it is not in one of the formats specified by the C standard. | +| test.c:36:5:36:37 | ____codeql_coding_standards_main8 | main function may trigger undefined behavior because it is not in one of the formats specified by the C standard. | +| test.c:40:5:40:37 | ____codeql_coding_standards_main9 | main function may trigger undefined behavior because it is not in one of the formats specified by the C standard. | +| test.c:44:5:44:38 | ____codeql_coding_standards_main10 | main function may trigger undefined behavior because it is not in one of the formats specified by the C standard. | +| test.c:48:5:48:38 | ____codeql_coding_standards_main11 | main function may trigger undefined behavior because it is not in one of the formats specified by the C standard. | diff --git a/c/misra/test/rules/RULE-1-3/test.c b/c/misra/test/rules/RULE-1-3/test.c index 190cff4000..fd54959f56 100644 --- a/c/misra/test/rules/RULE-1-3/test.c +++ b/c/misra/test/rules/RULE-1-3/test.c @@ -1,25 +1,50 @@ -void main(void) { // COMPLIANT +int main(void) { // COMPLIANT } -int ____codeql_coding_standards_m1(int argc, char **argv) { // NON_COMPLIANT +void ____codeql_coding_standards_main1(void) { // NON_COMPLIANT return 0; } -void ____codeql_coding_standards_m2(char *argc, char **argv) { // NON_COMPLIANT +int ____codeql_coding_standards_main2() { // NON_COMPLIANT + return 0; +} + +int ____codeql_coding_standards_main3(int argc, char **argv) { // COMPLIANT + return 0; +} + +int ____codeql_coding_standards_main4(int argc, char argv[][]) { // COMPLIANT + return 0; +} + +int ____codeql_coding_standards_main5(int argc, char *argv[]) { // COMPLIANT + return 0; +} + +typedef int MY_INT; +typedef char *MY_CHAR_PTR; + +int ____codeql_coding_standards_main6(MY_INT argc, + MY_CHAR_PTR argv[]) { // COMPLIANT + return 0; +} + +void ____codeql_coding_standards_main7(char *argc, + char **argv) { // NON_COMPLIANT } -int ____codeql_coding_standards_m3(int argc, char *argv) { // NON_COMPLIANT +int ____codeql_coding_standards_main8(int argc, char *argv) { // NON_COMPLIANT return 0; } -int ____codeql_coding_standards_m4() { // NON_COMPLIANT +int ____codeql_coding_standards_main9() { // NON_COMPLIANT return 0; } -int ____codeql_coding_standards_m5(int argc, int *argv) { // NON_COMPLIANT +int ____codeql_coding_standards_main10(int argc, int *argv) { // NON_COMPLIANT return 0; } -int ____codeql_coding_standards_m6(int argc, int **argv) { // NON_COMPLIANT +int ____codeql_coding_standards_main11(int argc, int **argv) { // NON_COMPLIANT return 0; } diff --git a/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected b/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected index 2745223358..3f63a6c26c 100644 --- a/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected +++ b/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected @@ -1,15 +1 @@ -| test.c:1:1:1:21 | #include | Usage of emergent language feature. | -| test.c:2:1:2:22 | #include | Usage of emergent language feature. | -| test.c:3:1:3:24 | #include | Usage of emergent language feature. | -| test.c:4:1:4:20 | #include | Usage of emergent language feature. | -| test.c:6:1:6:49 | #define MACRO(x) _Generic((x), int : 0, long : 1) | Usage of emergent language feature. | | test.c:7:1:7:32 | #define __STDC_WANT_LIB_EXT1__ 1 | Usage of emergent language feature. | -| test.c:9:16:9:17 | f0 | Usage of emergent language feature. | -| test.c:12:26:12:40 | atomic_new_type | Usage of emergent language feature. | -| test.c:17:15:17:15 | i | Usage of emergent language feature. | -| test.c:19:3:19:10 | alignas(...) | Usage of emergent language feature. | -| test.c:20:3:20:9 | alignas(...) | Usage of emergent language feature. | -| test.c:21:11:21:23 | alignof(int) | Usage of emergent language feature. | -| test.c:22:12:22:23 | alignof(int) | Usage of emergent language feature. | -| test.c:24:27:24:28 | i3 | Usage of emergent language feature. | -| test.c:25:28:25:29 | i4 | Usage of emergent language feature. | diff --git a/c/misra/test/rules/RULE-1-4/test.c b/c/misra/test/rules/RULE-1-4/test.c index 153c722c94..5bea219b54 100644 --- a/c/misra/test/rules/RULE-1-4/test.c +++ b/c/misra/test/rules/RULE-1-4/test.c @@ -1,26 +1,26 @@ -#include //NON_COMPLIANT -#include //NON_COMPLIANT -#include //NON_COMPLIANT -#include //NON_COMPLIANT +#include //COMPLIANT +#include //COMPLIANT +#include //COMPLIANT +#include //COMPLIANT -#define MACRO(x) _Generic((x), int : 0, long : 1) // NON_COMPLIANT +#define MACRO(x) _Generic((x), int : 0, long : 1) // COMPLIANT #define __STDC_WANT_LIB_EXT1__ 1 // NON_COMPLIANT -_Noreturn void f0(); // NON_COMPLIANT +_Noreturn void f0(); // COMPLIANT typedef int new_type; // COMPLIANT -typedef _Atomic new_type atomic_new_type; // NON_COMPLIANT +typedef _Atomic new_type atomic_new_type; // COMPLIANT void f(int p) { - int i0 = _Generic(p, int : 0, long : 1); // NON_COMPLIANT[FALSE_NEGATIVE] + int i0 = _Generic(p, int : 0, long : 1); // COMPLIANT - _Atomic int i; // NON_COMPLIANT + _Atomic int i; // NON-COMPLIANT - _Alignas(4) int i1; // NON_COMPLIANT - alignas(4) int i2; // NON_COMPLIANT - int a = _Alignof(int); // NON_COMPLIANT - int a1 = alignof(int); // NON_COMPLIANT + _Alignas(4) int i1; // COMPLIANT + alignas(4) int i2; // COMPLIANT + int a = _Alignof(int); // COMPLIANT + int a1 = alignof(int); // COMPLIANT - static thread_local int i3; // NON_COMPLIANT - static _Thread_local int i4; // NON_COMPLIANT + static thread_local int i3; // COMPLIANT + static _Thread_local int i4; // COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/CallToObsolescentFunctionGets.expected b/c/misra/test/rules/RULE-1-5/CallToObsolescentFunctionGets.expected new file mode 100644 index 0000000000..4c8fdc27cf --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/CallToObsolescentFunctionGets.expected @@ -0,0 +1 @@ +| test.c:37:3:37:6 | call to gets | Call to obsolescent function 'gets'. | diff --git a/c/misra/test/rules/RULE-1-5/CallToObsolescentFunctionGets.qlref b/c/misra/test/rules/RULE-1-5/CallToObsolescentFunctionGets.qlref new file mode 100644 index 0000000000..1a2ec096cf --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/CallToObsolescentFunctionGets.qlref @@ -0,0 +1 @@ +rules/RULE-1-5/CallToObsolescentFunctionGets.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.testref b/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.testref new file mode 100644 index 0000000000..1a6a69fc24 --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.testref @@ -0,0 +1 @@ +c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected b/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected new file mode 100644 index 0000000000..854b200553 --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected @@ -0,0 +1,6 @@ +| test.c:22:1:22:14 | #define true 3 | Invalid define of boolean standard macro 'true'. | +| test.c:23:1:23:15 | #define false 3 | Invalid define of boolean standard macro 'false'. | +| test.c:24:1:24:18 | #define bool int * | Invalid define of boolean standard macro 'bool'. | +| test.c:25:1:25:11 | #undef true | Invalid undefine of boolean standard macro 'true'. | +| test.c:26:1:26:12 | #undef false | Invalid undefine of boolean standard macro 'false'. | +| test.c:27:1:27:11 | #undef bool | Invalid undefine of boolean standard macro 'bool'. | diff --git a/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.qlref b/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.qlref new file mode 100644 index 0000000000..5b112609cc --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.qlref @@ -0,0 +1 @@ +rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierFuncRedeclarationObsolete.testref b/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierFuncRedeclarationObsolete.testref new file mode 100644 index 0000000000..7d9f2ebc04 --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierFuncRedeclarationObsolete.testref @@ -0,0 +1 @@ +c/common/test/rules/missingstaticspecifierfunctionredeclarationshared/MissingStaticSpecifierFunctionRedeclarationShared.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationObsolete.testref b/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationObsolete.testref new file mode 100644 index 0000000000..23ed7c9fc5 --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationObsolete.testref @@ -0,0 +1 @@ +c/common/test/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/SizeInReallocCallIsZero.expected b/c/misra/test/rules/RULE-1-5/SizeInReallocCallIsZero.expected new file mode 100644 index 0000000000..7b05a5fc0a --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/SizeInReallocCallIsZero.expected @@ -0,0 +1 @@ +| test.c:14:3:14:9 | call to realloc | Size argument '$@' may equal zero in realloc call, resulting in obsolescent and/or implementation-defined behavior. | test.c:14:14:14:14 | 0 | 0 | diff --git a/c/misra/test/rules/RULE-1-5/SizeInReallocCallIsZero.qlref b/c/misra/test/rules/RULE-1-5/SizeInReallocCallIsZero.qlref new file mode 100644 index 0000000000..cef5e76d54 --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/SizeInReallocCallIsZero.qlref @@ -0,0 +1 @@ +rules/RULE-1-5/SizeInReallocCallIsZero.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/SizeInReallocCallMayBeZero.expected b/c/misra/test/rules/RULE-1-5/SizeInReallocCallMayBeZero.expected new file mode 100644 index 0000000000..f86ad4c57c --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/SizeInReallocCallMayBeZero.expected @@ -0,0 +1 @@ +| test.c:15:3:15:9 | call to realloc | Size argument '$@' equals zero in realloc call, resulting in obsolescent and/or implementation-defined behavior. | test.c:15:14:15:15 | p0 | p0 | diff --git a/c/misra/test/rules/RULE-1-5/SizeInReallocCallMayBeZero.qlref b/c/misra/test/rules/RULE-1-5/SizeInReallocCallMayBeZero.qlref new file mode 100644 index 0000000000..1287327c5d --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/SizeInReallocCallMayBeZero.qlref @@ -0,0 +1 @@ +rules/RULE-1-5/SizeInReallocCallMayBeZero.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected b/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected new file mode 100644 index 0000000000..fb8d44ea19 --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected @@ -0,0 +1,10 @@ +edges +| test.c:39:16:39:20 | *call to fopen | test.c:39:16:39:20 | *call to fopen | provenance | | +| test.c:39:16:39:20 | *call to fopen | test.c:41:15:41:18 | *file | provenance | | +nodes +| test.c:39:16:39:20 | *call to fopen | semmle.label | *call to fopen | +| test.c:39:16:39:20 | *call to fopen | semmle.label | *call to fopen | +| test.c:41:15:41:18 | *file | semmle.label | *file | +subpaths +#select +| test.c:41:15:41:18 | *file | test.c:39:16:39:20 | *call to fopen | test.c:41:15:41:18 | *file | Obsolescent call to ungetc on file stream $@ at position zero. | test.c:39:16:39:20 | *call to fopen | *call to fopen | diff --git a/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.qlref b/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.qlref new file mode 100644 index 0000000000..8c28919dcb --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.qlref @@ -0,0 +1 @@ +rules/RULE-1-5/UngetcCallOnStreamPositionZero.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected b/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected new file mode 100644 index 0000000000..edd607c52f --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected @@ -0,0 +1 @@ +| test.c:29:18:29:36 | ATOMIC_VAR_INIT(value) | Usage of macro ATOMIC_VAR_INIT() is declared obscelescent in C18, and discouraged in earlier C versions. | diff --git a/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected.gcc b/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected.gcc new file mode 100644 index 0000000000..cb8e72ff0f --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected.gcc @@ -0,0 +1 @@ +| test.c:29:18:29:36 | ATOMIC_VAR_INIT(VALUE) | Usage of macro ATOMIC_VAR_INIT() is declared obscelescent in C18, and discouraged in earlier C versions. | diff --git a/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.qlref b/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.qlref new file mode 100644 index 0000000000..9a54fdc83a --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.qlref @@ -0,0 +1 @@ +rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/test.c b/c/misra/test/rules/RULE-1-5/test.c new file mode 100644 index 0000000000..52144bad13 --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/test.c @@ -0,0 +1,48 @@ +#include "stdatomic.h" +#include "stdbool.h" +#include "stdio.h" +#include "stdlib.h" + +void f1(int p0) { + // malloc() is not obsolete, though it is banned by Rule 21.3 + int *t = malloc(10); // COMPLIANT + + // Valid usage of realloc, but all use of realloc is banned by Rule 21.3 + realloc(t, 20); // NON-COMPLIANT + + // Obsolete usage of realloc. + realloc(t, 0); // NON-COMPLIANT + realloc(t, p0); // NON-COMPLIANT +} + +extern const int g1; // COMPLIANT +const extern int g2; // NON-COMPLIANT + +#define MY_TRUE 3 // COMPLIANT +#define true 3 // NON-COMPLIANT +#define false 3 // NON-COMPLIANT +#define bool int * // NON-COMPLIANT +#undef true // NON-COMPLIANT +#undef false // NON-COMPLIANT +#undef bool // NON-COMPLIANT + +_Atomic int g3 = ATOMIC_VAR_INIT(18); // NON-COMPLIANT +_Atomic int g4 = 18; // COMPLIANT + +// `gets` was removed from C11. +extern char *gets(FILE *stream); + +// Rule 21.6 covers the below cases: +void f6(void) { + gets(stdin); // NON_COMPLIANT + + FILE *file = fopen("", 0); + // Obsolete usage of ungetc. + ungetc('c', file); // NON-COMPLIANT + + char buf[10]; + fread(buf, sizeof(buf), 10, file); + // This is not an obsolete usage of ungetc, though ungetc isn't allowed by + // 21-3. + ungetc('c', file); // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.expected b/c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.expected index b04a4ee4aa..7a8fd1e07c 100644 --- a/c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.expected +++ b/c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.expected @@ -1,187 +1,209 @@ -| test.c:13:3:13:6 | access to array | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:14:3:14:6 | access to array | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:20:3:20:4 | + ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:21:3:21:4 | + ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:22:3:22:5 | + ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:27:3:27:4 | - ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:28:3:28:4 | - ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:29:3:29:5 | - ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:31:3:31:4 | - ... | Operand of essentially Unsigned type will be converted to a signed type with the signedness dependent on the implemented size of int. | -| test.c:34:3:34:7 | ... + ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:36:3:36:8 | ... + ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:41:3:41:7 | ... - ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:43:3:43:8 | ... - ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:48:3:48:7 | ... + ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:50:3:50:8 | ... + ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:55:3:55:7 | ... - ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:57:3:57:8 | ... - ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:62:3:62:5 | ... ++ | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:64:3:64:6 | ... ++ | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:69:3:69:5 | ... -- | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:71:3:71:6 | ... -- | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:76:3:76:5 | ++ ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:78:3:78:6 | ++ ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:83:3:83:5 | -- ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:85:3:85:6 | -- ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:90:3:90:7 | ... * ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:91:3:91:7 | ... * ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:92:3:92:8 | ... * ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:97:3:97:7 | ... / ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:98:3:98:7 | ... / ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:99:3:99:8 | ... / ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:104:3:104:7 | ... * ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:105:3:105:7 | ... * ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:106:3:106:8 | ... * ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:111:3:111:7 | ... / ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:112:3:112:7 | ... / ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:113:3:113:8 | ... / ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:118:3:118:7 | ... % ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:119:3:119:7 | ... % ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:120:3:120:8 | ... % ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:125:3:125:7 | ... % ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:126:3:126:7 | ... % ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:127:3:127:8 | ... % ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:132:3:132:7 | ... < ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:139:3:139:7 | ... > ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:146:3:146:8 | ... <= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:153:3:153:8 | ... >= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:160:3:160:7 | ... < ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:167:3:167:7 | ... > ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:174:3:174:8 | ... <= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:181:3:181:8 | ... >= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:217:3:217:4 | ! ... | Operand of essentially Character type type interpreted as a Boolean value. | -| test.c:218:3:218:5 | ! ... | Operand of essentially Enum Type type interpreted as a Boolean value. | -| test.c:219:3:219:4 | ! ... | Operand of essentially Signed type type interpreted as a Boolean value. | -| test.c:220:3:220:4 | ! ... | Operand of essentially Unsigned type type interpreted as a Boolean value. | -| test.c:221:3:221:4 | ! ... | Operand of essentially Floating type type interpreted as a Boolean value. | -| test.c:224:3:224:11 | ... && ... | Operand of essentially Character type type interpreted as a Boolean value. | -| test.c:225:3:225:12 | ... && ... | Operand of essentially Enum Type type interpreted as a Boolean value. | -| test.c:226:3:226:11 | ... && ... | Operand of essentially Signed type type interpreted as a Boolean value. | -| test.c:227:3:227:11 | ... && ... | Operand of essentially Unsigned type type interpreted as a Boolean value. | -| test.c:228:3:228:11 | ... && ... | Operand of essentially Floating type type interpreted as a Boolean value. | -| test.c:231:3:231:12 | ... \|\| ... | Operand of essentially Character type type interpreted as a Boolean value. | -| test.c:232:3:232:13 | ... \|\| ... | Operand of essentially Enum Type type interpreted as a Boolean value. | -| test.c:233:3:233:12 | ... \|\| ... | Operand of essentially Signed type type interpreted as a Boolean value. | -| test.c:234:3:234:12 | ... \|\| ... | Operand of essentially Unsigned type type interpreted as a Boolean value. | -| test.c:235:3:235:12 | ... \|\| ... | Operand of essentially Floating type type interpreted as a Boolean value. | -| test.c:238:3:238:11 | ... && ... | Operand of essentially Character type type interpreted as a Boolean value. | -| test.c:239:3:239:12 | ... && ... | Operand of essentially Enum Type type interpreted as a Boolean value. | -| test.c:240:3:240:11 | ... && ... | Operand of essentially Signed type type interpreted as a Boolean value. | -| test.c:241:3:241:11 | ... && ... | Operand of essentially Unsigned type type interpreted as a Boolean value. | -| test.c:242:3:242:11 | ... && ... | Operand of essentially Floating type type interpreted as a Boolean value. | -| test.c:245:3:245:12 | ... \|\| ... | Operand of essentially Character type type interpreted as a Boolean value. | -| test.c:246:3:246:13 | ... \|\| ... | Operand of essentially Enum Type type interpreted as a Boolean value. | -| test.c:247:3:247:12 | ... \|\| ... | Operand of essentially Signed type type interpreted as a Boolean value. | -| test.c:248:3:248:12 | ... \|\| ... | Operand of essentially Unsigned type type interpreted as a Boolean value. | -| test.c:249:3:249:12 | ... \|\| ... | Operand of essentially Floating type type interpreted as a Boolean value. | -| test.c:251:3:251:8 | ... << ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:252:3:252:8 | ... << ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:253:3:253:9 | ... << ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:254:3:254:8 | ... << ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:258:3:258:8 | ... >> ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:259:3:259:8 | ... >> ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:260:3:260:9 | ... >> ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:261:3:261:8 | ... >> ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:265:3:265:8 | ... << ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:266:3:266:8 | ... << ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:267:3:267:9 | ... << ... | Right hand operatand of shift operator is essentially Enum Type and not not essentially unsigned. | -| test.c:268:3:268:8 | ... << ... | Right hand operatand of shift operator is essentially Signed type and not not essentially unsigned. | -| test.c:272:3:272:8 | ... >> ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:273:3:273:8 | ... >> ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:274:3:274:9 | ... >> ... | Right hand operatand of shift operator is essentially Enum Type and not not essentially unsigned. | -| test.c:275:3:275:8 | ... >> ... | Right hand operatand of shift operator is essentially Signed type and not not essentially unsigned. | -| test.c:279:3:279:6 | ... & ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:280:3:280:6 | ... & ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:281:3:281:7 | ... & ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:282:3:282:6 | ... & ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:286:3:286:7 | ... \| ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:287:3:287:7 | ... \| ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:288:3:288:8 | ... \| ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:289:3:289:7 | ... \| ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:293:3:293:7 | ... ^ ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:294:3:294:7 | ... ^ ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:295:3:295:8 | ... ^ ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:296:3:296:7 | ... ^ ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:300:3:300:6 | ... & ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:301:3:301:6 | ... & ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:302:3:302:7 | ... & ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:303:3:303:6 | ... & ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:307:3:307:7 | ... \| ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:308:3:308:7 | ... \| ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:309:3:309:8 | ... \| ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:310:3:310:7 | ... \| ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:314:3:314:7 | ... ^ ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:315:3:315:7 | ... ^ ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:316:3:316:8 | ... ^ ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:317:3:317:7 | ... ^ ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:329:3:329:11 | ... ? ... : ... | Operand of essentially Character type type interpreted as a Boolean value. | -| test.c:330:3:330:12 | ... ? ... : ... | Operand of essentially Enum Type type interpreted as a Boolean value. | -| test.c:331:3:331:11 | ... ? ... : ... | Operand of essentially Signed type type interpreted as a Boolean value. | -| test.c:332:3:332:11 | ... ? ... : ... | Operand of essentially Unsigned type type interpreted as a Boolean value. | -| test.c:333:3:333:11 | ... ? ... : ... | Operand of essentially Floating type type interpreted as a Boolean value. | -| test.c:342:3:342:8 | ... += ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:344:3:344:9 | ... += ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:349:3:349:8 | ... -= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:351:3:351:9 | ... -= ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:356:3:356:8 | ... += ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:358:3:358:9 | ... += ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:363:3:363:8 | ... -= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:365:3:365:9 | ... -= ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:370:3:370:8 | ... *= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:371:3:371:8 | ... *= ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:372:3:372:9 | ... *= ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:377:3:377:8 | ... /= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:378:3:378:8 | ... /= ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:379:3:379:9 | ... /= ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:384:3:384:8 | ... *= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:385:3:385:8 | ... *= ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:386:3:386:9 | ... *= ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:391:3:391:8 | ... /= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:392:3:392:8 | ... /= ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:393:3:393:9 | ... /= ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:398:3:398:8 | ... %= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:399:3:399:8 | ... %= ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:400:3:400:9 | ... %= ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:405:3:405:8 | ... %= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:406:3:406:8 | ... %= ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:407:3:407:9 | ... %= ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:412:3:412:9 | ... <<= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:413:3:413:9 | ... <<= ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:414:3:414:10 | ... <<= ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:415:3:415:9 | ... <<= ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:419:3:419:9 | ... >>= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:420:3:420:9 | ... >>= ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:421:3:421:10 | ... >>= ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:422:3:422:9 | ... >>= ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:426:3:426:9 | ... <<= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:427:3:427:9 | ... <<= ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:428:3:428:10 | ... <<= ... | Right hand operatand of shift operator is essentially Enum Type and not not essentially unsigned. | -| test.c:429:3:429:9 | ... <<= ... | Right hand operatand of shift operator is essentially Signed type and not not essentially unsigned. | -| test.c:433:3:433:9 | ... >>= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:434:3:434:9 | ... >>= ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:435:3:435:10 | ... >>= ... | Right hand operatand of shift operator is essentially Enum Type and not not essentially unsigned. | -| test.c:436:3:436:9 | ... >>= ... | Right hand operatand of shift operator is essentially Signed type and not not essentially unsigned. | -| test.c:440:3:440:8 | ... &= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:441:3:441:8 | ... &= ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:442:3:442:9 | ... &= ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:443:3:443:8 | ... &= ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:447:3:447:8 | ... ^= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:448:3:448:8 | ... ^= ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:449:3:449:9 | ... ^= ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:450:3:450:8 | ... ^= ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:454:3:454:8 | ... \|= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:455:3:455:8 | ... \|= ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:456:3:456:9 | ... \|= ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:457:3:457:8 | ... \|= ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:461:3:461:8 | ... &= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:462:3:462:8 | ... &= ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:463:3:463:9 | ... &= ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:464:3:464:8 | ... &= ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:468:3:468:8 | ... ^= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:469:3:469:8 | ... ^= ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:470:3:470:9 | ... ^= ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:471:3:471:8 | ... ^= ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:475:3:475:8 | ... \|= ... | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:476:3:476:8 | ... \|= ... | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:477:3:477:9 | ... \|= ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:478:3:478:8 | ... \|= ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:15:5:15:5 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:16:5:16:5 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:23:4:23:4 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:24:4:24:4 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:25:4:25:5 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:31:4:31:4 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:32:4:32:4 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:33:4:33:5 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:35:4:35:4 | u | Operand of essentially Unsigned type will be converted to a signed type with the signedness dependent on the implemented size of int. | +| test.c:39:7:39:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:41:7:41:8 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:47:7:47:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:49:7:49:8 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:55:3:55:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:57:3:57:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:63:3:63:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:65:3:65:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:71:3:71:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:73:3:73:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:77:3:77:4 | cf | Use of essentially Complex type in this way is a constraint violation. | +| test.c:79:3:79:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:81:3:81:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:85:3:85:4 | cf | Use of essentially Complex type in this way is a constraint violation. | +| test.c:87:5:87:5 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:89:5:89:6 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:93:5:93:6 | cf | Use of essentially Complex type in this way is a constraint violation. | +| test.c:95:5:95:5 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:97:5:97:6 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:101:5:101:6 | cf | Use of essentially Complex type in this way is a constraint violation. | +| test.c:103:7:103:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:104:7:104:7 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:105:7:105:8 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:111:7:111:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:112:7:112:7 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:113:7:113:8 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:119:3:119:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:120:3:120:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:121:3:121:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:127:3:127:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:128:3:128:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:129:3:129:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:135:3:135:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:136:3:136:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:137:3:137:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:143:7:143:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:144:7:144:7 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:145:7:145:8 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:151:7:151:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:159:7:159:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:167:8:167:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:175:8:175:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:183:3:183:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:191:3:191:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:199:3:199:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:207:3:207:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:220:3:220:3 | f | Floating point numbers have inherent error such that comparisons should consider precision and not exact equality. | +| test.c:221:3:221:4 | cf | Floating point numbers have inherent error such that comparisons should consider precision and not exact equality. | +| test.c:234:3:234:3 | f | Floating point numbers have inherent error such that comparisons should consider precision and not exact equality. | +| test.c:235:3:235:4 | cf | Floating point numbers have inherent error such that comparisons should consider precision and not exact equality. | +| test.c:248:8:248:8 | f | Floating point numbers have inherent error such that comparisons should consider precision and not exact equality. | +| test.c:249:8:249:9 | cf | Floating point numbers have inherent error such that comparisons should consider precision and not exact equality. | +| test.c:262:8:262:8 | f | Floating point numbers have inherent error such that comparisons should consider precision and not exact equality. | +| test.c:263:8:263:9 | cf | Floating point numbers have inherent error such that comparisons should consider precision and not exact equality. | +| test.c:272:4:272:4 | c | Operand of essentially Character type type interpreted as a Boolean value. | +| test.c:273:4:273:5 | e1 | Operand of essentially Enum Type type interpreted as a Boolean value. | +| test.c:274:4:274:4 | s | Operand of essentially Signed type type interpreted as a Boolean value. | +| test.c:275:4:275:4 | u | Operand of essentially Unsigned type type interpreted as a Boolean value. | +| test.c:276:4:276:4 | f | Operand of essentially Floating type type interpreted as a Boolean value. | +| test.c:277:4:277:5 | cf | Operand of essentially Complex Floating type type interpreted as a Boolean value. | +| test.c:280:3:280:3 | c | Operand of essentially Character type type interpreted as a Boolean value. | +| test.c:281:3:281:4 | e1 | Operand of essentially Enum Type type interpreted as a Boolean value. | +| test.c:282:3:282:3 | s | Operand of essentially Signed type type interpreted as a Boolean value. | +| test.c:283:3:283:3 | u | Operand of essentially Unsigned type type interpreted as a Boolean value. | +| test.c:284:3:284:3 | f | Operand of essentially Floating type type interpreted as a Boolean value. | +| test.c:285:3:285:4 | cf | Operand of essentially Complex Floating type type interpreted as a Boolean value. | +| test.c:288:3:288:3 | c | Operand of essentially Character type type interpreted as a Boolean value. | +| test.c:289:3:289:4 | e1 | Operand of essentially Enum Type type interpreted as a Boolean value. | +| test.c:290:3:290:3 | s | Operand of essentially Signed type type interpreted as a Boolean value. | +| test.c:291:3:291:3 | u | Operand of essentially Unsigned type type interpreted as a Boolean value. | +| test.c:292:3:292:3 | f | Operand of essentially Floating type type interpreted as a Boolean value. | +| test.c:293:3:293:4 | cf | Operand of essentially Complex Floating type type interpreted as a Boolean value. | +| test.c:296:11:296:11 | c | Operand of essentially Character type type interpreted as a Boolean value. | +| test.c:297:11:297:12 | e1 | Operand of essentially Enum Type type interpreted as a Boolean value. | +| test.c:298:11:298:11 | s | Operand of essentially Signed type type interpreted as a Boolean value. | +| test.c:299:11:299:11 | u | Operand of essentially Unsigned type type interpreted as a Boolean value. | +| test.c:300:11:300:11 | f | Operand of essentially Floating type type interpreted as a Boolean value. | +| test.c:301:11:301:12 | cf | Operand of essentially Complex Floating type type interpreted as a Boolean value. | +| test.c:304:12:304:12 | c | Operand of essentially Character type type interpreted as a Boolean value. | +| test.c:305:12:305:13 | e1 | Operand of essentially Enum Type type interpreted as a Boolean value. | +| test.c:306:12:306:12 | s | Operand of essentially Signed type type interpreted as a Boolean value. | +| test.c:307:12:307:12 | u | Operand of essentially Unsigned type type interpreted as a Boolean value. | +| test.c:308:12:308:12 | f | Operand of essentially Floating type type interpreted as a Boolean value. | +| test.c:309:12:309:13 | cf | Operand of essentially Complex Floating type type interpreted as a Boolean value. | +| test.c:311:3:311:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:312:3:312:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:313:3:313:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:314:3:314:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:319:3:319:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:320:3:320:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:321:3:321:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:322:3:322:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:327:8:327:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:328:8:328:8 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:329:8:329:9 | e1 | Right hand operand of shift operator is essentially Enum Type and not not essentially unsigned. | +| test.c:330:8:330:8 | s | Right hand operand of shift operator is essentially Signed type and not not essentially unsigned. | +| test.c:335:8:335:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:336:8:336:8 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:337:8:337:9 | e1 | Right hand operand of shift operator is essentially Enum Type and not not essentially unsigned. | +| test.c:338:8:338:8 | s | Right hand operand of shift operator is essentially Signed type and not not essentially unsigned. | +| test.c:343:3:343:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:344:3:344:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:345:3:345:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:346:3:346:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:351:3:351:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:352:3:352:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:353:3:353:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:354:3:354:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:359:3:359:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:360:3:360:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:361:3:361:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:362:3:362:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:367:6:367:6 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:368:6:368:6 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:369:6:369:7 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:370:6:370:6 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:375:7:375:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:376:7:376:7 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:377:7:377:8 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:378:7:378:7 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:383:7:383:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:384:7:384:7 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:385:7:385:8 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:386:7:386:7 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:391:4:391:4 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:392:4:392:4 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:393:4:393:5 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:394:4:394:4 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:400:3:400:3 | c | Operand of essentially Character type type interpreted as a Boolean value. | +| test.c:401:3:401:4 | e1 | Operand of essentially Enum Type type interpreted as a Boolean value. | +| test.c:402:3:402:3 | s | Operand of essentially Signed type type interpreted as a Boolean value. | +| test.c:403:3:403:3 | u | Operand of essentially Unsigned type type interpreted as a Boolean value. | +| test.c:404:3:404:3 | f | Operand of essentially Floating type type interpreted as a Boolean value. | +| test.c:405:3:405:4 | cf | Operand of essentially Complex Floating type type interpreted as a Boolean value. | +| test.c:415:3:415:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:417:3:417:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:423:3:423:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:425:3:425:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:431:8:431:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:433:8:433:9 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:439:8:439:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:441:8:441:9 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:447:3:447:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:448:3:448:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:449:3:449:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:455:3:455:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:456:3:456:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:457:3:457:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:463:8:463:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:464:8:464:8 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:465:8:465:9 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:471:8:471:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:472:8:472:8 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:473:8:473:9 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:479:3:479:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:480:3:480:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:481:3:481:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:487:8:487:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:488:8:488:8 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:489:8:489:9 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:495:3:495:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:496:3:496:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:497:3:497:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:498:3:498:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:503:3:503:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:504:3:504:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:505:3:505:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:506:3:506:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:511:9:511:9 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:512:9:512:9 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:513:9:513:10 | e1 | Right hand operand of shift operator is essentially Enum Type and not not essentially unsigned. | +| test.c:514:9:514:9 | s | Right hand operand of shift operator is essentially Signed type and not not essentially unsigned. | +| test.c:519:9:519:9 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:520:9:520:9 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:521:9:521:10 | e1 | Right hand operand of shift operator is essentially Enum Type and not not essentially unsigned. | +| test.c:522:9:522:9 | s | Right hand operand of shift operator is essentially Signed type and not not essentially unsigned. | +| test.c:527:3:527:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:528:3:528:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:529:3:529:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:530:3:530:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:535:3:535:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:536:3:536:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:537:3:537:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:538:3:538:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:543:3:543:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:544:3:544:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:545:3:545:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:546:3:546:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:551:8:551:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:552:8:552:8 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:553:8:553:9 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:554:8:554:8 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:559:8:559:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:560:8:560:8 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:561:8:561:9 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:562:8:562:8 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:567:8:567:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:568:8:568:8 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:569:8:569:9 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:570:8:570:8 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | diff --git a/c/misra/test/rules/RULE-10-1/PointerTypeOnLogicalOperator.expected b/c/misra/test/rules/RULE-10-1/PointerTypeOnLogicalOperator.expected index 35a55919fd..34d2993389 100644 --- a/c/misra/test/rules/RULE-10-1/PointerTypeOnLogicalOperator.expected +++ b/c/misra/test/rules/RULE-10-1/PointerTypeOnLogicalOperator.expected @@ -1,5 +1,5 @@ -| test.c:488:4:488:4 | p | Logical operators should not be used with pointer types. | -| test.c:490:3:490:3 | p | Logical operators should not be used with pointer types. | -| test.c:491:7:491:7 | p | Logical operators should not be used with pointer types. | -| test.c:493:3:493:3 | p | Logical operators should not be used with pointer types. | -| test.c:494:8:494:8 | p | Logical operators should not be used with pointer types. | +| test.c:581:4:581:4 | p | Logical operators should not be used with pointer types. | +| test.c:583:3:583:3 | p | Logical operators should not be used with pointer types. | +| test.c:584:7:584:7 | p | Logical operators should not be used with pointer types. | +| test.c:586:3:586:3 | p | Logical operators should not be used with pointer types. | +| test.c:587:8:587:8 | p | Logical operators should not be used with pointer types. | diff --git a/c/misra/test/rules/RULE-10-1/test.c b/c/misra/test/rules/RULE-10-1/test.c index 19b7d2e3e8..3b96c7151d 100644 --- a/c/misra/test/rules/RULE-10-1/test.c +++ b/c/misra/test/rules/RULE-10-1/test.c @@ -1,3 +1,4 @@ +#include "math.h" #include "stdbool.h" void testInappropriateOperands() { @@ -7,6 +8,7 @@ void testInappropriateOperands() { signed int s = 100; unsigned int u = 1; float f = 1.0; + float _Complex cf = 1.0 + 1.0i; int a[20]; @@ -16,6 +18,7 @@ void testInappropriateOperands() { a[s]; // COMPLIANT a[u]; // COMPLIANT // a[f]; // NON_COMPILABLE + // a[cf]; // NON_COMPILABLE +b; // NON_COMPLIANT +c; // NON_COMPLIANT @@ -23,6 +26,7 @@ void testInappropriateOperands() { +s; // COMPLIANT +u; // COMPLIANT +f; // COMPLIANT + +cf; // COMPLIANT -b; // NON_COMPLIANT -c; // NON_COMPLIANT @@ -30,6 +34,7 @@ void testInappropriateOperands() { -s; // COMPLIANT -u; // NON_COMPLIANT -f; // COMPLIANT + -cf; // COMPLIANT 1 + b; // NON_COMPLIANT 1 + c; // COMPLIANT @@ -37,6 +42,7 @@ void testInappropriateOperands() { 1 + s; // COMPLIANT 1 + u; // COMPLIANT 1 + f; // COMPLIANT + 1 + cf; // COMPLIANT 1 - b; // NON_COMPLIANT 1 - c; // COMPLIANT @@ -44,6 +50,7 @@ void testInappropriateOperands() { 1 - s; // COMPLIANT 1 - u; // COMPLIANT 1 - f; // COMPLIANT + 1 - cf; // COMPLIANT b + 1; // NON_COMPLIANT c + 1; // COMPLIANT @@ -51,6 +58,7 @@ void testInappropriateOperands() { s + 1; // COMPLIANT u + 1; // COMPLIANT f + 1; // COMPLIANT + cf + 1; // COMPLIANT b - 1; // NON_COMPLIANT c - 1; // COMPLIANT @@ -58,6 +66,7 @@ void testInappropriateOperands() { s - 1; // COMPLIANT u - 1; // COMPLIANT f - 1; // COMPLIANT + cf - 1; // COMPLIANT b++; // NON_COMPLIANT c++; // COMPLIANT @@ -65,6 +74,7 @@ void testInappropriateOperands() { s++; // COMPLIANT u++; // COMPLIANT f++; // COMPLIANT + cf++; // NON_COMPLIANT b--; // NON_COMPLIANT c--; // COMPLIANT @@ -72,6 +82,7 @@ void testInappropriateOperands() { s--; // COMPLIANT u--; // COMPLIANT f--; // COMPLIANT + cf--; // NON_COMPLIANT ++b; // NON_COMPLIANT ++c; // COMPLIANT @@ -79,6 +90,7 @@ void testInappropriateOperands() { ++s; // COMPLIANT ++u; // COMPLIANT ++f; // COMPLIANT + ++cf; // NON_COMPLIANT --b; // NON_COMPLIANT --c; // COMPLIANT @@ -86,6 +98,7 @@ void testInappropriateOperands() { --s; // COMPLIANT --u; // COMPLIANT --f; // COMPLIANT + --cf; // NON_COMPLIANT 1 * b; // NON_COMPLIANT 1 * c; // NON_COMPLIANT @@ -93,6 +106,7 @@ void testInappropriateOperands() { 1 * s; // COMPLIANT 1 * u; // COMPLIANT 1 * f; // COMPLIANT + 1 * cf; // COMPLIANT 1 / b; // NON_COMPLIANT 1 / c; // NON_COMPLIANT @@ -100,6 +114,7 @@ void testInappropriateOperands() { 1 / s; // COMPLIANT 1 / u; // COMPLIANT 1 / f; // COMPLIANT + 1 / cf; // COMPLIANT b * 1; // NON_COMPLIANT c * 1; // NON_COMPLIANT @@ -107,6 +122,7 @@ void testInappropriateOperands() { s * 1; // COMPLIANT u * 1; // COMPLIANT f * 1; // COMPLIANT + cf * 1; // COMPLIANT b / 1; // NON_COMPLIANT c / 1; // NON_COMPLIANT @@ -114,6 +130,7 @@ void testInappropriateOperands() { s / 1; // COMPLIANT u / 1; // COMPLIANT f / 1; // COMPLIANT + cf / 1; // COMPLIANT b % 1; // NON_COMPLIANT c % 1; // NON_COMPLIANT @@ -121,6 +138,7 @@ void testInappropriateOperands() { s % 1; // COMPLIANT u % 1; // COMPLIANT // f % 1; // NON_COMPILABLE + // cf % 1; // NON_COMPILABLE 1 % b; // NON_COMPLIANT 1 % c; // NON_COMPLIANT @@ -128,6 +146,7 @@ void testInappropriateOperands() { 1 % s; // COMPLIANT 1 % u; // COMPLIANT // 1 % f; // NON_COMPILABLE + // 1 % cf; // NON_COMPILABLE 1 < b; // NON_COMPLIANT 1 < c; // COMPLIANT @@ -135,6 +154,7 @@ void testInappropriateOperands() { 1 < s; // COMPLIANT 1 < u; // COMPLIANT 1 < f; // COMPLIANT + // 1 < cf; // NON_COMPILABLE 1 > b; // NON_COMPLIANT 1 > c; // COMPLIANT @@ -142,6 +162,7 @@ void testInappropriateOperands() { 1 > s; // COMPLIANT 1 > u; // COMPLIANT 1 > f; // COMPLIANT + // 1 > cf; // NON_COMPILABLE 1 <= b; // NON_COMPLIANT 1 <= c; // COMPLIANT @@ -149,6 +170,7 @@ void testInappropriateOperands() { 1 <= s; // COMPLIANT 1 <= u; // COMPLIANT 1 <= f; // COMPLIANT + // 1 <= cf; // NON_COMPILABLE 1 >= b; // NON_COMPLIANT 1 >= c; // COMPLIANT @@ -156,6 +178,7 @@ void testInappropriateOperands() { 1 >= s; // COMPLIANT 1 >= u; // COMPLIANT 1 >= f; // COMPLIANT + // 1 >= cf; // NON_COMPILABLE b < 1; // NON_COMPLIANT c < 1; // COMPLIANT @@ -163,6 +186,7 @@ void testInappropriateOperands() { s < 1; // COMPLIANT u < 1; // COMPLIANT f < 1; // COMPLIANT + // cf < 1; // NON_COMPILABLE b > 1; // NON_COMPLIANT c > 1; // COMPLIANT @@ -170,6 +194,7 @@ void testInappropriateOperands() { s > 1; // COMPLIANT u > 1; // COMPLIANT f > 1; // COMPLIANT + // cf > 1; // NON_COMPILABLE b <= 1; // NON_COMPLIANT c <= 1; // COMPLIANT @@ -177,6 +202,7 @@ void testInappropriateOperands() { s <= 1; // COMPLIANT u <= 1; // COMPLIANT f <= 1; // COMPLIANT + // cf <= 1; // NON_COMPILABLE b >= 1; // NON_COMPLIANT c >= 1; // COMPLIANT @@ -184,34 +210,63 @@ void testInappropriateOperands() { s >= 1; // COMPLIANT u >= 1; // COMPLIANT f >= 1; // COMPLIANT - - b == 1; // COMPLIANT - c == 1; // COMPLIANT - e1 == 1; // COMPLIANT - s == 1; // COMPLIANT - u == 1; // COMPLIANT - f == 1; // COMPLIANT - - b != 1; // COMPLIANT - c != 1; // COMPLIANT - e1 != 1; // COMPLIANT - s != 1; // COMPLIANT - u != 1; // COMPLIANT - f != 1; // COMPLIANT - - 1 == b; // COMPLIANT - 1 == c; // COMPLIANT - 1 == e1; // COMPLIANT - 1 == s; // COMPLIANT - 1 == u; // COMPLIANT - 1 == f; // COMPLIANT - - 1 != b; // COMPLIANT - 1 != c; // COMPLIANT - 1 != e1; // COMPLIANT - 1 != s; // COMPLIANT - 1 != u; // COMPLIANT - 1 != f; // COMPLIANT + // cf >= 1; // NON_COMPILABLE + + b == 1; // COMPLIANT + c == 1; // COMPLIANT + e1 == 1; // COMPLIANT + s == 1; // COMPLIANT + u == 1; // COMPLIANT + f == 1; // NON_COMPLIANT + cf == 1; // NON_COMPLIANT + f == 0; // COMPLIANT + f == INFINITY; // COMPLIANT + f == -INFINITY; // COMPLIANT + cf == 0; // COMPLIANT + cf == INFINITY; // COMPLIANT + cf == -INFINITY; // COMPLIANT + + b != 1; // COMPLIANT + c != 1; // COMPLIANT + e1 != 1; // COMPLIANT + s != 1; // COMPLIANT + u != 1; // COMPLIANT + f != 1; // NON_COMPLIANT + cf != 1; // NON_COMPLIANT + f != 0; // COMPLIANT + f != INFINITY; // COMPLIANT + f != -INFINITY; // COMPLIANT + cf != 0; // COMPLIANT + cf != INFINITY; // COMPLIANT + cf != -INFINITY; // COMPLIANT + + 1 == b; // COMPLIANT + 1 == c; // COMPLIANT + 1 == e1; // COMPLIANT + 1 == s; // COMPLIANT + 1 == u; // COMPLIANT + 1 == f; // NON_COMPLIANT + 1 == cf; // NON_COMPLIANT + 0 == f; // COMPLIANT + INFINITY == f; // COMPLIANT + -INFINITY == f; // COMPLIANT + 0 == cf; // COMPLIANT + INFINITY == cf; // COMPLIANT + -INFINITY == cf; // COMPLIANT + + 1 != b; // COMPLIANT + 1 != c; // COMPLIANT + 1 != e1; // COMPLIANT + 1 != s; // COMPLIANT + 1 != u; // COMPLIANT + 1 != f; // NON_COMPLIANT + 1 != cf; // NON_COMPLIANT + 0 != f; // COMPLIANT + INFINITY != f; // COMPLIANT + -INFINITY != f; // COMPLIANT + 0 != cf; // COMPLIANT + INFINITY != cf; // COMPLIANT + -INFINITY != cf; // COMPLIANT !b; // COMPLIANT !c; // NON_COMPLIANT @@ -219,6 +274,7 @@ void testInappropriateOperands() { !s; // NON_COMPLIANT !u; // NON_COMPLIANT !f; // NON_COMPLIANT + !cf; // NON_COMPLIANT b && true; // COMPLIANT c && true; // NON_COMPLIANT @@ -226,6 +282,7 @@ void testInappropriateOperands() { s && true; // NON_COMPLIANT u && true; // NON_COMPLIANT f && true; // NON_COMPLIANT + cf && true; // NON_COMPLIANT b || false; // COMPLIANT c || false; // NON_COMPLIANT @@ -233,6 +290,7 @@ void testInappropriateOperands() { s || false; // NON_COMPLIANT u || false; // NON_COMPLIANT f || false; // NON_COMPLIANT + cf || false; // NON_COMPLIANT true && b; // COMPLIANT true && c; // NON_COMPLIANT @@ -240,6 +298,7 @@ void testInappropriateOperands() { true && s; // NON_COMPLIANT true && u; // NON_COMPLIANT true && f; // NON_COMPLIANT + true && cf; // NON_COMPLIANT false || b; // COMPLIANT false || c; // NON_COMPLIANT @@ -247,6 +306,7 @@ void testInappropriateOperands() { false || s; // NON_COMPLIANT false || u; // NON_COMPLIANT false || f; // NON_COMPLIANT + false || cf; // NON_COMPLIANT b << u; // NON_COMPLIANT c << u; // NON_COMPLIANT @@ -254,6 +314,7 @@ void testInappropriateOperands() { s << u; // NON_COMPLIANT u << u; // COMPLIANT // f << u; // NON_COMPILABLE + // cf << u; // NON_COMPILABLE b >> u; // NON_COMPLIANT c >> u; // NON_COMPLIANT @@ -261,6 +322,7 @@ void testInappropriateOperands() { s >> u; // NON_COMPLIANT u >> u; // COMPLIANT // f >> u; // NON_COMPILABLE + // cf >> u; // NON_COMPILABLE u << b; // NON_COMPLIANT u << c; // NON_COMPLIANT @@ -268,6 +330,7 @@ void testInappropriateOperands() { u << s; // NON_COMPLIANT u << u; // COMPLIANT // u << f; // NON_COMPILABLE + // u << cf; // NON_COMPILABLE u >> b; // NON_COMPLIANT u >> c; // NON_COMPLIANT @@ -275,6 +338,7 @@ void testInappropriateOperands() { u >> s; // NON_COMPLIANT u >> u; // COMPLIANT // u >> f; // NON_COMPILABLE + // u >> cf; // NON_COMPILABLE b &u; // NON_COMPLIANT c &u; // NON_COMPLIANT @@ -282,6 +346,7 @@ void testInappropriateOperands() { s &u; // NON_COMPLIANT u &u; // COMPLIANT // f &u; // NON_COMPILABLE + // cf &u; // NON_COMPILABLE b | u; // NON_COMPLIANT c | u; // NON_COMPLIANT @@ -289,6 +354,7 @@ void testInappropriateOperands() { s | u; // NON_COMPLIANT u | u; // COMPLIANT // f | u; // NON_COMPILABLE + // cf | u; // NON_COMPILABLE b ^ u; // NON_COMPLIANT c ^ u; // NON_COMPLIANT @@ -296,6 +362,7 @@ void testInappropriateOperands() { s ^ u; // NON_COMPLIANT u ^ u; // COMPLIANT // f ^ u; // NON_COMPILABLE + // cf ^ u; // NON_COMPILABLE u &b; // NON_COMPLIANT u &c; // NON_COMPLIANT @@ -303,6 +370,7 @@ void testInappropriateOperands() { u &s; // NON_COMPLIANT u &u; // COMPLIANT // u &f; // NON_COMPILABLE + // u &cf; // NON_COMPILABLE u | b; // NON_COMPLIANT u | c; // NON_COMPLIANT @@ -310,6 +378,7 @@ void testInappropriateOperands() { u | s; // NON_COMPLIANT u | u; // COMPLIANT // u | f; // NON_COMPILABLE + // u | cf; // NON_COMPILABLE u ^ b; // NON_COMPLIANT u ^ c; // NON_COMPLIANT @@ -317,6 +386,7 @@ void testInappropriateOperands() { u ^ s; // NON_COMPLIANT u ^ u; // COMPLIANT // u ^ f; // NON_COMPILABLE + // u ^ cf; // NON_COMPILABLE ~b; // NON_COMPLIANT ~c; // NON_COMPLIANT @@ -324,6 +394,7 @@ void testInappropriateOperands() { ~s; // NON_COMPLIANT ~u; // COMPLIANT //~f; // NON_COMPILABLE + ~cf; // NON_COMPLIANT b ? 1 : 2; // COMPLIANT c ? 1 : 2; // NON_COMPLIANT @@ -331,6 +402,7 @@ void testInappropriateOperands() { s ? 1 : 2; // NON_COMPLIANT u ? 1 : 2; // NON_COMPLIANT f ? 1 : 2; // NON_COMPLIANT + cf ? 1 : 2; // NON_COMPLIANT b ? b : b; // COMPLIANT b ? c : c; // COMPLIANT @@ -338,6 +410,7 @@ void testInappropriateOperands() { b ? s : s; // COMPLIANT b ? u : u; // COMPLIANT b ? f : f; // COMPLIANT + b ? cf : cf; // COMPLIANT b += 1; // NON_COMPLIANT c += 1; // COMPLIANT @@ -345,6 +418,7 @@ void testInappropriateOperands() { s += 1; // COMPLIANT u += 1; // COMPLIANT f += 1; // COMPLIANT + cf += 1; // COMPLIANT b -= 1; // NON_COMPLIANT c -= 1; // COMPLIANT @@ -352,6 +426,7 @@ void testInappropriateOperands() { s -= 1; // COMPLIANT u -= 1; // COMPLIANT f -= 1; // COMPLIANT + cf -= 1; // COMPLIANT u += b; // NON_COMPLIANT u += c; // COMPLIANT @@ -359,6 +434,7 @@ void testInappropriateOperands() { u += s; // COMPLIANT u += u; // COMPLIANT u += f; // COMPLIANT + u += cf; // COMPLIANT u -= b; // NON_COMPLIANT u -= c; // COMPLIANT @@ -366,6 +442,7 @@ void testInappropriateOperands() { u -= s; // COMPLIANT u -= u; // COMPLIANT u -= f; // COMPLIANT + u -= cf; // COMPLIANT b *= 1; // NON_COMPLIANT c *= 1; // NON_COMPLIANT @@ -373,6 +450,7 @@ void testInappropriateOperands() { s *= 1; // COMPLIANT u *= 1; // COMPLIANT f *= 1; // COMPLIANT + cf *= 1; // COMPLIANT b /= 1; // NON_COMPLIANT c /= 1; // NON_COMPLIANT @@ -380,6 +458,7 @@ void testInappropriateOperands() { s /= 1; // COMPLIANT u /= 1; // COMPLIANT f /= 1; // COMPLIANT + cf /= 1; // COMPLIANT u *= b; // NON_COMPLIANT u *= c; // NON_COMPLIANT @@ -387,6 +466,7 @@ void testInappropriateOperands() { u *= s; // COMPLIANT u *= u; // COMPLIANT u *= f; // COMPLIANT + u *= cf; // COMPLIANT u /= b; // NON_COMPLIANT u /= c; // NON_COMPLIANT @@ -394,6 +474,7 @@ void testInappropriateOperands() { u /= s; // COMPLIANT u /= u; // COMPLIANT u /= f; // COMPLIANT + u /= cf; // COMPLIANT b %= 1; // NON_COMPLIANT c %= 1; // NON_COMPLIANT @@ -401,6 +482,7 @@ void testInappropriateOperands() { s %= 1; // COMPLIANT u %= 1; // COMPLIANT // f %= 1; // NON_COMPILABLE + // cf %= 1; // NON_COMPILABLE u %= b; // NON_COMPLIANT u %= c; // NON_COMPLIANT @@ -408,6 +490,7 @@ void testInappropriateOperands() { u %= s; // COMPLIANT u %= u; // COMPLIANT // u %= f; // NON_COMPILABLE + // u %= cf; // NON_COMPILABLE b <<= u; // NON_COMPLIANT c <<= u; // NON_COMPLIANT @@ -415,6 +498,7 @@ void testInappropriateOperands() { s <<= u; // NON_COMPLIANT u <<= u; // COMPLIANT // f <<= u; // NON_COMPILABLE + // cf <<= u; // NON_COMPILABLE b >>= u; // NON_COMPLIANT c >>= u; // NON_COMPLIANT @@ -422,6 +506,7 @@ void testInappropriateOperands() { s >>= u; // NON_COMPLIANT u >>= u; // COMPLIANT // f >>= u; // NON_COMPILABLE + // cf >>= u; // NON_COMPILABLE u <<= b; // NON_COMPLIANT u <<= c; // NON_COMPLIANT @@ -429,6 +514,7 @@ void testInappropriateOperands() { u <<= s; // NON_COMPLIANT u <<= u; // COMPLIANT // u <<= f; // NON_COMPILABLE + // u <<= cf; // NON_COMPILABLE u >>= b; // NON_COMPLIANT u >>= c; // NON_COMPLIANT @@ -436,6 +522,7 @@ void testInappropriateOperands() { u >>= s; // NON_COMPLIANT u >>= u; // COMPLIANT // u >>= f; // NON_COMPILABLE + // u >>= cf; // NON_COMPILABLE b &= u; // NON_COMPLIANT c &= u; // NON_COMPLIANT @@ -443,6 +530,7 @@ void testInappropriateOperands() { s &= u; // NON_COMPLIANT u &= u; // COMPLIANT // f &= u; // NON_COMPILABLE + // cf &= u; // NON_COMPILABLE b ^= u; // NON_COMPLIANT c ^= u; // NON_COMPLIANT @@ -450,6 +538,7 @@ void testInappropriateOperands() { s ^= u; // NON_COMPLIANT u ^= u; // COMPLIANT // f ^= u; // NON_COMPILABLE + // cf ^= u; // NON_COMPILABLE b |= u; // NON_COMPLIANT c |= u; // NON_COMPLIANT @@ -457,6 +546,7 @@ void testInappropriateOperands() { s |= u; // NON_COMPLIANT u |= u; // COMPLIANT // f |= u; // NON_COMPILABLE + // cf |= u; // NON_COMPILABLE u &= b; // NON_COMPLIANT u &= c; // NON_COMPLIANT @@ -464,6 +554,7 @@ void testInappropriateOperands() { u &= s; // NON_COMPLIANT u &= u; // COMPLIANT // u &= f; // NON_COMPILABLE + // u &= cf; // NON_COMPILABLE u ^= b; // NON_COMPLIANT u ^= c; // NON_COMPLIANT @@ -471,6 +562,7 @@ void testInappropriateOperands() { u ^= s; // NON_COMPLIANT u ^= u; // COMPLIANT // u ^= f; // NON_COMPILABLE + // u ^= cf; // NON_COMPILABLE u |= b; // NON_COMPLIANT u |= c; // NON_COMPLIANT @@ -478,6 +570,7 @@ void testInappropriateOperands() { u |= s; // NON_COMPLIANT u |= u; // COMPLIANT // u |= f; // NON_COMPILABLE + // u |= cf; // NON_COMPILABLE } void pointerType() { diff --git a/c/misra/test/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.expected b/c/misra/test/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.expected index 0a5c7ae0bb..a1d3657a1e 100644 --- a/c/misra/test/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.expected +++ b/c/misra/test/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.expected @@ -1,15 +1,19 @@ -| test.c:15:3:15:11 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:16:3:16:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:17:3:17:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:18:3:18:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:19:3:19:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:20:3:20:10 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:21:3:21:10 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:27:3:27:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:28:3:28:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:29:3:29:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:30:3:30:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:31:3:31:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:32:3:32:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:33:3:33:10 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:34:3:34:10 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:19:3:19:11 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:20:3:20:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:21:3:21:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:22:3:22:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:23:3:23:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:24:3:24:10 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:25:3:25:10 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:28:3:28:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:29:3:29:10 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:35:3:35:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:36:3:36:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:37:3:37:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:38:3:38:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:39:3:39:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:40:3:40:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:41:3:41:10 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:42:3:42:10 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:45:3:45:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:46:3:46:10 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | diff --git a/c/misra/test/rules/RULE-10-2/test.c b/c/misra/test/rules/RULE-10-2/test.c index 186c49226e..1d86013c07 100644 --- a/c/misra/test/rules/RULE-10-2/test.c +++ b/c/misra/test/rules/RULE-10-2/test.c @@ -5,6 +5,10 @@ void testRules() { enum E1 { A, B, C } e1 = A; signed int i = 100; unsigned int u = 100; + signed short s = 100; + unsigned short us = 100; + signed long l = 100L; + unsigned long ul = 100UL; float f = 10.0f; // Addition cases @@ -19,8 +23,12 @@ void testRules() { b + 'a'; // NON_COMPLIANT 'a' + e1; // NON_COMPLIANT e1 + 'a'; // NON_COMPLIANT + 'a' + s; // COMPLIANT + 'a' + us; // COMPLIANT + 'a' + l; // NON_COMPLIANT + 'a' + ul; // NON_COMPLIANT - // Subtration cases + // Subtraction cases 'a' - i; // COMPLIANT 'a' - u; // COMPLIANT 'a' - 'a'; // COMPLIANT @@ -32,4 +40,8 @@ void testRules() { 'a' - b; // NON_COMPLIANT e1 - 'a'; // NON_COMPLIANT 'a' - e1; // NON_COMPLIANT + 'a' - s; // COMPLIANT + 'a' - us; // COMPLIANT + 'a' - l; // NON_COMPLIANT + 'a' - ul; // NON_COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.expected b/c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.expected index 3867abd0ca..edfd93dc51 100644 --- a/c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.expected +++ b/c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.expected @@ -1,133 +1,194 @@ -| test.c:11:7:11:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | -| test.c:12:7:12:7 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | -| test.c:13:7:13:7 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | -| test.c:14:7:14:7 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | -| test.c:16:8:16:8 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | -| test.c:18:8:18:8 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | -| test.c:19:8:19:8 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | -| test.c:20:8:20:8 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | -| test.c:22:7:22:7 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | -| test.c:23:7:23:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | -| test.c:25:7:25:7 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | -| test.c:26:7:26:7 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | -| test.c:28:7:28:7 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | -| test.c:29:7:29:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | -| test.c:30:7:30:7 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | -| test.c:32:7:32:7 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | -| test.c:34:7:34:7 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | -| test.c:35:7:35:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | -| test.c:36:7:36:7 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | -| test.c:37:7:37:7 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | -| test.c:49:14:49:15 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | -| test.c:50:14:50:14 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | -| test.c:51:14:51:14 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | -| test.c:52:14:52:14 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | -| test.c:54:17:54:17 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | -| test.c:56:17:56:17 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | -| test.c:57:17:57:17 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | -| test.c:58:17:58:17 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | -| test.c:60:19:60:19 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | -| test.c:61:19:61:20 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | -| test.c:63:19:63:19 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | -| test.c:64:19:64:19 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | -| test.c:66:21:66:21 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | -| test.c:67:21:67:22 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | -| test.c:68:21:68:21 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | -| test.c:70:21:70:21 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | -| test.c:72:14:72:14 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | -| test.c:73:14:73:15 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | -| test.c:74:14:74:14 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | -| test.c:75:14:75:14 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | -| test.c:80:7:80:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | -| test.c:81:7:81:7 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | -| test.c:82:7:82:7 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | -| test.c:83:7:83:7 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | -| test.c:86:7:86:7 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | -| test.c:88:7:88:7 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | -| test.c:89:7:89:7 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | -| test.c:90:7:90:7 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | -| test.c:93:7:93:7 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | -| test.c:94:7:94:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | -| test.c:96:7:96:7 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | -| test.c:97:7:97:7 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | -| test.c:100:7:100:7 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | -| test.c:101:7:101:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | -| test.c:102:7:102:7 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | -| test.c:104:7:104:7 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | -| test.c:107:7:107:7 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | -| test.c:108:7:108:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | -| test.c:109:7:109:7 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | -| test.c:110:7:110:7 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | -| test.c:118:7:118:8 | - ... | Assignment of essentially Signed type value to an object of essentially Unsigned type. | -| test.c:119:7:119:16 | 4294967296 | Assignment of essentially Signed type value to an object of essentially Unsigned type. | -| test.c:131:8:131:8 | A | Assignment of essentially Enum Type value to an object of essentially Boolean type. | -| test.c:132:8:132:10 | 100 | Assignment of essentially Signed type value to an object of essentially Boolean type. | -| test.c:133:23:133:25 | 200 | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | -| test.c:138:8:138:11 | 1 | Assignment of essentially Boolean type value to an object of essentially Enum Type. | -| test.c:140:8:140:10 | 100 | Assignment of essentially Signed type value to an object of essentially Enum Type. | -| test.c:141:23:141:25 | 200 | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | -| test.c:146:8:146:11 | 1 | Assignment of essentially Boolean type value to an object of essentially Signed type. | -| test.c:147:8:147:8 | A | Assignment of essentially Enum Type value to an object of essentially Signed type. | -| test.c:149:23:149:25 | 200 | Assignment of essentially Unsigned type value to an object of essentially Signed type. | -| test.c:154:8:154:11 | 1 | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | -| test.c:155:8:155:8 | A | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | -| test.c:174:8:174:8 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | -| test.c:175:8:175:8 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | -| test.c:176:8:176:8 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | -| test.c:177:8:177:8 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | -| test.c:180:8:180:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | -| test.c:182:8:182:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | -| test.c:183:8:183:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | -| test.c:184:8:184:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | -| test.c:187:8:187:8 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | -| test.c:188:8:188:8 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | -| test.c:190:8:190:8 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | -| test.c:191:8:191:8 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | -| test.c:194:8:194:8 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | -| test.c:195:8:195:8 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | -| test.c:196:8:196:8 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | -| test.c:198:8:198:8 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | -| test.c:201:8:201:8 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | -| test.c:202:8:202:8 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | -| test.c:203:8:203:8 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | -| test.c:204:8:204:8 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | -| test.c:220:12:220:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | -| test.c:222:12:222:12 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | -| test.c:224:12:224:12 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | -| test.c:226:12:226:12 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | -| test.c:239:12:239:12 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | -| test.c:243:12:243:12 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | -| test.c:245:12:245:12 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | -| test.c:247:12:247:12 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | -| test.c:260:12:260:12 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | -| test.c:262:12:262:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | -| test.c:266:12:266:12 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | -| test.c:268:12:268:12 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | -| test.c:281:12:281:12 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | -| test.c:283:12:283:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | -| test.c:285:12:285:12 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | -| test.c:289:12:289:12 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | -| test.c:302:12:302:12 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | -| test.c:304:12:304:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | -| test.c:306:12:306:12 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | -| test.c:308:12:308:12 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | -| test.c:332:10:332:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | -| test.c:333:10:333:10 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | -| test.c:334:10:334:10 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | -| test.c:335:10:335:10 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | -| test.c:337:11:337:11 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | -| test.c:339:11:339:11 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | -| test.c:340:11:340:11 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | -| test.c:341:11:341:11 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | -| test.c:343:10:343:10 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | -| test.c:344:10:344:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | -| test.c:346:10:346:10 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | -| test.c:347:10:347:10 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | -| test.c:349:10:349:10 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | -| test.c:350:10:350:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | -| test.c:351:10:351:10 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | -| test.c:353:10:353:10 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | -| test.c:355:10:355:10 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | -| test.c:356:10:356:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | -| test.c:357:10:357:10 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | -| test.c:358:10:358:10 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:13:7:13:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:14:7:14:7 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:15:7:15:7 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:16:7:16:7 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | +| test.c:17:7:17:8 | cf | Assignment of essentially Complex Floating type value to an object of essentially Boolean type. | +| test.c:19:8:19:8 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:21:8:21:8 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:22:8:22:8 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:23:8:23:8 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | +| test.c:24:8:24:9 | cf | Assignment of essentially Complex Floating type value to an object of essentially Enum Type. | +| test.c:26:7:26:7 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:27:7:27:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:29:7:29:7 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:30:7:30:7 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | +| test.c:31:7:31:8 | cf | Assignment of essentially Complex Floating type value to an object of essentially Signed type. | +| test.c:33:7:33:7 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:34:7:34:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:35:7:35:7 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:37:7:37:7 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | +| test.c:38:7:38:8 | cf | Assignment of essentially Complex Floating type value to an object of essentially Unsigned type. | +| test.c:40:7:40:7 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | +| test.c:41:7:41:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | +| test.c:42:7:42:7 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | +| test.c:43:7:43:7 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:45:7:45:8 | cf | Assignment of essentially Complex Floating type value to an object of essentially Floating type. | +| test.c:47:8:47:8 | b | Assignment of essentially Boolean type value to an object of essentially Complex Floating type. | +| test.c:48:8:48:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Complex Floating type. | +| test.c:49:8:49:8 | s | Assignment of essentially Signed type value to an object of essentially Complex Floating type. | +| test.c:50:8:50:8 | u | Assignment of essentially Unsigned type value to an object of essentially Complex Floating type. | +| test.c:64:14:64:15 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:65:14:65:14 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:66:14:66:14 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:67:14:67:14 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | +| test.c:68:15:68:16 | cf | Assignment of essentially Complex Floating type value to an object of essentially Boolean type. | +| test.c:70:17:70:17 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:72:17:72:17 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:73:17:73:17 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:74:17:74:17 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | +| test.c:75:18:75:19 | cf | Assignment of essentially Complex Floating type value to an object of essentially Enum Type. | +| test.c:77:19:77:19 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:78:19:78:20 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:80:19:80:19 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:81:19:81:19 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | +| test.c:82:20:82:21 | cf | Assignment of essentially Complex Floating type value to an object of essentially Signed type. | +| test.c:84:21:84:21 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:85:21:85:22 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:86:21:86:21 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:88:21:88:21 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | +| test.c:89:22:89:23 | cf | Assignment of essentially Complex Floating type value to an object of essentially Unsigned type. | +| test.c:91:14:91:14 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | +| test.c:92:14:92:15 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | +| test.c:93:14:93:14 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | +| test.c:94:14:94:14 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:96:15:96:16 | cf | Assignment of essentially Complex Floating type value to an object of essentially Floating type. | +| test.c:98:24:98:24 | b | Assignment of essentially Boolean type value to an object of essentially Complex Floating type. | +| test.c:99:24:99:25 | e1 | Assignment of essentially Enum Type value to an object of essentially Complex Floating type. | +| test.c:100:24:100:24 | s | Assignment of essentially Signed type value to an object of essentially Complex Floating type. | +| test.c:101:24:101:24 | u | Assignment of essentially Unsigned type value to an object of essentially Complex Floating type. | +| test.c:107:7:107:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:108:7:108:7 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:109:7:109:7 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:110:7:110:7 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | +| test.c:111:7:111:8 | cf | Assignment of essentially Complex Floating type value to an object of essentially Boolean type. | +| test.c:114:7:114:7 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:116:7:116:7 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:117:7:117:7 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:118:7:118:7 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | +| test.c:119:7:119:8 | cf | Assignment of essentially Complex Floating type value to an object of essentially Enum Type. | +| test.c:122:7:122:7 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:123:7:123:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:125:7:125:7 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:126:7:126:7 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | +| test.c:127:7:127:8 | cf | Assignment of essentially Complex Floating type value to an object of essentially Signed type. | +| test.c:130:7:130:7 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:131:7:131:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:132:7:132:7 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:134:7:134:7 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | +| test.c:135:7:135:8 | cf | Assignment of essentially Complex Floating type value to an object of essentially Unsigned type. | +| test.c:138:7:138:7 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | +| test.c:139:7:139:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | +| test.c:140:7:140:7 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | +| test.c:141:7:141:7 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:143:7:143:8 | cf | Assignment of essentially Complex Floating type value to an object of essentially Floating type. | +| test.c:146:7:146:7 | b | Assignment of essentially Boolean type value to an object of essentially Complex Floating type. | +| test.c:147:7:147:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Complex Floating type. | +| test.c:148:7:148:7 | s | Assignment of essentially Signed type value to an object of essentially Complex Floating type. | +| test.c:149:7:149:7 | u | Assignment of essentially Unsigned type value to an object of essentially Complex Floating type. | +| test.c:158:7:158:8 | - ... | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:159:7:159:16 | 4294967296 | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:171:8:171:8 | A | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:172:8:172:10 | 100 | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:173:23:173:25 | 200 | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:178:8:178:11 | 1 | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:180:8:180:10 | 100 | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:181:23:181:25 | 200 | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:186:8:186:11 | 1 | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:187:8:187:8 | A | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:189:23:189:25 | 200 | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:194:8:194:11 | 1 | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:195:8:195:8 | A | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:216:8:216:8 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:217:8:217:8 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:218:8:218:8 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:219:8:219:8 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | +| test.c:220:8:220:8 | b | Assignment of essentially Boolean type value to an object of essentially Complex Floating type. | +| test.c:223:8:223:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:225:8:225:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:226:8:226:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:227:8:227:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | +| test.c:228:8:228:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Complex Floating type. | +| test.c:231:8:231:8 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:232:8:232:8 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:234:8:234:8 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:235:8:235:8 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | +| test.c:236:8:236:8 | s | Assignment of essentially Signed type value to an object of essentially Complex Floating type. | +| test.c:239:8:239:8 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:240:8:240:8 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:241:8:241:8 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:243:8:243:8 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:244:8:244:8 | u | Assignment of essentially Unsigned type value to an object of essentially Complex Floating type. | +| test.c:247:8:247:8 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | +| test.c:248:8:248:8 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | +| test.c:249:8:249:8 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | +| test.c:250:8:250:8 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | +| test.c:255:8:255:9 | cf | Assignment of essentially Complex Floating type value to an object of essentially Boolean type. | +| test.c:256:8:256:9 | cf | Assignment of essentially Complex Floating type value to an object of essentially Enum Type. | +| test.c:257:8:257:9 | cf | Assignment of essentially Complex Floating type value to an object of essentially Signed type. | +| test.c:258:8:258:9 | cf | Assignment of essentially Complex Floating type value to an object of essentially Unsigned type. | +| test.c:259:8:259:9 | cf | Assignment of essentially Complex Floating type value to an object of essentially Floating type. | +| test.c:275:12:275:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:277:12:277:12 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:279:12:279:12 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:281:12:281:12 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | +| test.c:283:12:283:13 | cf | Assignment of essentially Complex Floating type value to an object of essentially Boolean type. | +| test.c:297:12:297:12 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:301:12:301:12 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:303:12:303:12 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:305:12:305:12 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | +| test.c:307:12:307:13 | cf | Assignment of essentially Complex Floating type value to an object of essentially Enum Type. | +| test.c:321:12:321:12 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:323:12:323:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:327:12:327:12 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:329:12:329:12 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | +| test.c:331:12:331:13 | cf | Assignment of essentially Complex Floating type value to an object of essentially Signed type. | +| test.c:345:12:345:12 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:347:12:347:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:349:12:349:12 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:353:12:353:12 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | +| test.c:355:12:355:13 | cf | Assignment of essentially Complex Floating type value to an object of essentially Unsigned type. | +| test.c:369:12:369:12 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | +| test.c:371:12:371:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | +| test.c:373:12:373:12 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | +| test.c:375:12:375:12 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:379:12:379:13 | cf | Assignment of essentially Complex Floating type value to an object of essentially Floating type. | +| test.c:393:12:393:12 | b | Assignment of essentially Boolean type value to an object of essentially Complex Floating type. | +| test.c:395:12:395:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Complex Floating type. | +| test.c:397:12:397:12 | s | Assignment of essentially Signed type value to an object of essentially Complex Floating type. | +| test.c:399:12:399:12 | u | Assignment of essentially Unsigned type value to an object of essentially Complex Floating type. | +| test.c:427:10:427:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:428:10:428:10 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:429:10:429:10 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:430:10:430:10 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | +| test.c:431:10:431:11 | cf | Assignment of essentially Complex Floating type value to an object of essentially Boolean type. | +| test.c:433:11:433:11 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:435:11:435:11 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:436:11:436:11 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:437:11:437:11 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | +| test.c:438:11:438:12 | cf | Assignment of essentially Complex Floating type value to an object of essentially Enum Type. | +| test.c:440:10:440:10 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:441:10:441:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:443:10:443:10 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:444:10:444:10 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | +| test.c:445:10:445:11 | cf | Assignment of essentially Complex Floating type value to an object of essentially Signed type. | +| test.c:447:10:447:10 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:448:10:448:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:449:10:449:10 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:451:10:451:10 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | +| test.c:452:10:452:11 | cf | Assignment of essentially Complex Floating type value to an object of essentially Unsigned type. | +| test.c:454:10:454:10 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | +| test.c:455:10:455:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | +| test.c:456:10:456:10 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | +| test.c:457:10:457:10 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:459:10:459:11 | cf | Assignment of essentially Complex Floating type value to an object of essentially Floating type. | +| test.c:461:11:461:11 | b | Assignment of essentially Boolean type value to an object of essentially Complex Floating type. | +| test.c:462:11:462:12 | e1 | Assignment of essentially Enum Type value to an object of essentially Complex Floating type. | +| test.c:463:11:463:11 | s | Assignment of essentially Signed type value to an object of essentially Complex Floating type. | +| test.c:464:11:464:11 | u | Assignment of essentially Unsigned type value to an object of essentially Complex Floating type. | +| test.c:473:26:473:28 | f64 | Assignment of essentially Floating type value to an object of essentially Complex Floating type. | +| test.c:490:12:490:20 | ... & ... | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:491:12:491:20 | ... \| ... | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:492:12:492:20 | ... ^ ... | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:497:20:497:27 | ... & ... | Assignment of value of essentially Signed type of size 2 bytes to an object narrower essential type of size 1 bytes. | +| test.c:502:23:502:30 | ... & ... | Assignment of value of essentially Unsigned type of size 2 bytes to an object narrower essential type of size 1 bytes. | +| test.c:505:22:505:29 | ... & ... | Assignment of essentially Signed type value to an object of essentially Unsigned type. | diff --git a/c/misra/test/rules/RULE-10-3/test.c b/c/misra/test/rules/RULE-10-3/test.c index 30ab2985ae..a5bfd3beaf 100644 --- a/c/misra/test/rules/RULE-10-3/test.c +++ b/c/misra/test/rules/RULE-10-3/test.c @@ -1,3 +1,4 @@ +#include #include void testAssignment() { @@ -6,36 +7,49 @@ void testAssignment() { signed int s = 100; // COMPLIANT unsigned int u = 100; // COMPLIANT - by exception 1 float f = 10.0f; // COMPLIANT + float _Complex cf = 10.0f; // COMPLIANT b = false; // COMPLIANT b = e1; // NON_COMPLIANT b = s; // NON_COMPLIANT b = u; // NON_COMPLIANT b = f; // NON_COMPLIANT + b = cf; // NON_COMPLIANT e1 = b; // NON_COMPLIANT e1 = e1; // COMPLIANT e1 = s; // NON_COMPLIANT e1 = u; // NON_COMPLIANT e1 = f; // NON_COMPLIANT + e1 = cf; // NON_COMPLIANT s = b; // NON_COMPLIANT s = e1; // NON_COMPLIANT s = s; // COMPLIANT s = u; // NON_COMPLIANT s = f; // NON_COMPLIANT + s = cf; // NON_COMPLIANT u = b; // NON_COMPLIANT u = e1; // NON_COMPLIANT u = s; // NON_COMPLIANT u = u; // COMPLIANT u = f; // NON_COMPLIANT + u = cf; // NON_COMPLIANT f = b; // NON_COMPLIANT f = e1; // NON_COMPLIANT f = s; // NON_COMPLIANT f = u; // NON_COMPLIANT f = f; // COMPLIANT + f = cf; // NON-COMPLIANT + + cf = b; // NON_COMPLIANT + cf = e1; // NON_COMPLIANT + cf = s; // NON_COMPLIANT + cf = u; // NON_COMPLIANT + cf = f; // COMPLIANT + cf = cf; // COMPLIANT } void testInitializers() { @@ -44,71 +58,97 @@ void testInitializers() { signed int s = 100; // COMPLIANT unsigned int u = 100; // COMPLIANT - by exception 1 float f = 10.0f; // COMPLIANT - - _Bool bb = b; // COMPLIANT - _Bool be = e1; // NON_COMPLIANT - _Bool bs = s; // NON_COMPLIANT - _Bool bu = u; // NON_COMPLIANT - _Bool bf = f; // NON_COMPLIANT - - enum E1 e1b = b; // NON_COMPLIANT - enum E1 e1e = e1; // COMPLIANT - enum E1 e1s = s; // NON_COMPLIANT - enum E1 e1u = u; // NON_COMPLIANT - enum E1 e1f = f; // NON_COMPLIANT - - signed int sb = b; // NON_COMPLIANT - signed int se = e1; // NON_COMPLIANT - signed int ss = s; // COMPLIANT - signed int su = u; // NON_COMPLIANT - signed int sf = f; // NON_COMPLIANT - - unsigned int ub = b; // NON_COMPLIANT - unsigned int ue = e1; // NON_COMPLIANT - unsigned int us = s; // NON_COMPLIANT - unsigned int uu = u; // COMPLIANT - unsigned int uf = f; // NON_COMPLIANT - - float fb = b; // NON_COMPLIANT - float fe = e1; // NON_COMPLIANT - float fs = s; // NON_COMPLIANT - float fu = u; // NON_COMPLIANT - float ff = f; // COMPLIANT - - _Bool ba[5] = { + float _Complex cf = 10.0f; // COMPLIANT + + _Bool bb = b; // COMPLIANT + _Bool be = e1; // NON_COMPLIANT + _Bool bs = s; // NON_COMPLIANT + _Bool bu = u; // NON_COMPLIANT + _Bool bf = f; // NON_COMPLIANT + _Bool bcf = cf; // NON_COMPLIANT + + enum E1 e1b = b; // NON_COMPLIANT + enum E1 e1e = e1; // COMPLIANT + enum E1 e1s = s; // NON_COMPLIANT + enum E1 e1u = u; // NON_COMPLIANT + enum E1 e1f = f; // NON_COMPLIANT + enum E1 e1cf = cf; // NON_COMPLIANT + + signed int sb = b; // NON_COMPLIANT + signed int se = e1; // NON_COMPLIANT + signed int ss = s; // COMPLIANT + signed int su = u; // NON_COMPLIANT + signed int sf = f; // NON_COMPLIANT + signed int scf = cf; // NON_COMPLIANT + + unsigned int ub = b; // NON_COMPLIANT + unsigned int ue = e1; // NON_COMPLIANT + unsigned int us = s; // NON_COMPLIANT + unsigned int uu = u; // COMPLIANT + unsigned int uf = f; // NON_COMPLIANT + unsigned int ucf = cf; // NON_COMPLIANT + + float fb = b; // NON_COMPLIANT + float fe = e1; // NON_COMPLIANT + float fs = s; // NON_COMPLIANT + float fu = u; // NON_COMPLIANT + float ff = f; // COMPLIANT + float fcf = cf; // NON-COMPLIANT + + float _Complex cfb = b; // NON_COMPLIANT + float _Complex cfe = e1; // NON_COMPLIANT + float _Complex cfs = s; // NON_COMPLIANT + float _Complex cfu = u; // NON_COMPLIANT + float _Complex cff = f; // COMPLIANT + float _Complex cfcf = cf; // COMPLIANT + + _Bool ba[6] = { b, // COMPLIANT e1, // NON_COMPLIANT s, // NON_COMPLIANT u, // NON_COMPLIANT - f // NON_COMPLIANT + f, // NON_COMPLIANT + cf // NON_COMPLIANT }; - enum E1 ea[5] = { + enum E1 ea[6] = { b, // NON_COMPLIANT e1, // COMPLIANT s, // NON_COMPLIANT u, // NON_COMPLIANT - f // NON_COMPLIANT + f, // NON_COMPLIANT + cf // NON_COMPLIANT }; - signed int sa[5] = { + signed int sa[6] = { b, // NON_COMPLIANT e1, // NON_COMPLIANT s, // COMPLIANT u, // NON_COMPLIANT - f // NON_COMPLIANT + f, // NON_COMPLIANT + cf // NON_COMPLIANT }; - unsigned int ua[5] = { + unsigned int ua[6] = { b, // NON_COMPLIANT e1, // NON_COMPLIANT s, // NON_COMPLIANT u, // COMPLIANT - f // NON_COMPLIANT + f, // NON_COMPLIANT + cf // NON_COMPLIANT + }; + float fa[6] = { + b, // NON_COMPLIANT + e1, // NON_COMPLIANT + s, // NON_COMPLIANT + u, // NON_COMPLIANT + f, // COMPLIANT + cf // NON_COMPLIANT }; - float fa[5] = { + float _Complex cfa[6] = { b, // NON_COMPLIANT e1, // NON_COMPLIANT s, // NON_COMPLIANT u, // NON_COMPLIANT - f // COMPLIANT + f, // COMPLIANT + cf // COMPLIANT }; } @@ -161,19 +201,22 @@ void testSwitchCase() { enum EG { EGA, EGB, EGC }; -void func(_Bool b, enum EG eg, signed int i, unsigned int u, float f); +void func(_Bool b, enum EG eg, signed int i, unsigned int u, float f, + float _Complex cf); void testFunctionCall() { - _Bool b = true; // COMPLIANT - enum EG e1 = EGA; // COMPLIANT - signed int s = 100; // COMPLIANT - unsigned int u = 100; // COMPLIANT - by exception 1 - float f = 10.0f; // COMPLIANT + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + float _Complex cf = 10.0f; // COMPLIANT func(b, // COMPLIANT b, // NON_COMPLIANT b, // NON_COMPLIANT b, // NON_COMPLIANT + b, // NON_COMPLIANT b // NON_COMPLIANT ); @@ -181,6 +224,7 @@ void testFunctionCall() { e1, // COMPLIANT e1, // NON_COMPLIANT e1, // NON_COMPLIANT + e1, // NON_COMPLIANT e1 // NON_COMPLIANT ); @@ -188,6 +232,7 @@ void testFunctionCall() { s, // NON_COMPLIANT s, // COMPLIANT s, // NON_COMPLIANT + s, // NON_COMPLIANT s // NON_COMPLIANT ); @@ -195,6 +240,7 @@ void testFunctionCall() { u, // NON_COMPLIANT u, // NON_COMPLIANT u, // COMPLIANT + u, // NON_COMPLIANT u // NON_COMPLIANT ); @@ -202,16 +248,25 @@ void testFunctionCall() { f, // NON_COMPLIANT f, // NON_COMPLIANT f, // NON_COMPLIANT + f, // COMPLIANT f // COMPLIANT ); + + func(cf, // NON_COMPLIANT + cf, // NON_COMPLIANT + cf, // NON_COMPLIANT + cf, // NON_COMPLIANT + cf, // NON_COMPLIANT + cf); } _Bool testBoolFunctionReturn(int x) { - _Bool b = true; // COMPLIANT - enum EG e1 = EGA; // COMPLIANT - signed int s = 100; // COMPLIANT - unsigned int u = 100; // COMPLIANT - by exception 1 - float f = 10.0f; // COMPLIANT + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + float _Complex cf = 10.0f; // COMPLIANT switch (x) { case 0: @@ -222,17 +277,20 @@ _Bool testBoolFunctionReturn(int x) { return s; // NON_COMPLIANT case 3: return u; // NON_COMPLIANT - default: + case 4: return f; // NON_COMPLIANT + default: + return cf; // NON_COMPLIANT } } enum EG testEnumFunctionReturn(int x) { - _Bool b = true; // COMPLIANT - enum EG e1 = EGA; // COMPLIANT - signed int s = 100; // COMPLIANT - unsigned int u = 100; // COMPLIANT - by exception 1 - float f = 10.0f; // COMPLIANT + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + float _Complex cf = 10.0f; // COMPLIANT switch (x) { case 0: @@ -243,17 +301,20 @@ enum EG testEnumFunctionReturn(int x) { return s; // NON_COMPLIANT case 3: return u; // NON_COMPLIANT - default: + case 4: return f; // NON_COMPLIANT + default: + return cf; // NON_COMPLIANT } } signed int testSignedIntFunctionReturn(int x) { - _Bool b = true; // COMPLIANT - enum EG e1 = EGA; // COMPLIANT - signed int s = 100; // COMPLIANT - unsigned int u = 100; // COMPLIANT - by exception 1 - float f = 10.0f; // COMPLIANT + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + float _Complex cf = 10.0f; // COMPLIANT switch (x) { case 0: @@ -264,17 +325,20 @@ signed int testSignedIntFunctionReturn(int x) { return s; // COMPLIANT case 3: return u; // NON_COMPLIANT - default: + case 4: return f; // NON_COMPLIANT + default: + return cf; // NON_COMPLIANT } } unsigned int testUnsignedIntFunctionReturn(int x) { - _Bool b = true; // COMPLIANT - enum EG e1 = EGA; // COMPLIANT - signed int s = 100; // COMPLIANT - unsigned int u = 100; // COMPLIANT - by exception 1 - float f = 10.0f; // COMPLIANT + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + float _Complex cf = 10.0f; // COMPLIANT switch (x) { case 0: @@ -285,17 +349,20 @@ unsigned int testUnsignedIntFunctionReturn(int x) { return s; // NON_COMPLIANT case 3: return u; // COMPLIANT - default: + case 4: return f; // NON_COMPLIANT + default: + return cf; // NON_COMPLIANT } } float testFloatFunctionReturn(int x) { - _Bool b = true; // COMPLIANT - enum EG e1 = EGA; // COMPLIANT - signed int s = 100; // COMPLIANT - unsigned int u = 100; // COMPLIANT - by exception 1 - float f = 10.0f; // COMPLIANT + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + float _Complex cf = 10.0f; // COMPLIANT switch (x) { case 0: @@ -306,8 +373,34 @@ float testFloatFunctionReturn(int x) { return s; // NON_COMPLIANT case 3: return u; // NON_COMPLIANT + case 4: + return f; // COMPLIANT default: + return cf; // NON_COMPLIANT + } +} + +float _Complex testComplexFunctionReturn(int x) { + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + float _Complex cf = 10.0f; // COMPLIANT + + switch (x) { + case 0: + return b; // NON_COMPLIANT + case 1: + return e1; // NON_COMPLIANT + case 2: + return s; // NON_COMPLIANT + case 3: + return u; // NON_COMPLIANT + case 4: return f; // COMPLIANT + default: + return cf; // COMPLIANT } } @@ -317,14 +410,16 @@ struct S1 { signed int s; unsigned int u; float f; + float _Complex cf; }; void testStructAssignment() { - _Bool b = true; // COMPLIANT - enum EG e1 = EGA; // COMPLIANT - signed int s = 100; // COMPLIANT - unsigned int u = 100; // COMPLIANT - by exception 1 - float f = 10.0f; // COMPLIANT + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + float _Complex cf = 10.0f; // COMPLIANT struct S1 s1; @@ -333,28 +428,79 @@ void testStructAssignment() { s1.b = s; // NON_COMPLIANT s1.b = u; // NON_COMPLIANT s1.b = f; // NON_COMPLIANT + s1.b = cf; // NON_COMPLIANT s1.e1 = b; // NON_COMPLIANT s1.e1 = e1; // COMPLIANT s1.e1 = s; // NON_COMPLIANT s1.e1 = u; // NON_COMPLIANT s1.e1 = f; // NON_COMPLIANT + s1.e1 = cf; // NON_COMPLIANT s1.s = b; // NON_COMPLIANT s1.s = e1; // NON_COMPLIANT s1.s = s; // COMPLIANT s1.s = u; // NON_COMPLIANT s1.s = f; // NON_COMPLIANT + s1.s = cf; // NON_COMPLIANT s1.u = b; // NON_COMPLIANT s1.u = e1; // NON_COMPLIANT s1.u = s; // NON_COMPLIANT s1.u = u; // COMPLIANT s1.u = f; // NON_COMPLIANT + s1.u = cf; // NON_COMPLIANT s1.f = b; // NON_COMPLIANT s1.f = e1; // NON_COMPLIANT s1.f = s; // NON_COMPLIANT s1.f = u; // NON_COMPLIANT s1.f = f; // COMPLIANT + s1.f = cf; // NON_COMPLIANT + + s1.cf = b; // NON_COMPLIANT + s1.cf = e1; // NON_COMPLIANT + s1.cf = s; // NON_COMPLIANT + s1.cf = u; // NON_COMPLIANT + s1.cf = f; // COMPLIANT + s1.cf = cf; // COMPLIANT +} + +void testException4() { + float f32 = 10.0f; // COMPLIANT + double f64 = 10.0f; // COMPLIANT + float _Complex cf32a = f32; // COMPLIANT + float _Complex cf32b = f64; // NON_COMPLIANT + double _Complex cf64a = f32; // COMPLIANT + double _Complex cf64b = f64; // COMPLIANT + + double _Complex f64byparts_a = 10.0i; // COMPLIANT + double _Complex f64byparts_b = 10.0 * I; // COMPLIANT + double _Complex f64byparts_c = 10.0f + 10.0i; // COMPLIANT + double _Complex f64byparts_d = 10.0f + 10.0f * I; // COMPLIANT +} + +void testBinaryBitwise() { + signed int s32 = 100; // COMPLIANT - wider + signed short s16 = 0; // COMPLIANT - wider + signed char s8 = 0; // COMPLIANT - wider + unsigned int u32 = 100; // COMPLIANT - by exception 1 + unsigned char u8 = 0; // COMPLIANT - by exception 1 + unsigned short u16 = 0; // COMPLIANT - by exception 1 + int x1 = s32 & u32; // NON_COMPLIANT - integer promotion to u32 + int x2 = s32 | u32; // NON_COMPLIANT - integer promotion to u32 + int x3 = s32 ^ u32; // NON_COMPLIANT - integer promotion to u32 + int x4 = s16 & s32; // COMPLIANT + int x5 = s16 & u16; // COMPLIANT + int x6 = s16 & s8; // COMPLIANT + signed short x7 = s16 & s8; // COMPLIANT + signed char x8 = s16 & s8; // NON_COMPLIANT + signed char x9 = s8 & s8; // COMPLIANT + signed short x10 = s8 & s8; // COMPLIANT + unsigned int x11 = u16 & u8; // COMPLIANT + unsigned short x12 = u16 & u8; // COMPLIANT + unsigned char x13 = u16 & u8; // NON_COMPLIANT + unsigned char x14 = u8 & u8; // COMPLIANT + unsigned short x15 = u8 & u8; // COMPLIANT + unsigned int x16 = s16 & s8; // NON_COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.expected b/c/misra/test/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.expected index 333c3ad581..c85f2a447e 100644 --- a/c/misra/test/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.expected +++ b/c/misra/test/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.expected @@ -1,10 +1,13 @@ -| test.c:14:3:14:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Unsigned type, right operand: essentially Signed type). | -| test.c:15:3:15:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Unsigned type). | -| test.c:16:3:16:10 | ... += ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Unsigned type). | -| test.c:17:3:17:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Floating type, right operand: essentially Signed type). | -| test.c:18:3:18:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Floating type). | -| test.c:19:3:19:10 | ... += ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Floating type). | -| test.c:27:3:27:9 | ... - ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Character type). | -| test.c:28:3:28:10 | ... -= ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Character type). | -| test.c:34:3:34:11 | ... < ... | The operands of this operator with usual arithmetic conversions have mismatched essentially Enum types (left operand: E1, right operand: E2). | -| test.c:35:3:35:7 | ... < ... | The operands of this operator with usual arithmetic conversions have mismatched essentially Enum types (left operand: E1, right operand: E2). | +| test.c:15:3:15:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Unsigned type, right operand: essentially Signed type). | +| test.c:16:3:16:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Unsigned type). | +| test.c:17:3:17:10 | ... += ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Unsigned type). | +| test.c:18:3:18:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Floating type, right operand: essentially Signed type). | +| test.c:19:3:19:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Floating type). | +| test.c:20:3:20:10 | ... += ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Floating type). | +| test.c:21:3:21:10 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Complex Floating type, right operand: essentially Signed type). | +| test.c:22:3:22:10 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Complex Floating type). | +| test.c:23:3:23:11 | ... += ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Complex Floating type). | +| test.c:31:3:31:9 | ... - ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Character type). | +| test.c:32:3:32:10 | ... -= ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Character type). | +| test.c:43:3:43:11 | ... < ... | The operands of this operator with usual arithmetic conversions have mismatched essentially Enum types (left operand: E1, right operand: E2). | +| test.c:44:3:44:7 | ... < ... | The operands of this operator with usual arithmetic conversions have mismatched essentially Enum types (left operand: E1, right operand: E2). | diff --git a/c/misra/test/rules/RULE-10-4/test.c b/c/misra/test/rules/RULE-10-4/test.c index 666590a2d5..223aacbdad 100644 --- a/c/misra/test/rules/RULE-10-4/test.c +++ b/c/misra/test/rules/RULE-10-4/test.c @@ -3,6 +3,7 @@ void testOps() { signed long long s64 = 100; unsigned int u = 100; float f = 10.0f; + float _Complex cf = 10.0f; char c = 'A'; s32 + s32; // COMPLIANT @@ -17,6 +18,9 @@ void testOps() { f + s32; // NON_COMPLIANT s32 + f; // NON_COMPLIANT s32 += f; // NON_COMPLIANT + cf + s32; // NON_COMPLIANT + s32 + cf; // NON_COMPLIANT + s32 += cf; // NON_COMPLIANT c + s32; // COMPLIANT - by exception c += s32; // COMPLIANT - by exception @@ -27,10 +31,24 @@ void testOps() { s32 - c; // NON_COMPLIANT s32 -= c; // NON_COMPLIANT + cf + f; // COMPLIANT - by exception + f + cf; // COMPLIANT - by exception + cf *f; // COMPLIANT - by exception + f *cf; // COMPLIANT - by exception + enum E1 { A, B, C } e1a; enum E2 { D, E, F } e2a; e1a < e1a; // COMPLIANT A < A; // COMPLIANT e1a < e2a; // NON_COMPLIANT A < D; // NON_COMPLIANT + + enum { G }; + s32 + G; // COMPLIANT + c == '\n'; // COMPLIANT + + typedef enum { H } E3; + + E3 e3a = H; + e3a < H; // COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-10-5/InappropriateEssentialTypeCast.expected b/c/misra/test/rules/RULE-10-5/InappropriateEssentialTypeCast.expected index 731ad9f312..2f4c38eb95 100644 --- a/c/misra/test/rules/RULE-10-5/InappropriateEssentialTypeCast.expected +++ b/c/misra/test/rules/RULE-10-5/InappropriateEssentialTypeCast.expected @@ -1,20 +1,25 @@ -| test.c:9:3:9:9 | (char)... | Incompatible cast from essentially Boolean type to essentially Character type. | -| test.c:10:3:10:13 | (E1)... | Incompatible cast from essentially Boolean type to essentially Enum Type. | -| test.c:11:3:11:15 | (signed int)... | Incompatible cast from essentially Boolean type to essentially Signed type. | -| test.c:12:3:12:17 | (unsigned int)... | Incompatible cast from essentially Boolean type to essentially Unsigned type. | -| test.c:13:3:13:10 | (float)... | Incompatible cast from essentially Boolean type to essentially Floating type. | -| test.c:16:3:16:11 | (bool)... | Incompatible cast from essentially Character type to essentially Boolean type. | -| test.c:18:3:18:13 | (E1)... | Incompatible cast from essentially Character type to essentially Enum Type. | -| test.c:21:3:21:10 | (float)... | Incompatible cast from essentially Character type to essentially Floating type. | -| test.c:24:3:24:11 | (bool)... | Incompatible cast from essentially Enum Type to essentially Boolean type. | -| test.c:26:3:26:13 | (E1)... | Incompatible cast from E2 to E1. | -| test.c:33:3:33:11 | (bool)... | Incompatible cast from essentially Signed type to essentially Boolean type. | -| test.c:35:3:35:13 | (E1)... | Incompatible cast from essentially Signed type to essentially Enum Type. | -| test.c:41:3:41:11 | (bool)... | Incompatible cast from essentially Unsigned type to essentially Boolean type. | -| test.c:43:3:43:13 | (E1)... | Incompatible cast from essentially Unsigned type to essentially Enum Type. | -| test.c:49:3:49:11 | (bool)... | Incompatible cast from essentially Floating type to essentially Boolean type. | -| test.c:50:3:50:9 | (char)... | Incompatible cast from essentially Floating type to essentially Character type. | -| test.c:51:3:51:13 | (E1)... | Incompatible cast from essentially Floating type to essentially Enum Type. | -| test.c:68:3:68:10 | (bool)... | Incompatible cast from essentially Signed type to essentially Boolean type. | -| test.c:72:3:72:16 | (MyBool)... | Incompatible cast from essentially Signed type to essentially Boolean type. | -| test.c:76:3:76:12 | (boolean)... | Incompatible cast from essentially Signed type to essentially Boolean type. | +| test.c:10:3:10:9 | (char)... | Incompatible cast from essentially Boolean type to essentially Character type. | +| test.c:11:3:11:13 | (E1)... | Incompatible cast from essentially Boolean type to essentially Enum Type. | +| test.c:12:3:12:15 | (signed int)... | Incompatible cast from essentially Boolean type to essentially Signed type. | +| test.c:13:3:13:17 | (unsigned int)... | Incompatible cast from essentially Boolean type to essentially Unsigned type. | +| test.c:14:3:14:10 | (float)... | Incompatible cast from essentially Boolean type to essentially Floating type. | +| test.c:15:3:15:20 | (_Complex float)... | Incompatible cast from essentially Boolean type to essentially Complex Floating type. | +| test.c:18:3:18:11 | (bool)... | Incompatible cast from essentially Character type to essentially Boolean type. | +| test.c:20:3:20:13 | (E1)... | Incompatible cast from essentially Character type to essentially Enum Type. | +| test.c:23:3:23:10 | (float)... | Incompatible cast from essentially Character type to essentially Floating type. | +| test.c:24:3:24:20 | (_Complex float)... | Incompatible cast from essentially Character type to essentially Complex Floating type. | +| test.c:27:3:27:11 | (bool)... | Incompatible cast from essentially Enum Type to essentially Boolean type. | +| test.c:29:3:29:13 | (E1)... | Incompatible cast from E2 to E1. | +| test.c:37:3:37:11 | (bool)... | Incompatible cast from essentially Signed type to essentially Boolean type. | +| test.c:39:3:39:13 | (E1)... | Incompatible cast from essentially Signed type to essentially Enum Type. | +| test.c:46:3:46:11 | (bool)... | Incompatible cast from essentially Unsigned type to essentially Boolean type. | +| test.c:48:3:48:13 | (E1)... | Incompatible cast from essentially Unsigned type to essentially Enum Type. | +| test.c:55:3:55:11 | (bool)... | Incompatible cast from essentially Floating type to essentially Boolean type. | +| test.c:56:3:56:9 | (char)... | Incompatible cast from essentially Floating type to essentially Character type. | +| test.c:57:3:57:13 | (E1)... | Incompatible cast from essentially Floating type to essentially Enum Type. | +| test.c:64:3:64:12 | (bool)... | Incompatible cast from essentially Complex Floating type to essentially Boolean type. | +| test.c:65:3:65:10 | (char)... | Incompatible cast from essentially Complex Floating type to essentially Character type. | +| test.c:66:3:66:14 | (E1)... | Incompatible cast from essentially Complex Floating type to essentially Enum Type. | +| test.c:84:3:84:10 | (bool)... | Incompatible cast from essentially Signed type to essentially Boolean type. | +| test.c:88:3:88:16 | (MyBool)... | Incompatible cast from essentially Signed type to essentially Boolean type. | +| test.c:92:3:92:12 | (boolean)... | Incompatible cast from essentially Signed type to essentially Boolean type. | diff --git a/c/misra/test/rules/RULE-10-5/test.c b/c/misra/test/rules/RULE-10-5/test.c index dbc5939f0f..d7a6d878f1 100644 --- a/c/misra/test/rules/RULE-10-5/test.c +++ b/c/misra/test/rules/RULE-10-5/test.c @@ -1,3 +1,4 @@ +#include #include void testIncompatibleCasts() { @@ -5,53 +6,68 @@ void testIncompatibleCasts() { _Bool b = true; - (_Bool) b; // COMPLIANT - (char)b; // NON_COMPLIANT - (enum E1) b; // NON_COMPLIANT - (signed int)b; // NON_COMPLIANT - (unsigned int)b; // NON_COMPLIANT - (float)b; // NON_COMPLIANT + (_Bool) b; // COMPLIANT + (char)b; // NON_COMPLIANT + (enum E1) b; // NON_COMPLIANT + (signed int)b; // NON_COMPLIANT + (unsigned int)b; // NON_COMPLIANT + (float)b; // NON_COMPLIANT + (float _Complex) b; // NON_COMPLIANT char c = 100; - (_Bool) c; // NON_COMPLIANT - (char)c; // COMPLIANT - (enum E1) c; // NON_COMPLIANT - (signed int)c; // COMPLIANT - (unsigned int)c; // COMPLIANT - (float)c; // NON_COMPLIANT + (_Bool) c; // NON_COMPLIANT + (char)c; // COMPLIANT + (enum E1) c; // NON_COMPLIANT + (signed int)c; // COMPLIANT + (unsigned int)c; // COMPLIANT + (float)c; // NON_COMPLIANT + (float _Complex) c; // NON_COMPLIANT enum E2 { C, D } e = C; - (_Bool) e; // NON_COMPLIANT - (char)e; // COMPLIANT - (enum E1) e; // NON_COMPLIANT - (enum E2) e; // COMPLIANT - (signed int)e; // COMPLIANT - (unsigned int)e; // COMPLIANT - (float)e; // COMPLIANT + (_Bool) e; // NON_COMPLIANT + (char)e; // COMPLIANT + (enum E1) e; // NON_COMPLIANT + (enum E2) e; // COMPLIANT + (signed int)e; // COMPLIANT + (unsigned int)e; // COMPLIANT + (float)e; // COMPLIANT + (float _Complex) e; // COMPLIANT signed int i = 100; - (_Bool) i; // NON_COMPLIANT - (char)i; // COMPLIANT - (enum E1) i; // NON_COMPLIANT - (signed int)i; // COMPLIANT - (unsigned int)i; // COMPLIANT - (float)i; // COMPLIANT + (_Bool) i; // NON_COMPLIANT + (char)i; // COMPLIANT + (enum E1) i; // NON_COMPLIANT + (signed int)i; // COMPLIANT + (unsigned int)i; // COMPLIANT + (float)i; // COMPLIANT + (float _Complex) i; // COMPLIANT unsigned int u = 100; - (_Bool) u; // NON_COMPLIANT - (char)u; // COMPLIANT - (enum E1) u; // NON_COMPLIANT - (signed int)u; // COMPLIANT - (unsigned int)u; // COMPLIANT - (float)u; // COMPLIANT + (_Bool) u; // NON_COMPLIANT + (char)u; // COMPLIANT + (enum E1) u; // NON_COMPLIANT + (signed int)u; // COMPLIANT + (unsigned int)u; // COMPLIANT + (float)u; // COMPLIANT + (float _Complex) u; // COMPLIANT float f = 100.0; - (_Bool) f; // NON_COMPLIANT - (char)f; // NON_COMPLIANT - (enum E1) f; // NON_COMPLIANT - (signed int)f; // COMPLIANT - (unsigned int)f; // COMPLIANT - (float)f; // COMPLIANT + (_Bool) f; // NON_COMPLIANT + (char)f; // NON_COMPLIANT + (enum E1) f; // NON_COMPLIANT + (signed int)f; // COMPLIANT + (unsigned int)f; // COMPLIANT + (float)f; // COMPLIANT + (float _Complex) f; // COMPLIANT + + float _Complex cf = 100.0; + (_Bool) cf; // NON_COMPLIANT + (char)cf; // NON_COMPLIANT + (enum E1) cf; // NON_COMPLIANT + (signed int)cf; // COMPLIANT + (unsigned int)cf; // COMPLIANT + (float)cf; // COMPLIANT + (float _Complex) cf; // COMPLIANT } void testImplicit() { diff --git a/c/misra/test/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.expected b/c/misra/test/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.expected index 30b5e1efb7..ea8fc433b1 100644 --- a/c/misra/test/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.expected +++ b/c/misra/test/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.expected @@ -1,3 +1,7 @@ | test.c:5:3:5:16 | ... + ... | Implicit conversion of $@ from unsigned short to unsigned int | test.c:5:9:5:16 | ... * ... | composite op | | test.c:6:3:6:18 | ... * ... | Implicit conversion of $@ from unsigned short to unsigned int | test.c:6:9:6:17 | ... + ... | composite op | | test.c:9:3:9:20 | ... += ... | Implicit conversion of $@ from unsigned short to unsigned int | test.c:9:11:9:19 | ... + ... | composite op | +| test.c:24:3:24:19 | ... + ... | Implicit conversion of $@ from float to double | test.c:24:10:24:18 | ... + ... | composite op | +| test.c:25:3:25:21 | ... + ... | Implicit conversion of $@ from _Complex float to double | test.c:25:10:25:20 | ... + ... | composite op | +| test.c:26:3:26:20 | ... + ... | Implicit conversion of $@ from float to _Complex double | test.c:26:11:26:19 | ... + ... | composite op | +| test.c:27:3:27:22 | ... + ... | Implicit conversion of $@ from _Complex float to _Complex double | test.c:27:11:27:21 | ... + ... | composite op | diff --git a/c/misra/test/rules/RULE-10-7/test.c b/c/misra/test/rules/RULE-10-7/test.c index 59d0ed1437..7aaa1847e4 100644 --- a/c/misra/test/rules/RULE-10-7/test.c +++ b/c/misra/test/rules/RULE-10-7/test.c @@ -11,4 +11,18 @@ void testComposite() { signed int s32 = 100; s32 += (u16 + u16); // // ignored - prohibited by Rule 10.4 + + float f32 = 10.0f; + double f64 = 10.0f; + float _Complex cf32 = 10.0f; + double _Complex cf64 = 10.0f; + + f32 + (f32 + f32); // COMPLIANT + cf32 + (cf32 + cf32); // COMPLIANT + f32 + (cf32 + cf32); // COMPLIANT + cf32 + (f32 + f32); // COMPLIANT + f64 + (f32 + f32); // NON_COMPLIANT + f64 + (cf32 + cf32); // NON_COMPLIANT + cf64 + (f32 + f32); // NON_COMPLIANT + cf64 + (cf32 + cf32); // NON_COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-10-8/InappropriateCastOfCompositeExpression.expected b/c/misra/test/rules/RULE-10-8/InappropriateCastOfCompositeExpression.expected index 85e2471a41..659b41199d 100644 --- a/c/misra/test/rules/RULE-10-8/InappropriateCastOfCompositeExpression.expected +++ b/c/misra/test/rules/RULE-10-8/InappropriateCastOfCompositeExpression.expected @@ -1,4 +1,10 @@ | test.c:4:16:4:20 | ... + ... | Cast from essentially Unsigned type to essentially Signed type changes type category. | | test.c:5:18:5:22 | ... + ... | Cast from essentially Signed type to essentially Unsigned type changes type category. | -| test.c:14:18:14:24 | ... + ... | Cast from essentially Unsigned type to essentially Unsigned type widens type. | -| test.c:20:16:20:22 | ... + ... | Cast from essentially Signed type to essentially Signed type widens type. | +| test.c:11:11:11:15 | ... + ... | Cast from essentially Unsigned type to essentially Floating type changes type category. | +| test.c:12:20:12:24 | ... + ... | Cast from essentially Unsigned type to essentially Complex Floating type changes type category. | +| test.c:13:18:13:22 | ... + ... | Cast from essentially Floating type to essentially Unsigned type changes type category. | +| test.c:14:18:14:24 | ... + ... | Cast from essentially Complex Floating type to essentially Unsigned type changes type category. | +| test.c:25:18:25:24 | ... + ... | Cast from essentially Unsigned type to essentially Unsigned type widens type. | +| test.c:31:16:31:22 | ... + ... | Cast from essentially Signed type to essentially Signed type widens type. | +| test.c:43:12:43:20 | ... + ... | Cast from essentially Floating type to essentially Floating type widens type. | +| test.c:44:12:44:22 | ... + ... | Cast from essentially Complex Floating type to essentially Floating type widens type. | diff --git a/c/misra/test/rules/RULE-10-8/test.c b/c/misra/test/rules/RULE-10-8/test.c index 41efb6b8d8..31294ed550 100644 --- a/c/misra/test/rules/RULE-10-8/test.c +++ b/c/misra/test/rules/RULE-10-8/test.c @@ -5,6 +5,17 @@ void testDifferentEssentialType() { (unsigned int)(s + s); // NON_COMPLIANT (signed int)(s + s); // COMPLIANT (unsigned int)(u + u); // COMPLIANT + + float f = 1.0; + float _Complex cf = 1.0; + (float)(u + u); // NON_COMPLIANT + (float _Complex)(u + u); // NON_COMPLIANT + (unsigned int)(f + f); // NON_COMPLIANT + (unsigned int)(cf + cf); // NON_COMPLIANT + (float)(f + f); // COMPLIANT + (float)(cf + cf); // COMPLIANT + (float _Complex)(f + f); // COMPLIANT + (float _Complex)(cf + cf); // COMPLIANT } void testWiderType() { @@ -19,4 +30,18 @@ void testWiderType() { (signed int)(ss + ss); // NON_COMPLIANT (signed short)(s + s); // COMPLIANT + + float f32 = 1.0; + double f64 = 1.0; + float _Complex cf32 = 1.0; + double _Complex cf64 = 1.0; + + (float)(f32 + f32); // COMPLIANT + (float)(cf32 + cf32); // COMPLIANT + (float _Complex)(f32 + f32); // COMPLIANT + (float _Complex)(cf32 + cf32); // COMPLIANT + (double)(f32 + f32); // NON_COMPLIANT + (double)(cf32 + cf32); // NON_COMPLIANT + (double _Complex)(f64 + f64); // COMPLIANT + (double _Complex)(cf64 + cf64); // COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.expected b/c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.expected index ebe2c74742..0144180616 100644 --- a/c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.expected +++ b/c/misra/test/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.expected @@ -1,7 +1,6 @@ | test.c:11:8:11:16 | (fp1 *)... | Cast performed between a function pointer and another type. | | test.c:11:8:11:16 | (fp1)... | Cast performed between a function pointer and another type. | | test.c:12:14:12:23 | (void *)... | Cast performed between a function pointer and another type. | -| test.c:14:8:14:15 | (fp2)... | Cast performed between a function pointer and another type. | | test.c:15:8:15:15 | (fp2)... | Cast performed between a function pointer and another type. | | test.c:22:12:22:13 | (fp1)... | Cast performed between a function pointer and another type. | | test.c:25:8:25:9 | (fp1)... | Cast performed between a function pointer and another type. | diff --git a/c/misra/test/rules/RULE-11-1/test.c b/c/misra/test/rules/RULE-11-1/test.c index 858c6e68a9..4fcabb0599 100644 --- a/c/misra/test/rules/RULE-11-1/test.c +++ b/c/misra/test/rules/RULE-11-1/test.c @@ -11,7 +11,7 @@ void f1(void) { v1 = (fp1 *)v2; // NON_COMPLIANT void *v3 = (void *)v1; // NON_COMPLIANT - v2 = (fp2 *)0; // NON_COMPLIANT + v2 = (fp2 *)0; // COMPLIANT - null pointer constant v2 = (fp2 *)1; // NON_COMPLIANT pfp2 v4; diff --git a/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.expected b/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.expected new file mode 100644 index 0000000000..d38aac6455 --- /dev/null +++ b/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.expected @@ -0,0 +1,8 @@ +| test.c:3:15:3:16 | definition of g3 | g3 declared with an atomic void type. | +| test.c:10:17:10:18 | definition of m3 | m3 declared with an atomic void type. | +| test.c:15:22:15:23 | definition of p2 | p2 declared with an atomic void type. | +| test.c:20:23:20:24 | declaration of f2 | f2 declared with an atomic void type. | +| test.c:21:25:21:26 | declaration of f3 | f3 declared with an atomic void type. | +| test.c:22:14:22:15 | declaration of f4 | f4 declared with an atomic void type. | +| test.c:23:16:23:17 | declaration of f5 | f5 declared with an atomic void type. | +| test.c:27:3:27:19 | (_Atomic(void) *)... | Cast declared with an atomic void type. | diff --git a/c/misra/test/rules/RULE-7-3/cpp/LowercaseCharacterLUsedInLiteralSuffix.expected b/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.expected.clang similarity index 100% rename from c/misra/test/rules/RULE-7-3/cpp/LowercaseCharacterLUsedInLiteralSuffix.expected rename to c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.expected.clang diff --git a/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.qlref b/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.qlref new file mode 100644 index 0000000000..2046575237 --- /dev/null +++ b/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.qlref @@ -0,0 +1 @@ +rules/RULE-11-10/AtomicQualifierAppliedToVoid.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-10/test.c b/c/misra/test/rules/RULE-11-10/test.c new file mode 100644 index 0000000000..8f8e837b66 --- /dev/null +++ b/c/misra/test/rules/RULE-11-10/test.c @@ -0,0 +1,28 @@ +// _Atomic void g1; // doesn't compile +_Atomic int g2; // COMPLIANT +_Atomic void *g3; // NON_COMPLIANT +// _Atomic void g4[]; // doesn't compile +void *_Atomic g5; // COMPLIANT + +struct { + _Atomic int m1; // COMPLIANT + // _Atomic void m2; // doesn't compile + _Atomic void *m3; // NON_COMPLIANT + void *_Atomic m4; // COMPLIANT +} s1; + +void f(_Atomic int p1, // COMPLIANT + _Atomic void *p2 // NON_COMPLIANT + // _Atomic void p3[] // doesn't compile, even though it perhaps should as + // it is adjusted to void*. +) {} + +typedef _Atomic void *f2(void); // NON_COMPLIANT +typedef _Atomic void *(*f3)(void); // NON_COMPLIANT +typedef void f4(_Atomic void *); // NON_COMPLIANT +typedef void (*f5)(_Atomic void *); // NON_COMPLIANT + +void f6() { + (void *)0; // COMPLIANT + (_Atomic void *)0; // NON_COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-10/test.c.clang b/c/misra/test/rules/RULE-11-10/test.c.clang new file mode 100644 index 0000000000..c30368a48d --- /dev/null +++ b/c/misra/test/rules/RULE-11-10/test.c.clang @@ -0,0 +1,28 @@ +// _Atomic void g1; // doesn't compile +_Atomic int g2; // COMPLIANT +// _Atomic void *g3; // NON_COMPLIANT +// _Atomic void g4[]; // doesn't compile +void *_Atomic g5; // COMPLIANT + +struct { + _Atomic int m1; // COMPLIANT + // _Atomic void m2; // doesn't compile + // _Atomic void *m3; // NON_COMPLIANT + void *_Atomic m4; // COMPLIANT +} s1; + +void f(_Atomic int p1 // COMPLIANT + // _Atomic void *p2 // NON_COMPLIANT + // _Atomic void p3[] // doesn't compile, even though it perhaps should as + // it is adjusted to void*. +) {} + +// typedef _Atomic void *f2(void); // NON_COMPLIANT +// typedef _Atomic void *(*f3)(void); // NON_COMPLIANT +// typedef void f4(_Atomic void *); // NON_COMPLIANT +// typedef void (*f5)(_Atomic void *); // NON_COMPLIANT + +void f6() { + (void *)0; // COMPLIANT + // (_Atomic void *)0; // NON_COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.expected b/c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.expected index 91fd9f274a..24e6c4d5af 100644 --- a/c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.expected +++ b/c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.expected @@ -2,3 +2,11 @@ | test.c:14:8:14:9 | (int *)... | Cast performed between a pointer to object type (char) and a pointer to a different object type (int). | | test.c:15:8:15:25 | (int *)... | Cast performed between a pointer to object type (short) and a pointer to a different object type (int). | | test.c:15:15:15:25 | (short *)... | Cast performed between a pointer to object type (char) and a pointer to a different object type (short). | +| test.c:20:3:20:17 | (const int *)... | Cast performed between a pointer to object type (char) and a pointer to a different object type (const int). | +| test.c:21:3:21:16 | (int *)... | Cast performed between a pointer to object type (char) and a pointer to a different object type (int). | +| test.c:22:20:22:21 | (int *)... | Cast performed between a pointer to object type (char) and a pointer to a different object type (int). | +| test.c:23:3:23:18 | (long long *)... | Cast performed between a pointer to object type (int) and a pointer to a different object type (long long). | +| test.c:26:3:26:13 | (char *)... | Cast performed between a pointer to object type (_Atomic(int)) and a pointer to a different object type (char). | +| test.c:27:8:27:10 | (char *)... | Cast performed between a pointer to object type (_Atomic(int)) and a pointer to a different object type (char). | +| test.c:28:3:28:21 | (_Atomic(char) *)... | Cast performed between a pointer to object type (_Atomic(int)) and a pointer to a different object type (_Atomic(char)). | +| test.c:29:23:29:25 | (_Atomic(char) *)... | Cast performed between a pointer to object type (_Atomic(int)) and a pointer to a different object type (_Atomic(char)). | diff --git a/c/misra/test/rules/RULE-11-3/test.c b/c/misra/test/rules/RULE-11-3/test.c index 64ae688993..0d91740438 100644 --- a/c/misra/test/rules/RULE-11-3/test.c +++ b/c/misra/test/rules/RULE-11-3/test.c @@ -13,4 +13,18 @@ void f1(void) { int *v8 = (int *)0; // COMPLIANT v8 = v2; // NON_COMPLIANT v8 = (int *)(short *)v2; // NON_COMPLIANT + (const void *)v1; // COMPLIANT + const void *v9 = v1; // COMPLIANT + (int *)v9; // COMPLIANT - cast from void* + (const void *)v2; // COMPLIANT + (const int *)v2; // NON_COMPLIANT + (int *const)v2; // NON_COMPLIANT + int *const v10 = v2; // NON_COMPLIANT + (long long *)v10; // NON_COMPLIANT + + _Atomic int *v11 = 0; + (char *)v11; // NON_COMPLIANT + v2 = v11; // NON_COMPLIANT + (_Atomic char *)v11; // NON_COMPLIANT + _Atomic char *v12 = v11; // NON_COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected b/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected index 5fedfdcce4..17a2fa223f 100644 --- a/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected +++ b/c/misra/test/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.expected @@ -1,6 +1,6 @@ -| test.c:5:21:5:42 | (unsigned int)... | Cast performed between a pointer to object type and a pointer to an integer type. | -| test.c:5:35:5:42 | (int *)... | Cast performed between a pointer to object type and a pointer to an integer type. | -| test.c:6:21:6:37 | (unsigned int)... | Cast performed between a pointer to object type and a pointer to an integer type. | -| test.c:8:8:8:24 | (unsigned int)... | Cast performed between a pointer to object type and a pointer to an integer type. | -| test.c:10:22:10:22 | (unsigned int *)... | Cast performed between a pointer to object type and a pointer to an integer type. | -| test.c:12:22:12:39 | (unsigned int *)... | Cast performed between a pointer to object type and a pointer to an integer type. | +| test.c:6:21:6:37 | (unsigned int)... | Cast from pointer to object type 'unsigned int *' to integer type 'unsigned int'. | test.c:6:21:6:37 | (unsigned int)... | | +| test.c:8:8:8:24 | (unsigned int)... | Cast from pointer to object type 'unsigned int *' to integer type 'unsigned int'. | test.c:8:8:8:24 | (unsigned int)... | | +| test.c:12:22:12:39 | (unsigned int *)... | Cast from integer type 'unsigned int' to pointer to object type 'unsigned int *'. | test.c:12:22:12:39 | (unsigned int *)... | | +| test.c:18:1:18:24 | #define FOO (int *)0x200 | Cast from integer type 'int' to pointer to object type 'int *'. | test.c:18:1:18:24 | #define FOO (int *)0x200 | | +| test.c:26:3:26:22 | (int *)... | Cast from integer type 'int' to pointer to object type 'int *' from expansion of macro $@. | test.c:20:1:20:34 | #define FOO_FUNCTIONAL(x) (int *)x | FOO_FUNCTIONAL | +| test.c:27:14:27:25 | (int *)... | Cast from integer type 'int' to pointer to object type 'int *' from expansion of macro $@. | test.c:21:1:21:23 | #define FOO_INSERT(x) x | FOO_INSERT | diff --git a/c/misra/test/rules/RULE-11-4/test.c b/c/misra/test/rules/RULE-11-4/test.c index 25e3f3c4b2..283af5e560 100644 --- a/c/misra/test/rules/RULE-11-4/test.c +++ b/c/misra/test/rules/RULE-11-4/test.c @@ -2,12 +2,27 @@ void f1(void) { unsigned int v1 = (unsigned int)(void *)0; // COMPLIANT - unsigned int v2 = (unsigned int)(int *)0; // NON_COMPLIANT + unsigned int v2 = (unsigned int)(int *)0; // COMPLIANT unsigned int v3 = (unsigned int)&v2; // NON_COMPLIANT v3 = v2; // COMPLIANT v3 = (unsigned int)&v2; // NON_COMPLIANT v3 = NULL; // COMPLIANT - unsigned int *v4 = 0; // NON_COMPLIANT + unsigned int *v4 = 0; // COMPLIANT unsigned int *v5 = NULL; // COMPLIANT unsigned int *v6 = (unsigned int *)v2; // NON_COMPLIANT + const void *v7 = 0; + (unsigned int)v7; // COMPLIANT - cast const void to int + (const void *)v1; // COMPLIANT - casting int to const void +} + +#define FOO (int *)0x200 // NON_COMPLIANT +#define FOO_WRAPPER FOO; +#define FOO_FUNCTIONAL(x) (int *)x +#define FOO_INSERT(x) x + +void test_macros() { + FOO; // Issue is reported at the macro + FOO_WRAPPER; // Issue is reported at the macro + FOO_FUNCTIONAL(0x200); // NON_COMPLIANT + FOO_INSERT((int *)0x200); // NON_COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.expected b/c/misra/test/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.expected index 5b4eec8d15..42cf288b34 100644 --- a/c/misra/test/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.expected +++ b/c/misra/test/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.expected @@ -1 +1,2 @@ | test.c:6:13:6:21 | (int *)... | Cast performed from a void pointer into a pointer to an object (int *). | +| test.c:11:3:11:11 | (int *)... | Cast performed from a void pointer into a pointer to an object (int *). | diff --git a/c/misra/test/rules/RULE-11-5/test.c b/c/misra/test/rules/RULE-11-5/test.c index a7ffa4822e..5b5a5b3a52 100644 --- a/c/misra/test/rules/RULE-11-5/test.c +++ b/c/misra/test/rules/RULE-11-5/test.c @@ -7,4 +7,8 @@ void f1(void) { v2 = NULL; // COMPLIANT void *v3 = (void *)v1; // COMPLIANT v3 = (void *)v2; // COMPLIANT + const void *v4 = 0; + (int *)v4; // NON_COMPLIANT - const in type is irrelevant + (const void *)v1; // COMPLIANT - casting is from void to void, const addition + // should be irrelevant } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-7/test.c b/c/misra/test/rules/RULE-11-7/test.c index b7dd989b00..4891aaae85 100644 --- a/c/misra/test/rules/RULE-11-7/test.c +++ b/c/misra/test/rules/RULE-11-7/test.c @@ -7,4 +7,12 @@ void f1(void) { float v4 = (float)(bool)v1; // NON_COMPLIANT v1 = (int *)v2; // NON_COMPLIANT v4 = (float)v3; // COMPLIANT + void *v5 = 0; + const void *v6 = 0; + // void pointers (regardless of specifier) are not pointers to object, so all + // these examples are compliant according to this rule + (bool)v5; // COMPLIANT + (bool)v6; // COMPLIANT + (void *)v2; // COMPLIANT + (const void *)v2; // COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.expected b/c/misra/test/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.expected index 48658e2176..aa7752d28a 100644 --- a/c/misra/test/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.expected +++ b/c/misra/test/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.expected @@ -1,2 +1,6 @@ | test.c:4:19:4:33 | (const char *)... | Cast of pointer removes volatile qualification from its base type. | | test.c:6:13:6:21 | (char *)... | Cast of pointer removes const qualification from its base type. | +| test.c:9:3:9:11 | (char *)... | Cast of pointer removes atomic qualification from its base type. | +| test.c:10:7:10:7 | (char *)... | Cast of pointer removes atomic qualification from its base type. | +| test.c:11:3:11:17 | (const char *)... | Cast of pointer removes atomic qualification from its base type. | +| test.c:12:7:12:7 | (const char *)... | Cast of pointer removes atomic qualification from its base type. | diff --git a/c/misra/test/rules/RULE-11-8/test.c b/c/misra/test/rules/RULE-11-8/test.c index 75c7fc189a..e0e3b3a2fb 100644 --- a/c/misra/test/rules/RULE-11-8/test.c +++ b/c/misra/test/rules/RULE-11-8/test.c @@ -5,5 +5,12 @@ int f1(void) { const char *c2 = (const char *)c; // COMPLIANT char *d = (char *)c; // NON_COMPLIANT const char *e = (const char *)d; // COMPLIANT + _Atomic char *f = 0; + (char *)f; // NON_COMPLIANT + d = f; // NON_COMPLIANT + (const char *)f; // NON_COMPLIANT + e = f; // NON_COMPLIANT + (const _Atomic char *)f; // COMPLIANT + (const _Atomic char *)f; // COMPLIANT return 0; } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.expected b/c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.expected index 8cdd34edd1..d854730296 100644 --- a/c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.expected +++ b/c/misra/test/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.expected @@ -1,4 +1,5 @@ | test.c:15:13:15:13 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:15:7:15:13 | ... == ... | Equality operator | | test.c:17:8:17:8 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:17:3:17:8 | ... = ... | Assignment to pointer | -| test.c:25:20:25:20 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:25:3:25:35 | ... ? ... : ... | Ternary operator | -| test.c:25:20:25:20 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:25:15:25:20 | ... = ... | Assignment to pointer | +| test.c:23:13:23:13 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:23:3:23:13 | ... ? ... : ... | Ternary operator | +| test.c:24:8:24:8 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:24:3:24:13 | ... ? ... : ... | Ternary operator | +| test.c:31:14:31:14 | 0 | $@ uses zero-value integer constant expression as null pointer constant. | test.c:31:9:31:14 | ... = ... | Assignment to pointer | diff --git a/c/misra/test/rules/RULE-11-9/test.c b/c/misra/test/rules/RULE-11-9/test.c index 216ea2b280..e87366d831 100644 --- a/c/misra/test/rules/RULE-11-9/test.c +++ b/c/misra/test/rules/RULE-11-9/test.c @@ -19,9 +19,16 @@ void *f1(void *p1, int p2) { p1 = NULL; // COMPLIANT if (p2 == 0) { // COMPLIANT return NULL; - } // COMPLIANT - (p1) ? (p1 = NULL) : (p1 = NULL); // COMPLIANT - (p2 > 0) ? (p1 = NULL) : (p1 = NULL); // COMPLIANT - (p2 > 0) ? (p1 = 0) : (p1 = NULL); // NON_COMPLIANT - return 0; // COMPLIANT + } + p2 ? p1 : 0; // NON_COMPLIANT + p2 ? 0 : p1; // NON_COMPLIANT + p2 ? (void *)0 : p1; // COMPLIANT + p2 ? p1 : (void *)0; // COMPLIANT + p2 ? p2 : 0; // COMPLIANT - p2 is not a pointer type + p2 ? 0 : p2; // COMPLIANT - p2 is not a pointer type + int x; + int *y; + p2 ? (p1 = 0) : p1; // NON_COMPLIANT - p1 is a pointer type + p2 ? (p2 = 0) : p1; // COMPLIANT - p2 is not a pointer type + return 0; // COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-12-2/RightHandOperandOfAShiftRange.expected b/c/misra/test/rules/RULE-12-2/RightHandOperandOfAShiftRange.expected index a4deb83a14..5ac6f8bfd4 100644 --- a/c/misra/test/rules/RULE-12-2/RightHandOperandOfAShiftRange.expected +++ b/c/misra/test/rules/RULE-12-2/RightHandOperandOfAShiftRange.expected @@ -1,10 +1,12 @@ -| test.c:8:10:8:10 | 8 | The right hand operand of the shift operator shall lie in the range 0 to 7. | -| test.c:9:10:9:11 | - ... | The right hand operand of the shift operator shall lie in the range 0 to 7. | -| test.c:10:10:10:14 | ... + ... | The right hand operand of the shift operator shall lie in the range 0 to 7. | -| test.c:11:10:11:14 | ... + ... | The right hand operand of the shift operator shall lie in the range 0 to 7. | -| test.c:13:21:13:22 | 16 | The right hand operand of the shift operator shall lie in the range 0 to 15. | -| test.c:16:9:16:9 | 8 | The right hand operand of the shift operator shall lie in the range 0 to 7. | -| test.c:21:9:21:10 | 64 | The right hand operand of the shift operator shall lie in the range 0 to 63. | -| test.c:25:10:25:10 | 8 | The right hand operand of the shift operator shall lie in the range 0 to 7. | -| test.c:26:10:26:11 | 64 | The right hand operand of the shift operator shall lie in the range 0 to 7. | -| test.c:30:16:30:17 | 64 | The right hand operand of the shift operator shall lie in the range 0 to 63. | +| test.c:8:10:8:10 | 8 | The possible range of the right operand of the shift operator (8..8) is outside the the valid shift range (0..7) for the essential type of the left operand (uint8_t). | test.c:8:3:8:10 | ... >> ... | | +| test.c:9:10:9:11 | - ... | The possible range of the right operand of the shift operator (-1..-1) is outside the the valid shift range (0..7) for the essential type of the left operand (uint8_t). | test.c:9:3:9:11 | ... >> ... | | +| test.c:10:10:10:14 | ... + ... | The possible range of the right operand of the shift operator (8..8) is outside the the valid shift range (0..7) for the essential type of the left operand (uint8_t). | test.c:10:3:10:14 | ... >> ... | | +| test.c:11:10:11:14 | ... + ... | The possible range of the right operand of the shift operator (8..8) is outside the the valid shift range (0..7) for the essential type of the left operand (uint8_t). | test.c:11:3:11:14 | ... << ... | | +| test.c:13:21:13:22 | 16 | The possible range of the right operand of the shift operator (16..16) is outside the the valid shift range (0..15) for the essential type of the left operand (uint16_t). | test.c:13:3:13:22 | ... << ... | | +| test.c:16:9:16:9 | 8 | The possible range of the right operand of the shift operator (8..8) is outside the the valid shift range (0..7) for the essential type of the left operand (unsigned char). | test.c:16:3:16:9 | ... << ... | | +| test.c:21:9:21:10 | 64 | The possible range of the right operand of the shift operator (64..64) is outside the the valid shift range (0..63) for the essential type of the left operand (unsigned long). | test.c:21:3:21:10 | ... << ... | | +| test.c:26:10:26:11 | 64 | The possible range of the right operand of the shift operator (64..64) is outside the the valid shift range (0..63) for the essential type of the left operand (unsigned long). | test.c:26:3:26:11 | ... << ... | | +| test.c:30:16:30:17 | 64 | The possible range of the right operand of the shift operator (64..64) is outside the the valid shift range (0..63) for the essential type of the left operand (unsigned long). | test.c:30:3:30:17 | ... << ... | | +| test.c:34:8:34:8 | y | The possible range of the right operand of the shift operator (0..4294967295) is outside the the valid shift range (0..31) for the essential type of the left operand (unsigned int). | test.c:34:3:34:8 | ... >> ... | | +| test.c:40:8:40:8 | y | The possible range of the right operand of the shift operator (-2147483648..2147483647) is outside the the valid shift range (0..31) for the essential type of the left operand (signed int). | test.c:40:3:40:8 | ... >> ... | | +| test.c:42:8:42:8 | y | The possible range of the right operand of the shift operator (-31..31) is outside the the valid shift range (0..31) for the essential type of the left operand (signed int). | test.c:42:3:42:8 | ... >> ... | | diff --git a/c/misra/test/rules/RULE-12-2/test.c b/c/misra/test/rules/RULE-12-2/test.c index 449a47b7ae..db7b7b062d 100644 --- a/c/misra/test/rules/RULE-12-2/test.c +++ b/c/misra/test/rules/RULE-12-2/test.c @@ -29,3 +29,15 @@ void f1() { ULONG_MAX << 8; // COMPLIANT ULONG_MAX << 64; // NON_COMPLIANT } + +void unsignedRemAssign(unsigned int y, unsigned int x) { + x >> y; // NON_COMPLIANT + y %= 32; + x >> y; // COMPLIANT +} + +void signedRemAssign(signed int y, signed int x) { + x >> y; // NON_COMPLIANT + y %= 32; + x >> y; // NON_COMPLIANT - may be negative +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected b/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected new file mode 100644 index 0000000000..5a92fc72fd --- /dev/null +++ b/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected @@ -0,0 +1,13 @@ +| test.c:43:13:43:13 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:44:18:44:18 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:45:13:45:13 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:46:18:46:18 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:65:6:65:6 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:71:9:71:9 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:82:18:82:18 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:83:3:83:31 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:84:3:84:39 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:85:3:85:19 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:86:3:86:23 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:87:3:87:19 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:88:3:88:23 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | diff --git a/cpp/autosar/test/rules/A18-5-4/GlobalUnsizedOperatorDeleteNotDefined.expected b/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected.clang similarity index 100% rename from cpp/autosar/test/rules/A18-5-4/GlobalUnsizedOperatorDeleteNotDefined.expected rename to c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected.clang diff --git a/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.qlref b/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.qlref new file mode 100644 index 0000000000..2196eeace1 --- /dev/null +++ b/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.qlref @@ -0,0 +1 @@ +rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-12-6/test.c b/c/misra/test/rules/RULE-12-6/test.c new file mode 100644 index 0000000000..74d9de2fca --- /dev/null +++ b/c/misra/test/rules/RULE-12-6/test.c @@ -0,0 +1,89 @@ +#include "stdatomic.h" +#include "string.h" + +typedef struct s1 { + int x; +} s1; + +_Atomic s1 atomic_s1; +// A non-atomic pointer to an atomic s1 +_Atomic s1 *ptr_atomic_s1; +// An atomic pointer to a non-atomic s1 +s1 *_Atomic s1_atomic_ptr; + +_Atomic int g3; + +void takeCopy(s1 p1); + +void f1() { + s1 l1; + s1 *l2; + l1 = atomic_load(&atomic_s1); // COMPLIANT + l1 = atomic_load(ptr_atomic_s1); // COMPLIANT + l2 = atomic_load(&s1_atomic_ptr); // COMPLIANT + l1.x = 4; // COMPLIANT + l2->x = 4; // COMPLIANT + atomic_store(&atomic_s1, l1); // COMPLIANT + atomic_store(ptr_atomic_s1, l1); // COMPLIANT + atomic_store(&s1_atomic_ptr, l2); // COMPLIANT + + // Undefined behavior, but not banned by this rule. + memset(&atomic_s1, 0, sizeof(atomic_s1)); // COMPLIANT + memset(ptr_atomic_s1, 0, sizeof(*ptr_atomic_s1)); // COMPLIANT + + // OK: whole loads and stores are protected from data-races. + takeCopy(atomic_s1); // COMPLIANT + takeCopy(*ptr_atomic_s1); // COMPLIANT + atomic_s1 = (s1){0}; // COMPLIANT + *ptr_atomic_s1 = (s1){0}; // COMPLIANT + atomic_s1 = *l2; // COMPLIANT + ptr_atomic_s1 = l2; // COMPLIANT + + // Banned: circumvents data-race protection, results in UB. + atomic_s1.x; // NON-COMPLIANT + ptr_atomic_s1->x; // NON-COMPLIANT + atomic_s1.x = 0; // NON-COMPLIANT + ptr_atomic_s1->x = 0; // NON-COMPLIANT + + // OK: not evaluated. + sizeof(atomic_s1); // COMPLIANT + sizeof(ptr_atomic_s1); // COMPLIANT + sizeof(atomic_s1.x); // COMPLIANT + sizeof(ptr_atomic_s1->x); // COMPLIANT + + // All OK: not an atomic struct, but rather an atomic pointer to non-atomic + // struct. + memset(s1_atomic_ptr, 0, sizeof(*s1_atomic_ptr)); // COMPLIANT + takeCopy(*s1_atomic_ptr); // COMPLIANT + *s1_atomic_ptr = (s1){0}; // COMPLIANT + s1_atomic_ptr = l2; // COMPLIANT + s1_atomic_ptr->x; // COMPLIANT + + // Atomic specifier hidden behind a typedef, still atomic: + typedef _Atomic s1 atomic_s1; + atomic_s1 l3; + l3.x; // NON_COMPLIANT + + // Worst case scenario: a typedef of a volatile const pointer to an atomic + // typedef type. + typedef atomic_s1 *volatile const atomic_s1_specified_ptr; + atomic_s1_specified_ptr l4; + (l4)->x; // NON_COMPLIANT +} + +#define NOOP(x) (x) +#define DOT_FIELD_ACCESS_X(v) (v).x +#define POINTER_FIELD_ACCESS_X(v) (v)->x +#define GET_X_ATOMIC_S1() atomic_s1.x +#define GET_X_PTR_ATOMIC_S1() atomic_s1.x + +void f2() { + // Banned UB with user macros: + NOOP(atomic_s1.x); // NON-COMPLIANT + DOT_FIELD_ACCESS_X(atomic_s1); // NON-COMPLIANT + POINTER_FIELD_ACCESS_X(ptr_atomic_s1); // NON-COMPLIANT + GET_X_ATOMIC_S1(); // NON-COMPLIANT + GET_X_PTR_ATOMIC_S1(); // NON-COMPLIANT + GET_X_ATOMIC_S1() = 0; // NON-COMPLIANT + GET_X_PTR_ATOMIC_S1() = 0; // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-12-6/test.c.clang b/c/misra/test/rules/RULE-12-6/test.c.clang new file mode 100644 index 0000000000..83ad24cdb5 --- /dev/null +++ b/c/misra/test/rules/RULE-12-6/test.c.clang @@ -0,0 +1,89 @@ +#include "stdatomic.h" +#include "string.h" + +typedef struct s1 { + int x; +} s1; + +_Atomic s1 atomic_s1; +// A non-atomic pointer to an atomic s1 +_Atomic s1 *ptr_atomic_s1; +// An atomic pointer to a non-atomic s1 +s1 *_Atomic s1_atomic_ptr; + +_Atomic int g3; + +void takeCopy(s1 p1); + +void f1() { + s1 l1; + s1 *l2; + l1 = atomic_load(&atomic_s1); // COMPLIANT + l1 = atomic_load(ptr_atomic_s1); // COMPLIANT + l2 = atomic_load(&s1_atomic_ptr); // COMPLIANT + l1.x = 4; // COMPLIANT + l2->x = 4; // COMPLIANT + atomic_store(&atomic_s1, l1); // COMPLIANT + atomic_store(ptr_atomic_s1, l1); // COMPLIANT + atomic_store(&s1_atomic_ptr, l2); // COMPLIANT + + // Undefined behavior, but not banned by this rule. + memset(&atomic_s1, 0, sizeof(atomic_s1)); // COMPLIANT + memset(ptr_atomic_s1, 0, sizeof(*ptr_atomic_s1)); // COMPLIANT + + // OK: whole loads and stores are protected from data-races. + takeCopy(atomic_s1); // COMPLIANT + takeCopy(*ptr_atomic_s1); // COMPLIANT + atomic_s1 = (s1){0}; // COMPLIANT + *ptr_atomic_s1 = (s1){0}; // COMPLIANT + atomic_s1 = *l2; // COMPLIANT + ptr_atomic_s1 = l2; // COMPLIANT + + // Banned: circumvents data-race protection, results in UB. + // atomic_s1.x; // NON-COMPLIANT + // ptr_atomic_s1->x; // NON-COMPLIANT + // atomic_s1.x = 0; // NON-COMPLIANT + // ptr_atomic_s1->x = 0; // NON-COMPLIANT + + // OK: not evaluated. + sizeof(atomic_s1); // COMPLIANT + sizeof(ptr_atomic_s1); // COMPLIANT + // sizeof(atomic_s1.x); // COMPLIANT + // sizeof(ptr_atomic_s1->x); // COMPLIANT + + // All OK: not an atomic struct, but rather an atomic pointer to non-atomic + // struct. + memset(s1_atomic_ptr, 0, sizeof(*s1_atomic_ptr)); // COMPLIANT + takeCopy(*s1_atomic_ptr); // COMPLIANT + *s1_atomic_ptr = (s1){0}; // COMPLIANT + s1_atomic_ptr = l2; // COMPLIANT + s1_atomic_ptr->x; // COMPLIANT + + // Atomic specifier hidden behind a typedef, still atomic: + typedef _Atomic s1 atomic_s1; + atomic_s1 l3; + // l3.x; // NON_COMPLIANT + + // Worst case scenario: a typedef of a volatile const pointer to an atomic + // typedef type. + typedef atomic_s1 *volatile const atomic_s1_specified_ptr; + atomic_s1_specified_ptr l4; + // (l4)->x; // NON_COMPLIANT +} + +#define NOOP(x) (x) +#define DOT_FIELD_ACCESS_X(v) (v).x +#define POINTER_FIELD_ACCESS_X(v) (v)->x +#define GET_X_ATOMIC_S1() atomic_s1.x +#define GET_X_PTR_ATOMIC_S1() atomic_s1.x + +void f2() { + // Banned UB with user macros: + // NOOP(atomic_s1.x); // NON-COMPLIANT + // DOT_FIELD_ACCESS_X(atomic_s1); // NON-COMPLIANT + // POINTER_FIELD_ACCESS_X(ptr_atomic_s1); // NON-COMPLIANT + // GET_X_ATOMIC_S1(); // NON-COMPLIANT + // GET_X_PTR_ATOMIC_S1(); // NON-COMPLIANT + // GET_X_ATOMIC_S1() = 0; // NON-COMPLIANT + // GET_X_PTR_ATOMIC_S1() = 0; // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected b/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected new file mode 100644 index 0000000000..4fa06eb069 --- /dev/null +++ b/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected @@ -0,0 +1,5 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:112,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:112,67-75) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:112,5-18) +| test.c:44:12:44:18 | ... + ... | Atomic variable $@ has a $@ that is unsequenced with $@. | test.c:42:15:42:16 | a1 | a1 | test.c:44:12:44:13 | a1 | previous read | test.c:44:17:44:18 | a1 | another read | +| test.c:46:3:46:37 | ... + ... | Atomic variable $@ has a $@ that is unsequenced with $@. | test.c:42:15:42:16 | a1 | a1 | test.c:46:16:46:17 | a1 | previous read | test.c:46:35:46:36 | a1 | another read | diff --git a/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected.gcc b/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected.gcc new file mode 100644 index 0000000000..ccfb4e6a7b --- /dev/null +++ b/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected.gcc @@ -0,0 +1,5 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:112,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:112,67-75) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:112,5-18) +| test.c:44:12:44:18 | ... + ... | Atomic variable $@ has a $@ that is unsequenced with $@. | test.c:42:15:42:16 | a1 | a1 | test.c:44:12:44:13 | a1 | previous read | test.c:44:17:44:18 | a1 | another read | +| test.c:46:15:46:17 | & ... | Atomic variable $@ has a $@ that is unsequenced with $@. | test.c:42:15:42:16 | a1 | a1 | test.c:46:16:46:17 | a1 | previous read | test.c:46:35:46:36 | a1 | another read | diff --git a/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.qlref b/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.qlref new file mode 100644 index 0000000000..46242df1b0 --- /dev/null +++ b/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.qlref @@ -0,0 +1 @@ +rules/RULE-13-2/UnsequencedAtomicReads.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-13-2/UnsequencedSideEffects.expected b/c/misra/test/rules/RULE-13-2/UnsequencedSideEffects.expected index 17b89c2f01..b6c704322c 100644 --- a/c/misra/test/rules/RULE-13-2/UnsequencedSideEffects.expected +++ b/c/misra/test/rules/RULE-13-2/UnsequencedSideEffects.expected @@ -1,6 +1,6 @@ -| test.c:6:12:6:18 | ... + ... | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:6:12:6:13 | l1 | side effect | test.c:6:12:6:13 | l1 | l1 | test.c:6:17:6:18 | l1 | side effect | test.c:6:17:6:18 | l1 | l1 | -| test.c:7:12:7:18 | ... + ... | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:7:12:7:13 | l1 | side effect | test.c:7:12:7:13 | l1 | l1 | test.c:7:17:7:18 | l2 | side effect | test.c:7:17:7:18 | l2 | l2 | -| test.c:17:3:17:21 | ... = ... | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:17:8:17:9 | l1 | side effect | test.c:17:8:17:9 | l1 | l1 | test.c:17:13:17:14 | l1 | side effect | test.c:17:13:17:14 | l1 | l1 | -| test.c:19:3:19:5 | call to foo | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:19:7:19:8 | l1 | side effect | test.c:19:7:19:8 | l1 | l1 | test.c:19:11:19:12 | l2 | side effect | test.c:19:11:19:12 | l2 | l2 | -| test.c:25:3:25:5 | call to foo | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:25:7:25:10 | ... ++ | side effect | test.c:25:7:25:8 | l8 | l8 | test.c:25:13:25:14 | l8 | read | test.c:25:13:25:14 | l8 | l8 | -| test.c:35:5:35:13 | ... = ... | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:35:10:35:12 | ... ++ | side effect | test.c:35:10:35:10 | i | i | test.c:35:10:35:12 | ... ++ | side effect | test.c:35:10:35:10 | i | i | +| test.c:8:12:8:18 | ... + ... | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:8:12:8:13 | l1 | side effect | test.c:8:12:8:13 | l1 | l1 | test.c:8:17:8:18 | l1 | side effect | test.c:8:17:8:18 | l1 | l1 | +| test.c:9:12:9:18 | ... + ... | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:9:12:9:13 | l1 | side effect | test.c:9:12:9:13 | l1 | l1 | test.c:9:17:9:18 | l2 | side effect | test.c:9:17:9:18 | l2 | l2 | +| test.c:19:3:19:21 | ... = ... | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:19:8:19:9 | l1 | side effect | test.c:19:8:19:9 | l1 | l1 | test.c:19:13:19:14 | l1 | side effect | test.c:19:13:19:14 | l1 | l1 | +| test.c:21:3:21:5 | call to foo | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:21:7:21:8 | l1 | side effect | test.c:21:7:21:8 | l1 | l1 | test.c:21:11:21:12 | l2 | side effect | test.c:21:11:21:12 | l2 | l2 | +| test.c:27:3:27:5 | call to foo | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:27:7:27:10 | ... ++ | side effect | test.c:27:7:27:8 | l8 | l8 | test.c:27:13:27:14 | l8 | read | test.c:27:13:27:14 | l8 | l8 | +| test.c:37:5:37:13 | ... = ... | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:37:10:37:12 | ... ++ | side effect | test.c:37:10:37:10 | i | i | test.c:37:10:37:12 | ... ++ | side effect | test.c:37:10:37:10 | i | i | diff --git a/c/misra/test/rules/RULE-13-2/test.c b/c/misra/test/rules/RULE-13-2/test.c index 1bebec3775..e1be53a037 100644 --- a/c/misra/test/rules/RULE-13-2/test.c +++ b/c/misra/test/rules/RULE-13-2/test.c @@ -1,3 +1,5 @@ +#include + void foo(int, int); void unsequenced_sideeffects1() { @@ -34,4 +36,15 @@ void unsequenced_sideeffects2() { for (i = 0; i < 10; i++) { test(i++); // NON_COMPLIANT } +} + +void atomics() { + _Atomic int a1, a2; + int l3 = a1 + a2; // COMPLIANT + int l4 = a1 + a1; // NON_COMPLIANT + a1 = a1 + 1; // COMPLIANT + atomic_load(&a1) + atomic_load(&a1); // NON_COMPLIANT + atomic_load(&a1) + atomic_load(&a2); // COMPLIANT + atomic_store(&a1, atomic_load(&a1)); // COMPLIANT + atomic_store(&a1, a1); // COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.expected b/c/misra/test/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.expected deleted file mode 100644 index 57f90043e1..0000000000 --- a/c/misra/test/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.expected +++ /dev/null @@ -1,3 +0,0 @@ -| test.c:7:7:7:12 | ... = ... | Use of an assignment operator's result. | -| test.c:11:11:11:16 | ... = ... | Use of an assignment operator's result. | -| test.c:13:8:13:13 | ... = ... | Use of an assignment operator's result. | diff --git a/c/misra/test/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.qlref b/c/misra/test/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.qlref deleted file mode 100644 index 16d027d915..0000000000 --- a/c/misra/test/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.testref b/c/misra/test/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.testref new file mode 100644 index 0000000000..41e225624c --- /dev/null +++ b/c/misra/test/rules/RULE-13-4/ResultOfAnAssignmentOperatorShouldNotBeUsed.testref @@ -0,0 +1 @@ +c/common/test/rules/resultofanassignmentoperatorshouldnotbeused/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-13-4/test.c b/c/misra/test/rules/RULE-13-4/test.c deleted file mode 100644 index aeabb60fac..0000000000 --- a/c/misra/test/rules/RULE-13-4/test.c +++ /dev/null @@ -1,14 +0,0 @@ -void test() { - int l1, l2; - int l3[1]; - - l1 = l2; // COMPLIANT - - if (l1 = 1) // NON_COMPLIANT - { - } - - l1 = l3[l2 = 0]; // NON_COMPLIANT - - l1 = l2 = 0; // NON_COMPLIANT -} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected b/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected index c03c04d6cc..3beb834f84 100644 --- a/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected +++ b/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected @@ -5,3 +5,4 @@ | test.c:27:10:27:14 | ... < ... | Controlling expression in loop statement has an invariant value. | | test.c:37:3:37:6 | 1 | Controlling expression in conditional statement has an invariant value. | | test.c:38:3:38:3 | 1 | Controlling expression in conditional statement has an invariant value. | +| test.c:45:10:45:26 | ... && ... | Controlling expression in loop statement has an invariant value. | diff --git a/c/misra/test/rules/RULE-14-3/test.c b/c/misra/test/rules/RULE-14-3/test.c index 38db3e1286..ed8854afd2 100644 --- a/c/misra/test/rules/RULE-14-3/test.c +++ b/c/misra/test/rules/RULE-14-3/test.c @@ -37,4 +37,11 @@ void f5(bool b1) { true ? 1 : 2; // NON_COMPLIANT 1 ? 1 : 2; // NON_COMPLIANT b1 ? 1 : 2; // COMPLIANT +} + +void f6(int p1) { + while (p1 < 10 && p1 > 12) { // NON_COMPLIANT[FALSE_NEGATIVE] + } + while (1 == 0 && p1 > 12) { // NON_COMPLIANT + } } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-15-1/GotoStatementUsed.expected b/c/misra/test/rules/RULE-15-1/GotoStatementUsed.expected deleted file mode 100644 index 7e06759159..0000000000 --- a/c/misra/test/rules/RULE-15-1/GotoStatementUsed.expected +++ /dev/null @@ -1 +0,0 @@ -| test.c:4:3:4:14 | goto ... | Use of goto. | diff --git a/c/misra/test/rules/RULE-15-1/GotoStatementUsed.qlref b/c/misra/test/rules/RULE-15-1/GotoStatementUsed.qlref deleted file mode 100644 index 338455d28f..0000000000 --- a/c/misra/test/rules/RULE-15-1/GotoStatementUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-15-1/GotoStatementUsed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-15-1/GotoStatementUsed.testref b/c/misra/test/rules/RULE-15-1/GotoStatementUsed.testref new file mode 100644 index 0000000000..1834c6e140 --- /dev/null +++ b/c/misra/test/rules/RULE-15-1/GotoStatementUsed.testref @@ -0,0 +1 @@ +c/common/test/rules/gotostatementshouldnotbeused/GotoStatementShouldNotBeUsed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-15-1/test.c b/c/misra/test/rules/RULE-15-1/test.c deleted file mode 100644 index d13f01961c..0000000000 --- a/c/misra/test/rules/RULE-15-1/test.c +++ /dev/null @@ -1,9 +0,0 @@ -void test_goto() { - int x = 1; - - goto label1; // NON_COMPLIANT - -label1: - - x = 2; -} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected b/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected deleted file mode 100644 index 730403cbd7..0000000000 --- a/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected +++ /dev/null @@ -1,3 +0,0 @@ -| test.c:2:3:2:10 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. | test.c:2:3:2:10 | goto ... | goto | test.c:4:3:4:5 | label ...: | label | -| test.c:40:3:40:10 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. | test.c:40:3:40:10 | goto ... | goto | test.c:44:3:44:5 | label ...: | label | -| test.c:55:5:55:12 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. | test.c:55:5:55:12 | goto ... | goto | test.c:58:3:58:5 | label ...: | label | diff --git a/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.qlref b/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.qlref deleted file mode 100644 index 5f430f0790..0000000000 --- a/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-15-3/GotoLabelBlockCondition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.testref b/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.testref new file mode 100644 index 0000000000..cf558d9350 --- /dev/null +++ b/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.testref @@ -0,0 +1 @@ +c/common/test/rules/gotoreferencealabelinsurroundingblock/GotoReferenceALabelInSurroundingBlock.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-15-3/test.c b/c/misra/test/rules/RULE-15-3/test.c deleted file mode 100644 index 739affcfc1..0000000000 --- a/c/misra/test/rules/RULE-15-3/test.c +++ /dev/null @@ -1,85 +0,0 @@ -void f1() { - goto L1; - for (int i = 0; i < 100; i++) { - L1: // NON_COMPLIANT - break; - } -} - -void f2() { - int i = 0; - if (i >= 0) { - for (int j = 0; j < 10; j++) { - goto L2; - } - } -L2: // COMPLIANT - return; -} - -void f3() { - int i = 0; - if (i >= 0) { - for (int j = 0; j < 10; j++) { - goto L3; - L3: // COMPLIANT - break; - } - } -} - -void f4() { - int i = 0; -L4: // COMPLIANT - if (i >= 0) { - goto L4; - } -} - -void f5(int p) { - goto L1; - - switch (p) { - case 0: - L1:; // NON_COMPLIANT - break; - default: - break; - } -} - -void f6(int p) { - - switch (p) { - case 0: - goto L1; - break; - default: - L1: // NON_COMPLIANT - break; - } -} - -void f7(int p) { -L1: // COMPLIANT - switch (p) { - case 0: - goto L1; - break; - default: - break; - } -} - -void f8(int p) { - - switch (p) { - case 0: - goto L1; - ; - L1:; // COMPLIANT - break; - default: - break; - } -} diff --git a/c/misra/test/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.expected b/c/misra/test/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.expected new file mode 100644 index 0000000000..a94e37baa4 --- /dev/null +++ b/c/misra/test/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.expected @@ -0,0 +1,4 @@ +| test.c:6:15:6:16 | f4 | The function f4 is declared _noreturn but has a return type of int. | +| test.c:19:15:19:16 | f8 | The function f8 is declared _noreturn but has a return type of int. | +| test.c:24:17:24:18 | f9 | The function f9 is declared _noreturn but has a return type of void *. | +| test.c:26:31:26:33 | f10 | The function f10 is declared _noreturn but has a return type of int. | diff --git a/c/misra/test/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.qlref b/c/misra/test/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.qlref new file mode 100644 index 0000000000..6726b6957a --- /dev/null +++ b/c/misra/test/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.qlref @@ -0,0 +1 @@ +rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-17-10/test.c b/c/misra/test/rules/RULE-17-10/test.c new file mode 100644 index 0000000000..b5fc988af2 --- /dev/null +++ b/c/misra/test/rules/RULE-17-10/test.c @@ -0,0 +1,26 @@ +#include "stdlib.h" + +void f1(); // COMPLIANT +int f2(); // COMPLIANT +_Noreturn void f3(); // COMPLIANT +_Noreturn int f4(); // NON-COMPLIANT + +void f5() { // COMPLIANT +} + +int f6() { // COMPLIANT + return 0; +} + +_Noreturn void f7() { // COMPLIANT + abort(); +} + +_Noreturn int f8() { // NON-COMPLIANT + abort(); + return 0; +} + +_Noreturn void *f9(); // NON-COMPLIANT + +__attribute__((noreturn)) int f10(); // NON-COMPLIANT \ No newline at end of file diff --git a/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected b/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected new file mode 100644 index 0000000000..ecb77a477c --- /dev/null +++ b/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected @@ -0,0 +1,6 @@ +| test.c:7:6:7:21 | test_noreturn_f2 | The function test_noreturn_f2 cannot return and should be declared as _Noreturn. | +| test.c:18:6:18:21 | test_noreturn_f4 | The function test_noreturn_f4 cannot return and should be declared as _Noreturn. | +| test.c:47:6:47:21 | test_noreturn_f8 | The function test_noreturn_f8 cannot return and should be declared as _Noreturn. | +| test.c:63:6:63:22 | test_noreturn_f10 | The function test_noreturn_f10 cannot return and should be declared as _Noreturn. | +| test.c:97:6:97:22 | test_noreturn_f15 | The function test_noreturn_f15 cannot return and should be declared as _Noreturn. | +| test.c:101:6:101:22 | test_noreturn_f16 | The function test_noreturn_f16 cannot return and should be declared as _Noreturn. | diff --git a/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.qlref b/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.qlref new file mode 100644 index 0000000000..feb6f40804 --- /dev/null +++ b/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.qlref @@ -0,0 +1 @@ +rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-17-11/test.c b/c/misra/test/rules/RULE-17-11/test.c new file mode 100644 index 0000000000..73227accb9 --- /dev/null +++ b/c/misra/test/rules/RULE-17-11/test.c @@ -0,0 +1,104 @@ +#include "stdlib.h" + +_Noreturn void test_noreturn_f1(int i) { // COMPLIANT + abort(); +} + +void test_noreturn_f2(int i) { // NON_COMPLIANT + abort(); +} + +_Noreturn void test_noreturn_f3(int i) { // COMPLIANT + if (i > 0) { + abort(); + } + exit(1); +} + +void test_noreturn_f4(int i) { // NON_COMPLIANT + if (i > 0) { + abort(); + } + exit(1); +} + +void test_noreturn_f5(int i) { // COMPLIANT + if (i > 0) { + return; + } + exit(1); +} + +void test_noreturn_f6(int i) { // COMPLIANT + if (i > 0) { + abort(); + } + if (i < 0) { + abort(); + } +} + +void test_noreturn_f7(int i) { // COMPLIANT + if (i > 0) { + abort(); + } +} + +void test_noreturn_f8(int i) { // NON_COMPLIANT + if (i > 0) { + abort(); + } else { + abort(); + } +} + +_Noreturn void test_noreturn_f9(int i) { // COMPLIANT + if (i > 0) { + abort(); + } else { + abort(); + } +} + +void test_noreturn_f10(int i) { // NON_COMPLIANT + if (i > 0) { + abort(); + } + while (1) { + i = 5; + } +} + +_Noreturn void test_noreturn_f11(int i) { // COMPLIANT + if (i > 0) { + abort(); + } + while (1) { + i = 5; + } +} + +void test_noreturn_f12(); // COMPLIANT + +__attribute__((noreturn)) void test_noreturn_f13(int i) { // COMPLIANT + abort(); +} + +// Allowed by exception. It is undefined behavior for main() to be declared with +// noreturn. +int main(int argc, char *argv[]) { // COMPLIANT + abort(); +} + +_Noreturn void test_noreturn_f14(int i) { // COMPLIANT + test_noreturn_f1(i); +} + +void test_noreturn_f15(int i) { // NON_COMPLIANT + test_noreturn_f1(i); +} + +void test_noreturn_f16(int i) { // NON_COMPLIANT + // Infinite tail recursion + test_noreturn_f16(i); +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-17-12/FunctionAddressesShouldAddressOperator.expected b/c/misra/test/rules/RULE-17-12/FunctionAddressesShouldAddressOperator.expected new file mode 100644 index 0000000000..5a37cbd97e --- /dev/null +++ b/c/misra/test/rules/RULE-17-12/FunctionAddressesShouldAddressOperator.expected @@ -0,0 +1,13 @@ +| test.c:14:25:14:29 | func2 | The address of function func2 is taken without the & operator. | +| test.c:15:25:15:29 | func3 | The address of function func3 is taken without the & operator. | +| test.c:21:12:21:16 | func1 | The address of function func1 is taken without the & operator. | +| test.c:38:3:38:7 | func1 | The address of function func1 is taken without the & operator. | +| test.c:39:3:39:7 | func2 | The address of function func2 is taken without the & operator. | +| test.c:57:13:57:17 | func1 | The address of function func1 is taken without the & operator. | +| test.c:58:21:58:25 | func2 | The address of function func2 is taken without the & operator. | +| test.c:59:13:59:17 | func1 | The address of function func1 is taken without the & operator. | +| test.c:59:20:59:24 | func2 | The address of function func2 is taken without the & operator. | +| test.c:67:11:67:15 | func1 | The address of function func1 is taken without the & operator. | +| test.c:68:12:68:16 | func1 | The address of function func1 is taken without the & operator. | +| test.c:69:12:69:16 | func1 | The address of function func1 is taken without the & operator. | +| test.c:71:18:71:22 | func1 | The address of function func1 is taken without the & operator. | diff --git a/c/misra/test/rules/RULE-17-12/FunctionAddressesShouldAddressOperator.qlref b/c/misra/test/rules/RULE-17-12/FunctionAddressesShouldAddressOperator.qlref new file mode 100644 index 0000000000..f0a4753620 --- /dev/null +++ b/c/misra/test/rules/RULE-17-12/FunctionAddressesShouldAddressOperator.qlref @@ -0,0 +1 @@ +rules/RULE-17-12/FunctionAddressesShouldAddressOperator.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-17-12/test.c b/c/misra/test/rules/RULE-17-12/test.c new file mode 100644 index 0000000000..5ab5a4984d --- /dev/null +++ b/c/misra/test/rules/RULE-17-12/test.c @@ -0,0 +1,107 @@ +void func1() {} +void func2(int x, char *y) {} + +typedef struct { +} s; + +int func3() { return 0; } + +typedef void (*func_ptr_t1)(); +typedef void (*func_ptr_t2)(int x, char *y); +typedef s (*func_ptr_t3)(); + +func_ptr_t1 func_ptr1 = &func1; // COMPLIANT +func_ptr_t2 func_ptr2 = func2; // NON-COMPLIANT +func_ptr_t3 func_ptr3 = func3 + 0; // NON-COMPLIANT + +void take_func(func_ptr_t1 f1, func_ptr_t2 f2); + +func_ptr_t1 returns_func(int x) { + if (x == 0) { + return func1; // NON-COMPLIANT + } else if (x == 1) { + return &func1; // COMPLIANT + } + + return returns_func(0); // COMPLIANT +} + +#define MACRO_IDENTITY(f) (f) +#define MACRO_INVOKE_RISKY(f) (f()) +#define MACRO_INVOKE_IMPROVED(f) ((f)()) +#define MACRO_INVOKE_AND_USE_AS_TOKEN(f) f(0, #f) + +void test() { + func1(); // COMPLIANT + func2(1, "hello"); // COMPLIANT + + func1; // NON-COMPLIANT + func2; // NON-COMPLIANT + + &func1; // COMPLIANT + &func2; // COMPLIANT + + (func1)(); // COMPLIANT + (func2)(1, "hello"); // COMPLIANT + + &(func1); // COMPLIANT + &(func2); // COMPLIANT + + (&func1)(); // COMPLIANT + (&func2)(1, "hello"); // COMPLIANT + + (func1()); // COMPLIANT + (func2(1, "hello")); // COMPLIANT + + take_func(&func1, &func2); // COMPLIANT + take_func(func1, &func2); // NON-COMPLIANT + take_func(&func1, func2); // NON-COMPLIANT + take_func(func1, func2); // NON-COMPLIANT + + returns_func(0); // COMPLIANT + returns_func(0)(); // COMPLIANT + (returns_func(0))(); // COMPLIANT + + (void *)&func1; // COMPLIANT + (void *)(&func1); // COMPLIANT + (void *)func1; // NON-COMPLIANT + (void *)(func1); // NON-COMPLIANT + ((void *)func1); // NON-COMPLIANT + + MACRO_IDENTITY(func1); // NON-COMPLIANT + MACRO_IDENTITY(func1)(); // NON-COMPLIANT[FALSE NEGATIVE] + MACRO_IDENTITY(&func1); // COMPLIANT + MACRO_IDENTITY (&func1)(); // COMPLIANT + + MACRO_INVOKE_RISKY(func3); // NON-COMPLIANT[FALSE NEGATIVE] + MACRO_INVOKE_IMPROVED(func3); // NON-COMPLIANT[FALSE NEGATIVE] + MACRO_INVOKE_IMPROVED(&func3); // COMPLIANT + + MACRO_INVOKE_AND_USE_AS_TOKEN(func1); // COMPLIANT + + // Function pointers are exempt from this rule. + func_ptr1(); // COMPLIANT + func_ptr2(1, "hello"); // COMPLIANT + func_ptr1; // COMPLIANT + func_ptr2; // COMPLIANT + &func_ptr1; // COMPLIANT + &func_ptr2; // COMPLIANT + (func_ptr1)(); // COMPLIANT + (func_ptr2)(1, "hello"); // COMPLIANT + (*func_ptr1)(); // COMPLIANT + (*func_ptr2)(1, "hello"); // COMPLIANT + take_func(func_ptr1, func_ptr2); // COMPLIANT + (void *)func_ptr1; // COMPLIANT + (void *)&func_ptr1; // COMPLIANT + (void *)(&func_ptr1); // COMPLIANT + (void *)func_ptr1; // COMPLIANT + (void *)(func_ptr1); // COMPLIANT + ((void *)func_ptr1); // COMPLIANT + MACRO_IDENTITY(func_ptr1); // COMPLIANT + MACRO_IDENTITY(func_ptr1)(); // COMPLIANT + MACRO_IDENTITY(&func_ptr1); // COMPLIANT + (*MACRO_IDENTITY(&func_ptr1))(); // COMPLIANT + MACRO_INVOKE_RISKY(func_ptr3); // COMPLIANT + MACRO_INVOKE_IMPROVED(func_ptr3); // COMPLIANT + MACRO_INVOKE_IMPROVED(*&func_ptr3); // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected b/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected index 913f6f1c34..174c6aa40f 100644 --- a/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected +++ b/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected @@ -1,3 +1,9 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:48,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:49,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:51,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:56,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:72,28-36) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:72,51-59) | test.c:18:6:18:6 | 0 | The function argument does not have a sufficient number or elements declared in the $@. | test.c:1:13:1:14 | ar | parameter | | test.c:19:6:19:7 | ar | The function argument does not have a sufficient number or elements declared in the $@. | test.c:1:13:1:14 | ar | parameter | | test.c:21:6:21:9 | ar2p | The function argument does not have a sufficient number or elements declared in the $@. | test.c:1:13:1:14 | ar | parameter | diff --git a/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.testref b/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.testref new file mode 100644 index 0000000000..09a6d90538 --- /dev/null +++ b/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.testref @@ -0,0 +1 @@ +c/common/test/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.expected b/c/misra/test/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.expected new file mode 100644 index 0000000000..76b3da5eb0 --- /dev/null +++ b/c/misra/test/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.expected @@ -0,0 +1,17 @@ +| test.c:17:11:17:12 | definition of p5 | Parameter p5 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int' | test.c:17:15:17:16 | p0 | p0 | +| test.c:18:11:18:12 | definition of p6 | Parameter p6 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:18:18:18:19 | p0 | p0 | +| test.c:19:11:19:12 | definition of p7 | Parameter p7 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int[2]' | test.c:19:15:19:16 | p0 | p0 | +| test.c:20:11:20:12 | definition of p8 | Parameter p8 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int[]' | test.c:20:15:20:16 | p0 | p0 | +| test.c:20:11:20:12 | definition of p8 | Parameter p8 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int[]' | test.c:20:19:20:20 | p0 | p0 | +| test.c:24:12:24:13 | definition of p9 | Parameter p9 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int *' | test.c:24:16:24:17 | p0 | p0 | +| test.c:25:13:25:15 | definition of p10 | Parameter p10 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int *' | test.c:25:18:25:19 | p0 | p0 | +| test.c:28:12:28:14 | definition of p11 | Parameter p11 is adjusted to variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:28:21:28:22 | p0 | p0 | +| test.c:32:17:32:19 | definition of p13 | Parameter p13 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'const int' | test.c:32:22:32:23 | p0 | p0 | +| test.c:33:17:33:19 | definition of p14 | Parameter p14 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:33:22:33:23 | p0 | p0 | +| test.c:40:12:40:14 | definition of p17 | Parameter p17 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:40:24:40:25 | p0 | p0 | +| test.c:41:14:41:16 | definition of p18 | Parameter p18 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:41:27:41:28 | p0 | p0 | +| test.c:68:9:68:11 | definition of p27 | Parameter p27 is adjusted to variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:68:13:68:14 | p0 | p0 | +| test.c:68:9:68:11 | definition of p27 | Parameter p27 is adjusted to variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:68:17:68:18 | p0 | p0 | +| test.c:74:8:74:9 | definition of l3 | Variable l3 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int' | test.c:74:12:74:13 | p0 | p0 | +| test.c:79:15:79:16 | definition of l4 | Variable l4 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int' | test.c:79:19:79:20 | p0 | p0 | +| test.c:84:16:84:18 | declaration of td3 | Declaration td3 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:84:21:84:22 | p0 | p0 | diff --git a/c/misra/test/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.qlref b/c/misra/test/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.qlref new file mode 100644 index 0000000000..1a60cfacca --- /dev/null +++ b/c/misra/test/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.qlref @@ -0,0 +1 @@ +rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-10/test.c b/c/misra/test/rules/RULE-18-10/test.c new file mode 100644 index 0000000000..565b51e8de --- /dev/null +++ b/c/misra/test/rules/RULE-18-10/test.c @@ -0,0 +1,106 @@ +#define CONSTANT 1 + +int g1[3]; // COMPLIANT +int (*g2)[3]; // COMPLIANT +int (*g3)[CONSTANT]; // COMPLIANT + +void f1( + int p0, + + // Basic fixed length array types: + int p1[3], // COMPLIANT + int (*p2)[3], // COMPLIANT + int (*p3)[2][3], // COMPLIANT + int (*p4)[CONSTANT], // COMPLIANT + + // Basic pointers to VMTs: + int (*p5)[p0], // NON-COMPLIANT + int (*p6)[2][p0], // NON-COMPLIANT + int (*p7)[p0][2], // NON-COMPLIANT + int (*p8)[p0][p0], // NON-COMPLIANT + + // Types referring to pointers to VMTs: + // - pointer to pointer to VMT + int(*(*p9)[p0]), // NON-COMPLIANT + int(*(**p10)[p0]), // NON-COMPLIANT + + // - array of pointers to VMT + int (*(p11[3]))[p0], // NON-COMPLIANT + + // - const VMTs, const array-to-pointer adjustment + const int p12[p0], // COMPLIANT + const int (*p13)[p0], // NON-COMPLIANT + int (*const p14)[p0], // NON-COMPLIANT + + // - function types with argument that is a pointer to a VMT + int p15(int (*inner)[p0]), // NON-COMPLIANT[FALSE_NEGATIVE] + int (*p16)(int (*inner)[p0]), // NON-COMPLIANT[FALSE_NEGATIVE] + + // - function types that returns a pointer to a VMT + int (*(p17(void)))[p0], // NON-COMPLIANT + int (*((*p18)(void)))[p0], // NON-COMPLIANT + + // - structs cannot contain a VMT as a member. + struct { + int g1[3]; // COMPLIANT + int(*g2)[3]; // COMPLIANT + int(*g3)[CONSTANT]; // COMPLIANT + // Pointer to VMT (`int (*g4)[p0]`) is not allowed. + } p19, + + // - unions cannot contain a VMT as a member. + union { + int g1[3]; // COMPLIANT + int(*g2)[3]; // COMPLIANT + int(*g3)[CONSTANT]; // COMPLIANT + // Pointer to VMT (`int (*g4)[p0]`) is not allowed. + } p20, + + // Unknown array length types: + int p21[], // COMPLIANT + int p22[][2], // COMPLIANT + int (*p23)[], // COMPLIANT + // int (*p24)[2][], // doesn't compile + int (*p25)[][2], // COMPLIANT + + // VLA types that are rewritten as pointers: + int p26[p0], // COMPLIANT + int p27[p0][p0] // NON-COMPLIANT +) { + // Local variables may contain pointers to VMTs: + int l0[p0]; // COMPLIANT + int(*l1)[]; // COMPLIANT + int(*l2)[3]; // COMPLIANT + int(*l3)[p0]; // NON-COMPLIANT + + int l6[10]; + + // A pointer to a VMT may be declared `static`. + static int(*l4)[p0]; // NON-COMPLIANT + + // Block scope typedefs may refer to VMTs + typedef int(*td1)[3]; // COMPLIANT + typedef int(*td2)[]; // COMPLIANT + typedef int(*td3)[p0]; // NON-COMPLIANT + + td3 l5; // NON-COMPLIANT +} + +// Function prototypes may contain VMTs using '*' syntax: +void f2(int (*p1)[3], // COMPLIANT + int (*p2)[*], // NON-COMPLIANT[FALSE_NEGATIVE] + int (*p3)[2][*], // NON-COMPLIANT[FALSE_NEGATIVE] + int (*p4)[*][2], // NON-COMPLIANT[FALSE_NEGATIVE] + int (*p5)[*][*] // NON-COMPLIANT[FALSE_NEGATIVE] +); + +#define CONFUSING_MACRO() \ + int x; \ + int(*vla)[x]; \ + int(*not_vla)[]; + +void f3() { + // We cannot report `vla` in this macro without a false positive for + // `not_vla`. + CONFUSING_MACRO() // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.expected b/c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.expected new file mode 100644 index 0000000000..99c5a91645 --- /dev/null +++ b/c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.expected @@ -0,0 +1,4 @@ +| test.c:29:3:29:10 | ... = ... | Thread local object $@ address copied to static object $@. | test.c:8:19:8:20 | test.c:8:19:8:20 | t1 | test.c:12:6:12:7 | test.c:12:6:12:7 | g2 | +| test.c:55:3:55:14 | ... = ... | Thread local object $@ address copied to static object $@. | test.c:10:17:10:18 | test.c:10:17:10:18 | t3 | test.c:13:3:13:4 | test.c:13:3:13:4 | g3 | +| test.c:152:3:152:21 | ... = ... | Thread local object $@ address copied to static object $@. | test.c:152:16:152:20 | test.c:152:16:152:20 | & ... | test.c:12:6:12:7 | test.c:12:6:12:7 | g2 | +| test.c:155:3:155:23 | ... = ... | Thread local object $@ address copied to static object $@. | test.c:155:18:155:22 | test.c:155:18:155:22 | & ... | test.c:13:3:13:4 | test.c:13:3:13:4 | g3 | diff --git a/c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.qlref b/c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.qlref new file mode 100644 index 0000000000..90cdd7a43f --- /dev/null +++ b/c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.qlref @@ -0,0 +1 @@ +rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-6/test.c b/c/misra/test/rules/RULE-18-6/test.c new file mode 100644 index 0000000000..13b1070397 --- /dev/null +++ b/c/misra/test/rules/RULE-18-6/test.c @@ -0,0 +1,169 @@ +#include + +typedef struct { + int *p; + int m +} s; + +_Thread_local int t1; +_Thread_local int *t2; +_Thread_local s t3; +int g1; +int *g2; +s g3; + +void f1() { + // Regular object accesses + t1 = t1; // COMPLIANT + t1 = *t2; // COMPLIANT + t1 = g1; // COMPLIANT + t1 = *g2; // COMPLIANT + g1 = t1; // COMPLIANT + g1 = *t2; // COMPLIANT + g1 = g1; // COMPLIANT + g1 = *g2; // COMPLIANT + t2 = &t1; // COMPLIANT + t2 = t2; // COMPLIANT + t2 = &g1; // COMPLIANT + t2 = g2; // COMPLIANT + g2 = &t1; // NON-COMPLIANT + g2 = t2; // COMPLIANT + g2 = &g1; // COMPLIANT + g2 = g2; // COMPLIANT + *t2 = t1; // COMPLIANT + *t2 = *t2; // COMPLIANT + *t2 = g1; // COMPLIANT + *t2 = *g2; // COMPLIANT + *g2 = t1; // COMPLIANT + *g2 = *t2; // COMPLIANT + *g2 = g1; // COMPLIANT + *g2 = *g2; // COMPLIANT + + // Subobject accesses + t3.m = t3.m; // COMPLIANT + t3.m = *t3.p; // COMPLIANT + t3.m = g3.m; // COMPLIANT + t3.m = *g3.p; // COMPLIANT + g3.m = t3.m; // COMPLIANT + g3.m = *t3.p; // COMPLIANT + g3.m = g3.m; // COMPLIANT + g3.m = *g3.p; // COMPLIANT + t3.p = &t3.m; // COMPLIANT + t3.p = t3.p; // COMPLIANT + t3.p = &g3.m; // COMPLIANT + t3.p = g3.p; // COMPLIANT + g3.p = &t3.m; // NON-COMPLIANT + g3.p = t3.p; // COMPLIANT + g3.p = &g3.m; // COMPLIANT + g3.p = g3.p; // COMPLIANT + *t3.p = t3.m; // COMPLIANT + *t3.p = *t3.p; // COMPLIANT + *t3.p = g3.m; // COMPLIANT + *t3.p = *g3.p; // COMPLIANT + *g3.p = t3.m; // COMPLIANT + *g3.p = *t3.p; // COMPLIANT + *g3.p = g3.m; // COMPLIANT + *g3.p = *g3.p; // COMPLIANT + + // Storing values in locals (automatic storage duration) + int l1; + int *l2; + s l3; + + l1 = l1; // COMPLIANT + l1 = *l2; // COMPLIANT + l1 = l3.m; // COMPLIANT + l1 = *l3.p; // COMPLIANT + l1 = t1; // COMPLIANT + l1 = *t2; // COMPLIANT + l1 = t3.m; // COMPLIANT + l1 = *t3.p; // COMPLIANT + l1 = g1; // COMPLIANT + l1 = *g2; // COMPLIANT + l1 = g3.m; // COMPLIANT + l1 = *g3.p; // COMPLIANT + l2 = &l1; // COMPLIANT + l2 = l2; // COMPLIANT + l2 = &l3.m; // COMPLIANT + l2 = l3.p; // COMPLIANT + l2 = &t1; // COMPLIANT + l2 = t2; // COMPLIANT + l2 = &t3.m; // COMPLIANT + l2 = t3.p; // COMPLIANT + l2 = &g1; // COMPLIANT + l2 = g2; // COMPLIANT + l2 = &g3.m; // COMPLIANT + l2 = g3.p; // COMPLIANT + *l2 = l1; // COMPLIANT + *l2 = *l2; // COMPLIANT + *l2 = l3.m; // COMPLIANT + *l2 = *l3.p; // COMPLIANT + *l2 = t1; // COMPLIANT + *l2 = *t2; // COMPLIANT + *l2 = t3.m; // COMPLIANT + *l2 = *t3.p; // COMPLIANT + *l2 = g1; // COMPLIANT + *l2 = *g2; // COMPLIANT + *l2 = g3.m; // COMPLIANT + *l2 = *g3.p; // COMPLIANT + l3.m = l1; // COMPLIANT + l3.m = *l2; // COMPLIANT + l3.m = l3.m; // COMPLIANT + l3.m = *l3.p; // COMPLIANT + l3.m = t1; // COMPLIANT + l3.m = *t2; // COMPLIANT + l3.m = t3.m; // COMPLIANT + l3.m = *t3.p; // COMPLIANT + l3.m = g1; // COMPLIANT + l3.m = *g2; // COMPLIANT + l3.m = g3.m; // COMPLIANT + l3.m = *g3.p; // COMPLIANT + l3.p = &l1; // COMPLIANT + l3.p = l2; // COMPLIANT + l3.p = &l3.m; // COMPLIANT + l3.p = l3.p; // COMPLIANT + l3.p = &t1; // COMPLIANT + l3.p = t2; // COMPLIANT + l3.p = &t3.m; // COMPLIANT + l3.p = t3.p; // COMPLIANT + l3.p = &g1; // COMPLIANT + l3.p = g2; // COMPLIANT + l3.p = &g3.m; // COMPLIANT + l3.p = g3.p; // COMPLIANT + *l3.p = l1; // COMPLIANT + *l3.p = *l2; // COMPLIANT + *l3.p = l3.m; // COMPLIANT + *l3.p = *l3.p; // COMPLIANT + *l3.p = t1; // COMPLIANT + *l3.p = *t2; // COMPLIANT + *l3.p = t3.m; // COMPLIANT + *l3.p = *t3.p; // COMPLIANT + *l3.p = g1; // COMPLIANT + *l3.p = *g2; // COMPLIANT + *l3.p = g3.m; // COMPLIANT + *l3.p = *g3.p; // COMPLIANT + + // Storing local values in globals is covered by the shared query. +} + +tss_t tss1; +void f2() { + g1 = *(int *)tss_get(&tss1); // COMPLIANT + g2 = tss_get(&tss1); // NON-COMPLIANT + *g2 = *(int *)tss_get(&tss1); // COMPLIANT + g3.m = *(int *)tss_get(&tss1); // COMPLIANT + g3.p = tss_get(&tss1); // NON-COMPLIANT + *g3.p = *(int *)tss_get(&tss1); // COMPLIANT + g1 = ((s *)tss_get(&tss1))->m; // COMPLIANT + g1 = *((s *)tss_get(&tss1))->p; // COMPLIANT + g2 = &((s *)tss_get(&tss1))->m; // NON-COMPLIANT[false negative] + g2 = *((s *)tss_get(&tss1))->p; // COMPLIANT + *g2 = ((s *)tss_get(&tss1))->m; // COMPLIANT + *g2 = *((s *)tss_get(&tss1))->p; // COMPLIANT + g3.m = ((s *)tss_get(&tss1))->m; // COMPLIANT + g3.m = *((s *)tss_get(&tss1))->p; // COMPLIANT + g3.p = &((s *)tss_get(&tss1))->m; // NON-COMPLIANT[false negative] + g3.p = *((s *)tss_get(&tss1))->p; // COMPLIANT + *g3.p = ((s *)tss_get(&tss1))->m; // COMPLIANT + *g3.p = *((s *)tss_get(&tss1))->p; // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-8/VariableLengthArrayTypesUsed.expected b/c/misra/test/rules/RULE-18-8/VariableLengthArrayTypesUsed.expected index e9721ce642..af73daccfd 100644 --- a/c/misra/test/rules/RULE-18-8/VariableLengthArrayTypesUsed.expected +++ b/c/misra/test/rules/RULE-18-8/VariableLengthArrayTypesUsed.expected @@ -1,5 +1,8 @@ -| test.c:3:19:3:20 | definition of pa | Variable length array declared. | -| test.c:6:7:6:8 | definition of a1 | Variable length array declared. | -| test.c:7:7:7:8 | definition of a2 | Variable length array declared. | -| test.c:8:7:8:8 | definition of a3 | Variable length array declared. | -| test.c:14:20:14:21 | definition of pa | Variable length array declared. | +| test.c:6:7:6:8 | a1 | Variable length array of element type 'int' with non-constant size $@. | test.c:6:10:6:14 | ... + ... | ... + ... | +| test.c:7:7:7:8 | a2 | Variable length array of element type 'int' with non-constant size $@. | test.c:7:10:7:10 | n | n | +| test.c:8:7:8:8 | a3 | Variable length array of element type 'int[]' with non-constant size $@. | test.c:8:13:8:13 | n | n | +| test.c:12:7:12:8 | a7 | Variable length array of element type 'int[1]' with non-constant size $@. | test.c:12:10:12:10 | n | n | +| test.c:20:14:20:15 | t1 | Variable length array of element type 'int' with non-constant size $@. | test.c:18:26:18:26 | n | n | +| test.c:21:14:21:15 | t2 | Variable length array of element type 'int' with non-constant size $@. | test.c:18:26:18:26 | n | n | +| test.c:22:14:22:15 | t3 | Variable length array of element type 'int' with non-constant size $@. | test.c:18:26:18:26 | n | n | +| test.c:22:14:22:15 | t3 | Variable length array of element type 'vlaTypedef' with non-constant size $@. | test.c:22:17:22:17 | x | x | diff --git a/c/misra/test/rules/RULE-18-8/test.c b/c/misra/test/rules/RULE-18-8/test.c index 3a0a040f6d..ea639de271 100644 --- a/c/misra/test/rules/RULE-18-8/test.c +++ b/c/misra/test/rules/RULE-18-8/test.c @@ -1,7 +1,7 @@ #define TEST 1 -void f(int n, int pa[1][n]) { // NON_COMPLIANT - int a[1]; // COMPLIANT +void f(int n) { + int a[1]; // COMPLIANT int x = 1; int a1[1 + x]; // NON_COMPLIANT - not integer constant expr int a2[n]; // NON_COMPLIANT @@ -9,7 +9,33 @@ void f(int n, int pa[1][n]) { // NON_COMPLIANT int a4[] = {1}; // COMPLIANT - not a VLA int a5[TEST]; // COMPLIANT int a6[1 + 1]; // COMPLIANT + int a7[n][1]; // NON_COMPLIANT + int(*a8)[n]; // COMPLIANT - pointer to VLA, see RULE-18-10 + + extern int e1[]; // COMPLIANT + + // A typedef is not a VLA. + typedef int vlaTypedef[n]; // COMPLIANT + // The declarations using the typedef may or may not be VLAs. + vlaTypedef t1; // NON_COMPLIANT + vlaTypedef t2[1]; // NON_COMPLIANT + vlaTypedef t3[x]; // NON_COMPLIANT + vlaTypedef *t4; // COMPLIANT } -void f1(int n, int pa[n]) { // NON_COMPLIANT -} \ No newline at end of file +void f1(int n, + // Parameter array types are adjusted to pointers + int p1[n], // COMPLIANT + // Pointers to variably-modified types are not VLAs. + int p2[n][n], + int p3[], // array of unknown length is converted to pointer + int p4[][n] // array of unknown length are not VLAs. +) {} + +struct s { + // Structs must have at least one non-flexible array member. + int foo; + + // Flexible array members are not VLAs. + int flexibleArrayMember[]; // COMPLIANT +}; \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected b/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected new file mode 100644 index 0000000000..cf741ed16c --- /dev/null +++ b/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected @@ -0,0 +1,30 @@ +| test.c:45:3:45:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:45:3:45:8 | call to get_s1 | call to get_s1 | +| test.c:46:3:46:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:46:3:46:8 | call to get_s1 | call to get_s1 | +| test.c:47:7:47:24 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:47:7:47:12 | call to get_s1 | call to get_s1 | +| test.c:48:4:48:21 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:48:4:48:9 | call to get_s1 | call to get_s1 | +| test.c:49:4:49:21 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:49:4:49:9 | call to get_s1 | call to get_s1 | +| test.c:50:3:50:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:50:3:50:8 | call to get_s1 | call to get_s1 | +| test.c:51:3:51:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:51:3:51:8 | call to get_s1 | call to get_s1 | +| test.c:52:3:52:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:52:3:52:8 | call to get_s1 | call to get_s1 | +| test.c:53:3:53:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:53:3:53:8 | call to get_s1 | call to get_s1 | +| test.c:54:3:54:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:54:3:54:8 | call to get_s1 | call to get_s1 | +| test.c:55:8:55:25 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:55:8:55:13 | call to get_s1 | call to get_s1 | +| test.c:56:3:56:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:56:3:56:8 | call to get_s1 | call to get_s1 | +| test.c:57:8:57:25 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:57:8:57:13 | call to get_s1 | call to get_s1 | +| test.c:58:3:58:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:58:3:58:8 | call to get_s1 | call to get_s1 | +| test.c:59:3:59:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:59:3:59:8 | call to get_s1 | call to get_s1 | +| test.c:60:15:60:32 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:60:15:60:20 | call to get_s1 | call to get_s1 | +| test.c:61:16:61:33 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:61:16:61:21 | call to get_s1 | call to get_s1 | +| test.c:62:23:62:40 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:62:23:62:28 | call to get_s1 | call to get_s1 | +| test.c:63:7:63:24 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:63:7:63:12 | call to get_s1 | call to get_s1 | +| test.c:64:16:64:33 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:64:16:64:21 | call to get_s1 | call to get_s1 | +| test.c:65:15:65:32 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:65:15:65:20 | call to get_s1 | call to get_s1 | +| test.c:66:16:66:33 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:66:16:66:21 | call to get_s1 | call to get_s1 | +| test.c:67:23:67:40 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:67:23:67:28 | call to get_s1 | call to get_s1 | +| test.c:89:3:89:30 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:89:3:89:8 | call to get_s2 | call to get_s2 | +| test.c:90:3:90:36 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:90:3:90:8 | call to get_s2 | call to get_s2 | +| test.c:91:15:91:42 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:91:15:91:20 | call to get_s2 | call to get_s2 | +| test.c:92:15:92:48 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:92:15:92:20 | call to get_s2 | call to get_s2 | +| test.c:114:15:114:27 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:112:9:112:11 | arr | arr | test.c:114:16:114:22 | ... = ... | ... = ... | +| test.c:116:15:116:37 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:116:16:116:26 | ... ? ... : ... | ... ? ... : ... | +| test.c:117:15:117:31 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:117:16:117:20 | ... , ... | ... , ... | diff --git a/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.qlref b/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.qlref new file mode 100644 index 0000000000..d2db40e77c --- /dev/null +++ b/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.qlref @@ -0,0 +1 @@ +rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.expected b/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.expected new file mode 100644 index 0000000000..4c961ee994 --- /dev/null +++ b/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.expected @@ -0,0 +1,15 @@ +| test.c:80:3:80:17 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:80:12:80:14 | arr | arr | test.c:80:3:80:8 | call to get_s1 | call to get_s1 | +| test.c:81:3:81:17 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:81:12:81:14 | arr | arr | test.c:81:3:81:8 | call to get_s1 | call to get_s1 | +| test.c:82:3:82:17 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:82:12:82:14 | arr | arr | test.c:82:3:82:8 | call to get_s1 | call to get_s1 | +| test.c:83:3:83:17 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:83:12:83:14 | arr | arr | test.c:83:3:83:8 | call to get_s1 | call to get_s1 | +| test.c:84:5:84:19 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:84:14:84:16 | arr | arr | test.c:84:5:84:10 | call to get_s1 | call to get_s1 | +| test.c:93:3:93:27 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:93:22:93:24 | arr | arr | test.c:93:3:93:8 | call to get_s2 | call to get_s2 | +| test.c:94:3:94:27 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:94:22:94:24 | arr | arr | test.c:94:3:94:8 | call to get_s2 | call to get_s2 | +| test.c:140:3:140:23 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:140:12:140:20 | arr_union | arr_union | test.c:140:3:140:8 | call to get_s3 | call to get_s3 | +| test.c:141:3:141:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:141:12:141:21 | arr_struct | arr_struct | test.c:141:3:141:8 | call to get_s3 | call to get_s3 | +| test.c:142:3:142:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:142:12:142:21 | arr_struct | arr_struct | test.c:142:3:142:8 | call to get_s3 | call to get_s3 | +| test.c:143:3:143:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:143:12:143:21 | arr_struct | arr_struct | test.c:143:3:143:8 | call to get_s3 | call to get_s3 | +| test.c:144:3:144:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:144:12:144:21 | arr_struct | arr_struct | test.c:144:3:144:8 | call to get_s3 | call to get_s3 | +| test.c:145:4:145:25 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:145:13:145:22 | arr_struct | arr_struct | test.c:145:4:145:9 | call to get_s3 | call to get_s3 | +| test.c:149:3:149:19 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:149:12:149:16 | arr2d | arr2d | test.c:149:3:149:8 | call to get_s3 | call to get_s3 | +| test.c:150:4:150:20 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:150:13:150:17 | arr2d | arr2d | test.c:150:4:150:9 | call to get_s3 | call to get_s3 | diff --git a/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.qlref b/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.qlref new file mode 100644 index 0000000000..c1fb0bd2d4 --- /dev/null +++ b/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.qlref @@ -0,0 +1 @@ +rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-9/test.c b/c/misra/test/rules/RULE-18-9/test.c new file mode 100644 index 0000000000..d5eb5ec35e --- /dev/null +++ b/c/misra/test/rules/RULE-18-9/test.c @@ -0,0 +1,154 @@ +struct s1 { + int m1; + const int const_arr[10]; + int arr[10]; +}; + +struct s1 get_s1(); + +struct s2 { + struct s1 member_s1; + struct s1 const const_s1_arr[10]; + struct s1 *s1ptr; + struct s1 s1_arr[10]; +}; + +struct s2 get_s2(); +struct s2 *get_s2_ptr(); + +void use_int(int x) {} +void use_int_ptr(int *x) {} + +void f(void) { + struct s1 l1; + + // Auto lifetime, allowed: + l1.const_arr + 1; // COMPLIANT + l1.const_arr - 1; // COMPLIANT + &l1.const_arr; // COMPLIANT + use_int_ptr(l1.const_arr); // COMPLIANT + l1.arr[0] = 1; // COMPLIANT + + // Extern lifetime, allowed: + extern struct s1 g1; + g1.const_arr + 1; // COMPLIANT + g1.const_arr - 1; // COMPLIANT + &g1.const_arr; // COMPLIANT + use_int_ptr(g1.const_arr); // COMPLIANT + g1.arr[0] = 1; // COMPLIANT + + // Temporary lifetime, no conversion: + get_s1().const_arr; // COMPLIANT - not used as a value. + get_s1().m1 + 1; // COMPLIANT - not an array. + + // Temporary lifetime, array to pointer conversions: + get_s1().const_arr + 1; // NON-COMPLIANT + get_s1().const_arr - 1; // NON-COMPLIANT + 1 + get_s1().const_arr; // NON-COMPLIANT + *get_s1().const_arr; // NON-COMPLIANT + !get_s1().const_arr; // NON-COMPLIANT + get_s1().const_arr < 1; // NON-COMPLIANT + get_s1().const_arr <= 1; // NON-COMPLIANT + get_s1().const_arr > 1; // NON-COMPLIANT + get_s1().const_arr >= 1; // NON-COMPLIANT + get_s1().const_arr == 1; // NON-COMPLIANT + 1 == get_s1().const_arr; // NON-COMPLIANT + get_s1().const_arr && 1; // NON-COMPLIANT + 1 && get_s1().const_arr; // NON-COMPLIANT + get_s1().const_arr || 1; // NON-COMPLIANT + get_s1().const_arr ? 1 : 1; // NON-COMPLIANT + use_int_ptr(get_s1().const_arr); // NON-COMPLIANT + use_int_ptr((get_s1().const_arr)); // NON-COMPLIANT + use_int_ptr((void *)get_s1().const_arr); // NON-COMPLIANT + (1, get_s1().const_arr) + 1; // NON-COMPLIANT + int *local = get_s1().const_arr; // NON-COMPLIANT + (struct s1){get_s1().const_arr}; // NON-COMPLIANT + (struct s2){{get_s1().const_arr}}; // NON-COMPLIANT + struct s1 local2 = {get_s1().const_arr}; // NON-COMPLIANT + + // Results are not 'used' as a value. + (void *)get_s1().const_arr; // COMPLIANT + sizeof(get_s1().const_arr); // COMPLIANT + get_s1().const_arr, 1; // COMPLIANT + 1, get_s1().const_arr; // COMPLIANT + (get_s1().const_arr); // COMPLIANT + + get_s1().const_arr[0]; // COMPLIANT - subscripted value not modifiable + get_s1().arr[0]; // COMPLIANT - subscripted value not used as modifiable + use_int(get_s1().const_arr[0]); // COMPLIANT + use_int(get_s1().arr[0]); // COMPLIANT + get_s1().arr[0] = 1; // NON-COMPLIANT + get_s1().arr[0] -= 1; // NON-COMPLIANT + get_s1().arr[0]--; // NON-COMPLIANT + get_s1().arr[0]++; // NON-COMPLIANT + &(get_s1().arr[0]); // NON-COMPLIANT + + struct s2 l2; + + // Deeper accesses: + get_s2().member_s1.const_arr + 1; // NON-COMPLIANT + get_s2().const_s1_arr[0].const_arr + 1; // NON-COMPLIANT + use_int_ptr(get_s2().member_s1.const_arr); // NON-COMPLIANT + use_int_ptr(get_s2().const_s1_arr[0].const_arr); // NON-COMPLIANT + get_s2().member_s1.arr[0] = 1; // NON-COMPLIANT + get_s2().s1_arr[0].arr[0] = 1; // NON-COMPLIANT + get_s2().member_s1.const_arr[0]; // COMPLIANT + get_s2().const_s1_arr[0].const_arr[0]; // COMPLIANT + get_s2().s1_arr[0].const_arr[0]; // COMPLIANT + get_s2().s1ptr->const_arr[0]; // COMPLIANT + use_int(get_s2().member_s1.const_arr[0]); // COMPLIANT + use_int(get_s2().const_s1_arr[0].const_arr[0]); // COMPLIANT + use_int(get_s2().s1ptr->const_arr[0]); // COMPLIANT + + // Pointer members of a struct don't have temporary lifetime. + get_s2().s1ptr->const_arr + 1; // COMPLIANT + use_int_ptr(get_s2().s1ptr->const_arr); // COMPLIANT + get_s2().s1ptr->arr[0] = 1; // COMPLIANT + get_s2_ptr()->member_s1.const_arr + 1; // COMPLIANT + get_s2_ptr()->member_s1.arr[0] = 1; // COMPLIANT + + // Other types of non-lvalue types + struct { + int arr[10]; + } l3; + use_int_ptr((l3 = l3).arr); // NON-COMPLIANT + use_int_ptr(((struct s1)l1).const_arr); // NON-COMPLIANT[FALSE_NEGATIVE] + use_int_ptr((1 ? l1 : l1).const_arr); // NON-COMPLIANT + use_int_ptr((0, l1).const_arr); // NON-COMPLIANT + use_int_ptr((l2.s1ptr++)->const_arr); // COMPLIANT + use_int_ptr((--l2.s1ptr)->const_arr); // COMPLIANT +} + +// Additional modifiable lvalue tests +struct s3 { + struct s4 { + struct s5 { + struct s6 { + int x; + } m1; + } m1; + } arr_struct[1]; + + union u1 { + int x; + } arr_union[1]; + + int arr2d[1][1]; +} get_s3(); + +void f2(void) { + get_s3().arr_union[0].x = 1; // NON_COMPLIANT + get_s3().arr_struct[0] = (struct s4){0}; // NON_COMPLIANT + get_s3().arr_struct[0].m1 = (struct s5){0}; // NON_COMPLIANT + get_s3().arr_struct[0].m1.m1 = (struct s6){0}; // NON_COMPLIANT + get_s3().arr_struct[0].m1.m1.x = 1; // NON_COMPLIANT + &get_s3().arr_struct[0].m1.m1.x; // NON_COMPLIANT + get_s3().arr_struct[0].m1.m1.x + 1; // COMPLIANT + + get_s3().arr2d[1][1] + 1; // COMPLIANT + get_s3().arr2d[1][1] = 1; // NON_COMPLIANT + &get_s3().arr2d[1]; // NON_COMPLIANT + // The following cases are missing an ArrayToPointerConversion + use_int_ptr(get_s3().arr2d[1]); // NON_COMPLIANT[FALSE NEGATIVE] + get_s3().arr2d[1] + 1; // NON_COMPLIANT[FALSE NEGATIVE] +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-2-2/DeadCode.expected b/c/misra/test/rules/RULE-2-2/DeadCode.expected new file mode 100644 index 0000000000..e25a5a97ef --- /dev/null +++ b/c/misra/test/rules/RULE-2-2/DeadCode.expected @@ -0,0 +1,9 @@ +| test.c:15:3:15:11 | ... = ... | Assignment to dead1 is unused and has no side effects. | test.c:15:3:15:11 | ... = ... | | +| test.c:16:3:16:11 | ... = ... | Assignment to dead2 is unused and has no side effects. | test.c:16:3:16:11 | ... = ... | | +| test.c:19:3:19:7 | ... + ... | Result of operation is unused and has no side effects. | test.c:19:3:19:7 | ... + ... | | +| test.c:21:3:21:17 | call to no_side_effects | Result of operation is unused and has no side effects from call to function $@. | test.c:2:5:2:19 | no_side_effects | no_side_effects | +| test.c:23:3:23:30 | (int)... | Cast operation is unused. | test.c:23:3:23:30 | (int)... | | +| test.c:24:3:24:25 | (int)... | Cast operation is unused. | test.c:24:3:24:25 | (int)... | | +| test.c:27:4:27:18 | call to no_side_effects | Result of operation is unused and has no side effects from call to function $@. | test.c:2:5:2:19 | no_side_effects | no_side_effects | +| test.c:37:3:37:27 | call to no_side_effects | Result of operation is unused and has no side effects from call to function $@. | test.c:2:5:2:19 | no_side_effects | no_side_effects | +| test.c:38:7:38:31 | call to no_side_effects | Result of operation is unused and has no side effects from call to function $@. | test.c:2:5:2:19 | no_side_effects | no_side_effects | diff --git a/c/misra/test/rules/RULE-2-2/DeadCode.qlref b/c/misra/test/rules/RULE-2-2/DeadCode.qlref new file mode 100644 index 0000000000..761e04d51b --- /dev/null +++ b/c/misra/test/rules/RULE-2-2/DeadCode.qlref @@ -0,0 +1 @@ +rules/RULE-2-2/DeadCode.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-2-2/DeadCode.testref b/c/misra/test/rules/RULE-2-2/DeadCode.testref deleted file mode 100644 index f084f30aaa..0000000000 --- a/c/misra/test/rules/RULE-2-2/DeadCode.testref +++ /dev/null @@ -1 +0,0 @@ -c/common/test/rules/deadcode/DeadCode.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-2-2/test.c b/c/misra/test/rules/RULE-2-2/test.c new file mode 100644 index 0000000000..f8248c52d2 --- /dev/null +++ b/c/misra/test/rules/RULE-2-2/test.c @@ -0,0 +1,42 @@ +int may_have_side_effects(); +int no_side_effects(int x) { return 1 + 2; } +int no_side_effects_nondeterministic(); + +int test_dead_code(int x) { + int live1 = may_have_side_effects(), + live2 = may_have_side_effects(); // COMPLIANT + int live3 = 0, + live4 = may_have_side_effects(); // COMPLIANT + int live5 = 0, live6 = 0; // COMPLIANT + live5 = 1; // COMPLIANT + live6 = 2; // COMPLIANT + + int dead1 = 0, dead2 = 0; // COMPLIANT - init not considered by this rule + dead1 = 1; // NON_COMPLIANT - useless assignment + dead2 = 1; // NON_COMPLIANT - useless assignment + + may_have_side_effects(); // COMPLIANT + 1 + 2; // NON_COMPLIANT + + no_side_effects(x); // NON_COMPLIANT + + (int)may_have_side_effects(); // NON_COMPLIANT + (int)no_side_effects(x); // NON_COMPLIANT + (void)no_side_effects(x); // COMPLIANT + (may_have_side_effects()); // COMPLIANT + (no_side_effects(x)); // NON_COMPLIANT + +#define FULL_STMT_NO_SIDE_EFFECTS no_side_effects(1); +#define PART_STMT_NO_SIDE_EFFECTS no_side_effects(1) +#define BLOCK_SOME_SIDE_EFFECTS \ + { \ + may_have_side_effects(); \ + no_side_effects(1); \ + } + + FULL_STMT_NO_SIDE_EFFECTS // NON_COMPLIANT + PART_STMT_NO_SIDE_EFFECTS; // NON_COMPLIANT + BLOCK_SOME_SIDE_EFFECTS; // COMPLIANT + + return live5 + live6; // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-2-5/test.c b/c/misra/test/rules/RULE-2-5/test.c index f37acb1509..15930f68d1 100644 --- a/c/misra/test/rules/RULE-2-5/test.c +++ b/c/misra/test/rules/RULE-2-5/test.c @@ -13,4 +13,55 @@ void test() { MACRO2; HEADER_MACRO2; -} \ No newline at end of file +} + +#define CHECKED_MACRO_1 // COMPLIANT - used in branch +#define CHECKED_MACRO_2 // COMPLIANT - used in branch +#define CHECKED_MACRO_3 // COMPLIANT - used in branch + +#ifdef CHECKED_MACRO_1 +#endif + +#ifndef CHECKED_MACRO_2 +#endif + +#if defined(CHECKED_MACRO_3) +#endif + +// In the case above, the extractor will identify macro accesses with each use +// of the macro. In the case above, the extractor does not tie them together, +// but the standard considers this acceptable usage. Notably, this type of +// pattern occurs for header guards. + +#ifdef CHECKED_MACRO_BEFORE_1 +#endif + +#ifndef CHECKED_MACRO_BEFORE_2 +#endif + +#if defined(CHECKED_MACRO_BEFORE_3) +#endif + +// clang-format off + +#if defined (CHECKED_MACRO_BEFORE_4) +#endif + +#if defined( CHECKED_MACRO_BEFORE_5 ) +#endif + +#if defined ( CHECKED_MACRO_BEFORE_6 ) +#endif + +#if defined CHECKED_MACRO_BEFORE_7 +#endif + +// clang-format on + +#define CHECKED_MACRO_BEFORE_1 // COMPLIANT - used in branch +#define CHECKED_MACRO_BEFORE_2 // COMPLIANT - used in branch +#define CHECKED_MACRO_BEFORE_3 // COMPLIANT - used in branch +#define CHECKED_MACRO_BEFORE_4 // COMPLIANT - used in branch +#define CHECKED_MACRO_BEFORE_5 // COMPLIANT - used in branch +#define CHECKED_MACRO_BEFORE_6 // COMPLIANT - used in branch +#define CHECKED_MACRO_BEFORE_7 // COMPLIANT - used in branch \ No newline at end of file diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected new file mode 100644 index 0000000000..9a373a644c --- /dev/null +++ b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected @@ -0,0 +1,12 @@ +| test.c:6:5:6:6 | definition of g2 | Unused object 'g2'. | test.c:6:5:6:6 | definition of g2 | (ignored) | +| test.c:9:5:9:6 | definition of g3 | Unused object 'g3'. | test.c:9:5:9:6 | definition of g3 | (ignored) | +| test.c:20:7:20:8 | definition of l2 | Unused object 'l2'. | test.c:20:7:20:8 | definition of l2 | (ignored) | +| test.c:27:7:27:8 | definition of l5 | Unused object 'l5'. | test.c:27:7:27:8 | definition of l5 | (ignored) | +| test.c:37:10:37:11 | definition of g5 | Unused object 'g5'. | test.c:37:10:37:11 | definition of g5 | (ignored) | +| test.c:45:9:45:10 | definition of g6 | Unused object 'g6'. | test.c:45:9:45:10 | definition of g6 | (ignored) | +| test.c:51:5:51:6 | definition of g7 | Unused object 'g7'. | test.c:51:5:51:6 | definition of g7 | (ignored) | +| test.c:64:3:64:18 | ONLY_DEF_VAR(x) | Invocation of macro '$@' defines unused object 'l2'. | test.c:60:1:60:34 | #define ONLY_DEF_VAR(x) int x = 0; | ONLY_DEF_VAR | +| test.c:68:1:71:5 | #define ALSO_DEF_VAR(x) int x = 0; while (1) ; | Macro 'ALSO_DEF_VAR' defines unused object with an invocation-dependent name, for example, '$@'. | test.c:73:16:73:17 | definition of l1 | l1 | +| test.c:77:1:82:3 | #define DEF_UNUSED_INNER_VAR() { int _v = 0; while (1) ; } | Macro 'DEF_UNUSED_INNER_VAR' defines unused object '_v'. | test.c:77:1:82:3 | #define DEF_UNUSED_INNER_VAR() { int _v = 0; while (1) ; } | (ignored) | +| test.c:119:11:119:13 | definition of g10 | Unused object 'g10'. | test.c:119:11:119:13 | definition of g10 | (ignored) | +| test.c:124:13:124:14 | definition of l2 | Unused object 'l2'. | test.c:124:13:124:14 | definition of l2 | (ignored) | diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.qlref b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.qlref new file mode 100644 index 0000000000..096c4c64f1 --- /dev/null +++ b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.qlref @@ -0,0 +1 @@ +rules/RULE-2-8/UnusedObjectDefinition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.expected b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.expected new file mode 100644 index 0000000000..fa191e5d68 --- /dev/null +++ b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.expected @@ -0,0 +1,4 @@ +| test.c:87:29:87:30 | definition of g8 | Unused object 'g8'. | test.c:87:29:87:30 | definition of g8 | (ignored) | +| test.c:92:3:92:30 | ONLY_DEF_ATTR_UNUSED_VAR(x) | Invocation of macro '$@' defines unused object 'l2'. | test.c:88:1:88:70 | #define ONLY_DEF_ATTR_UNUSED_VAR(x) __attribute__((unused)) int x = 0; | ONLY_DEF_ATTR_UNUSED_VAR | +| test.c:96:1:99:5 | #define ALSO_DEF_ATTR_UNUSED_VAR(x) __attribute__((unused)) int x = 0; while (1) ; | Macro 'ALSO_DEF_ATTR_UNUSED_VAR' defines unused object with an invocation-dependent name, for example, '$@'. | test.c:101:28:101:29 | definition of l1 | l1 | +| test.c:106:1:111:3 | #define DEF_ATTR_UNUSED_INNER_VAR() { __attribute__((unused)) int _v = 0; while (1) ; } | Macro 'DEF_ATTR_UNUSED_INNER_VAR' defines unused object '_v'. | test.c:106:1:111:3 | #define DEF_ATTR_UNUSED_INNER_VAR() { __attribute__((unused)) int _v = 0; while (1) ; } | (ignored) | diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.qlref b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.qlref new file mode 100644 index 0000000000..4aa7269881 --- /dev/null +++ b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.qlref @@ -0,0 +1 @@ +rules/RULE-2-8/UnusedObjectDefinitionStrict.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-2-8/test.c b/c/misra/test/rules/RULE-2-8/test.c new file mode 100644 index 0000000000..e35bf15567 --- /dev/null +++ b/c/misra/test/rules/RULE-2-8/test.c @@ -0,0 +1,133 @@ +// Not a definition, only a declaration: +extern int g1; // COMPLIANT + +// Both declared + defined: +extern int g2; // COMPLIANT +int g2 = 1; // NON_COMPLIANT + +// Definition is only declaration: +int g3 = 1; // NON_COMPLIANT + +// Definition, but value is required for program to compile: +int g4 = 1; // COMPLIANT +void f1() { g4; } + +// Local variables: +void f2() { + int l1; // COMPLIANT + l1; + + int l2; // NON-COMPLIANT + + // Value is required for the program to compile: + int l3; // COMPLIANT + sizeof(l3); + + int l4, // COMPLIANT + l5; // NON-COMPLIANT + l4; +} + +// Struct fields are not objects: +struct s { + int x; // COMPLIANT +}; + +// Declaration of type struct is an object: +struct s g5; // NON-COMPLIANT + +// Struct fields are not objects: +union u { + int x; // COMPLIANT +}; + +// Declaration of type union is an object: +union u g6; // NON-COMPLIANT + +// Typedefs are not objects: +typedef int td1; // COMPLIANT + +// Declaration of typedef type object: +td1 g7; // NON-COMPLIANT + +// Function parameters are not objects: +void f3(int p) {} // COMPLIANT + +// Function type parameters are not objects: +typedef int td2(int x); // COMPLIANT + +// Macros that define unused vars tests: +#define ONLY_DEF_VAR(x) int x = 0; +void f4() { + ONLY_DEF_VAR(l1); // COMPLIANT + l1; + ONLY_DEF_VAR(l2); // NON-COMPLIANT +} + +// NON-COMPLIANT +#define ALSO_DEF_VAR(x) \ + int x = 0; \ + while (1) \ + ; +void f5() { + ALSO_DEF_VAR(l1); // COMPLIANT + ALSO_DEF_VAR(l2); // COMPLIANT +} + +#define DEF_UNUSED_INNER_VAR() \ + { \ + int _v = 0; \ + while (1) \ + ; \ + } // NON-COMPLIANT +void f6() { + DEF_UNUSED_INNER_VAR(); // COMPLIANT +} + +__attribute__((unused)) int g8 = 1; // NON-COMPLIANT +#define ONLY_DEF_ATTR_UNUSED_VAR(x) __attribute__((unused)) int x = 0; +void f7() { + ONLY_DEF_ATTR_UNUSED_VAR(l1); // COMPLIANT + l1; + ONLY_DEF_ATTR_UNUSED_VAR(l2); // NON-COMPLIANT +} + +// NON-COMPLIANT +#define ALSO_DEF_ATTR_UNUSED_VAR(x) \ + __attribute__((unused)) int x = 0; \ + while (1) \ + ; +void f8() { + ALSO_DEF_ATTR_UNUSED_VAR(l1); // COMPLIANT + ALSO_DEF_ATTR_UNUSED_VAR(l2); // COMPLIANT +} + +// NON-COMPLIANT +#define DEF_ATTR_UNUSED_INNER_VAR() \ + { \ + __attribute__((unused)) int _v = 0; \ + while (1) \ + ; \ + } + +void f9() { + DEF_ATTR_UNUSED_INNER_VAR(); // COMPLIANT +} + +// Const variable tests: +const int g9 = 1; // COMPLIANT +const int g10 = 1; // NON-COMPLIANT + +void f10() { + g9; + const int l1 = 1; // COMPLIANT + const int l2 = 1; // NON-COMPLIANT + l1; +} + +// Side effects should not disable this rule: +void f11() { + int l1 = 1; // COMPLIANT + int l2 = l1++; // COMPLIANT + l2; +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.expected b/c/misra/test/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.expected deleted file mode 100644 index 406010428c..0000000000 --- a/c/misra/test/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.expected +++ /dev/null @@ -1 +0,0 @@ -| test.c:25:1:25:29 | #define MACROTHIRTEEN(X) #X ## X | Macro definition uses an # operator followed by a ## operator. | diff --git a/c/misra/test/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.qlref b/c/misra/test/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.qlref deleted file mode 100644 index 35ef457cac..0000000000 --- a/c/misra/test/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.testref b/c/misra/test/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.testref new file mode 100644 index 0000000000..be7ebf2815 --- /dev/null +++ b/c/misra/test/rules/RULE-20-11/MoreThanOneHashOperatorInMacroDefinition.testref @@ -0,0 +1 @@ +c/common/test/rules/macroparameterfollowinghash/MacroParameterFollowingHash.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-20-11/test.c b/c/misra/test/rules/RULE-20-11/test.c deleted file mode 100644 index ad2c205970..0000000000 --- a/c/misra/test/rules/RULE-20-11/test.c +++ /dev/null @@ -1,27 +0,0 @@ -#define MACROONE 1 // COMPLIANT - -#define MACROTWO '#\'-#' + '#' // COMPLIANT - -#define MACROTHREE "##" // COMPLIANT - -#define MACROFOUR "##" + "#" // COMPLIANT - -#define MACROFIVE(X) #X // COMPLIANT - -#define MACROSIX(X, Y) X##Y // COMPLIANT - -#define MACROSEVEN "##'" #"#" // COMPLIANT - -#define MACROEIGHT '##' #"#" // COMPLIANT - -#define MACRONINE "##\"\"" + "#" // COMPLIANT - -#define MACROTEN "##\"\"'" + "#" // COMPLIANT - -#define MACROELEVEN(X) X #X #X // COMPLIANT - -#define MACROTWELVE(X) X##X##X // COMPLIANT - -#define MACROTHIRTEEN(X) #X##X // NON_COMPLIANT - -#define MACROFOURTEEN '#\'-#' + 1 #1 #1 + '#' // COMPLIANT \ No newline at end of file diff --git a/c/misra/test/rules/RULE-20-12/MacroParameterUsedAsHashOperand.expected b/c/misra/test/rules/RULE-20-12/MacroParameterUsedAsHashOperand.expected deleted file mode 100644 index be347218b3..0000000000 --- a/c/misra/test/rules/RULE-20-12/MacroParameterUsedAsHashOperand.expected +++ /dev/null @@ -1,2 +0,0 @@ -| test.c:4:1:4:41 | #define BAD_MACRO_WITH_ARG(x) (x) + wow ## x | Macro BAD_MACRO_WITH_ARG contains use of parameter x used in multiple contexts. | -| test.c:5:1:5:48 | #define BAD_MACRO_WITH_ARG_TWO(x,y) (x) + wow ## x | Macro BAD_MACRO_WITH_ARG_TWO contains use of parameter x used in multiple contexts. | diff --git a/c/misra/test/rules/RULE-20-12/MacroParameterUsedAsHashOperand.qlref b/c/misra/test/rules/RULE-20-12/MacroParameterUsedAsHashOperand.qlref deleted file mode 100644 index a2edc3acc4..0000000000 --- a/c/misra/test/rules/RULE-20-12/MacroParameterUsedAsHashOperand.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-20-12/MacroParameterUsedAsHashOperand.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-20-12/MacroParameterUsedAsHashOperand.testref b/c/misra/test/rules/RULE-20-12/MacroParameterUsedAsHashOperand.testref new file mode 100644 index 0000000000..d1cc5971c7 --- /dev/null +++ b/c/misra/test/rules/RULE-20-12/MacroParameterUsedAsHashOperand.testref @@ -0,0 +1 @@ +c/common/test/rules/amixedusemacroargumentsubjecttoexpansion/AMixedUseMacroArgumentSubjectToExpansion.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-20-12/test.c b/c/misra/test/rules/RULE-20-12/test.c deleted file mode 100644 index 768238f36d..0000000000 --- a/c/misra/test/rules/RULE-20-12/test.c +++ /dev/null @@ -1,25 +0,0 @@ - -#define GOOD_MACRO_WITH_ARG(X) ((X)*X##_scale) // COMPLIANT -#define MACRO 1 -#define BAD_MACRO_WITH_ARG(x) (x) + wow##x // NON_COMPLIANT -#define BAD_MACRO_WITH_ARG_TWO(x, y) (x) + wow##x // NON_COMPLIANT -#define MACROONE(x) #x // COMPLIANT -#define MACROTWO(x) x *x // COMPLIANT -#define MACROTHREE(x) "##\"\"'" + (x) // COMPLIANT -#define FOO(x) #x MACROONE(x) // COMPLIANT - no further arg expansion - -void f() { - - int x; - int x_scale; - int y; - int wowMACRO = 0; - - y = GOOD_MACRO_WITH_ARG(x); - wowMACRO = BAD_MACRO_WITH_ARG(MACRO); - wowMACRO = BAD_MACRO_WITH_ARG_TWO(MACRO, 1); - char s[] = MACROONE(MACRO); - y = MACROTWO(MACRO); - MACROTHREE(MACRO); - FOO(x); -} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.expected b/c/misra/test/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.expected index 747b25a2c1..8032bf38cc 100644 --- a/c/misra/test/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.expected +++ b/c/misra/test/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.expected @@ -1,12 +1,16 @@ -| test.c:4:11:4:23 | call to feclearexcept | Call to banned function feclearexcept. | -| test.c:4:25:4:34 | FE_INVALID | Call to banned macro FE_INVALID. | -| test.c:6:3:6:17 | call to fegetexceptflag | Call to banned function fegetexceptflag. | -| test.c:6:24:6:36 | FE_ALL_EXCEPT | Call to banned macro FE_ALL_EXCEPT. | -| test.c:7:3:7:15 | call to feraiseexcept | Call to banned function feraiseexcept. | -| test.c:7:17:7:28 | FE_DIVBYZERO | Call to banned macro FE_DIVBYZERO. | -| test.c:8:3:8:15 | call to feraiseexcept | Call to banned function feraiseexcept. | -| test.c:8:17:8:27 | FE_OVERFLOW | Call to banned macro FE_OVERFLOW. | -| test.c:9:3:9:17 | call to fesetexceptflag | Call to banned function fesetexceptflag. | -| test.c:9:24:9:36 | FE_ALL_EXCEPT | Call to banned macro FE_ALL_EXCEPT. | -| test.c:10:3:10:14 | call to fetestexcept | Call to banned function fetestexcept. | -| test.c:10:16:10:27 | FE_UNDERFLOW | Call to banned macro FE_UNDERFLOW. | +| test.c:2:1:2:17 | #include | Include of banned header 'fenv.h'. | +| test.c:6:11:6:23 | call to feclearexcept | Call to banned function 'feclearexcept'. | +| test.c:6:25:6:34 | FE_INVALID | Expansion of banned macro 'FE_INVALID'. | +| test.c:8:3:8:17 | call to fegetexceptflag | Call to banned function 'fegetexceptflag'. | +| test.c:8:24:8:36 | FE_ALL_EXCEPT | Expansion of banned macro 'FE_ALL_EXCEPT'. | +| test.c:9:3:9:15 | call to feraiseexcept | Call to banned function 'feraiseexcept'. | +| test.c:9:17:9:28 | FE_DIVBYZERO | Expansion of banned macro 'FE_DIVBYZERO'. | +| test.c:10:3:10:15 | call to feraiseexcept | Call to banned function 'feraiseexcept'. | +| test.c:10:17:10:27 | FE_OVERFLOW | Expansion of banned macro 'FE_OVERFLOW'. | +| test.c:11:3:11:17 | call to fesetexceptflag | Call to banned function 'fesetexceptflag'. | +| test.c:11:24:11:36 | FE_ALL_EXCEPT | Expansion of banned macro 'FE_ALL_EXCEPT'. | +| test.c:12:3:12:14 | call to fetestexcept | Call to banned function 'fetestexcept'. | +| test.c:12:16:12:27 | FE_UNDERFLOW | Expansion of banned macro 'FE_UNDERFLOW'. | +| test.c:15:3:15:10 | call to fesetenv | Call to banned function 'fesetenv'. | +| test.c:16:3:16:13 | call to feupdateenv | Call to banned function 'feupdateenv'. | +| test.c:17:3:17:12 | call to fesetround | Call to banned function 'fesetround'. | diff --git a/c/misra/test/rules/RULE-21-12/test.c b/c/misra/test/rules/RULE-21-12/test.c index ae4d90a402..9a049c9ed8 100644 --- a/c/misra/test/rules/RULE-21-12/test.c +++ b/c/misra/test/rules/RULE-21-12/test.c @@ -1,4 +1,6 @@ +// NON_COMPLIANT: Cannot #include fenv.h. #include + void f2(); void f1() { int i = feclearexcept(FE_INVALID); // NON_COMPLIANT @@ -8,5 +10,10 @@ void f1() { feraiseexcept(FE_OVERFLOW); // NON_COMPLIANT fesetexceptflag(&i2, FE_ALL_EXCEPT); // NON_COMPLIANT fetestexcept(FE_UNDERFLOW); // NON_COMPLIANT - f2(); // COMPLIANT + fenv_t env; + fegetenv(&env); + fesetenv(&env); // NON_COMPLIANT + feupdateenv(&env); // NON_COMPLIANT + fesetround(0); // NON_COMPLIANT + f2(); // COMPLIANT } diff --git a/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected b/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected index bdfec99b4a..5ae49919a9 100644 --- a/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected +++ b/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected @@ -1,10 +1,14 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:23,54-62) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:24,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:50,20-28) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:58,43-56) edges -| test.c:12:13:12:15 | a | test.c:14:10:14:10 | a | -| test.c:12:13:12:15 | a | test.c:23:13:23:13 | a | -| test.c:12:13:12:15 | a | test.c:24:10:24:10 | a | -| test.c:13:13:13:15 | b | test.c:14:13:14:13 | b | -| test.c:18:15:18:28 | {...} | test.c:21:10:21:10 | e | -| test.c:19:15:19:28 | {...} | test.c:21:13:21:13 | f | +| test.c:12:13:12:15 | a | test.c:14:10:14:10 | a | provenance | | +| test.c:12:13:12:15 | a | test.c:23:13:23:13 | a | provenance | | +| test.c:12:13:12:15 | a | test.c:24:10:24:10 | a | provenance | | +| test.c:13:13:13:15 | b | test.c:14:13:14:13 | b | provenance | | +| test.c:18:15:18:28 | {...} | test.c:21:10:21:10 | e | provenance | | +| test.c:19:15:19:28 | {...} | test.c:21:13:21:13 | f | provenance | | nodes | test.c:10:10:10:12 | a | semmle.label | a | | test.c:10:15:10:17 | b | semmle.label | b | diff --git a/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected new file mode 100644 index 0000000000..03dddb8dfe --- /dev/null +++ b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected @@ -0,0 +1,134 @@ +| test.c:29:7:29:7 | c | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:40:7:40:7 | e | Argument 1 provided to type-generic macro 'cos' has essentially enum type, which is not essentially signed, unsigned, or floating type. | +| test.c:41:7:41:7 | b | Argument 1 provided to type-generic macro 'cos' has essentially boolean type, which is not essentially signed, unsigned, or floating type. | +| test.c:156:8:156:8 | c | Argument 1 provided to type-generic macro 'acos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:157:9:157:9 | c | Argument 1 provided to type-generic macro 'acosh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:158:8:158:8 | c | Argument 1 provided to type-generic macro 'asin' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:159:9:159:9 | c | Argument 1 provided to type-generic macro 'asinh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:160:9:160:9 | c | Argument 1 provided to type-generic macro 'atan2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:161:12:161:12 | c | Argument 2 provided to type-generic macro 'atan2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:162:9:162:9 | c | Argument 1 provided to type-generic macro 'atanh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:163:8:163:8 | c | Argument 1 provided to type-generic macro 'carg' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:164:8:164:8 | c | Argument 1 provided to type-generic macro 'ceil' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:165:9:165:9 | c | Argument 1 provided to type-generic macro 'cimag' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:166:8:166:8 | c | Argument 1 provided to type-generic macro 'conj' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:167:15:167:15 | c | Argument 2 provided to type-generic macro 'copysign' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:168:12:168:12 | c | Argument 1 provided to type-generic macro 'copysign' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:169:8:169:8 | c | Argument 1 provided to type-generic macro 'cosh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:170:9:170:9 | c | Argument 1 provided to type-generic macro 'cproj' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:171:9:171:9 | c | Argument 1 provided to type-generic macro 'creal' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:172:7:172:7 | c | Argument 1 provided to type-generic macro 'erf' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:173:8:173:8 | c | Argument 1 provided to type-generic macro 'erfc' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:174:7:174:7 | c | Argument 1 provided to type-generic macro 'exp' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:175:8:175:8 | c | Argument 1 provided to type-generic macro 'exp2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:176:9:176:9 | c | Argument 1 provided to type-generic macro 'expm1' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:177:8:177:8 | c | Argument 1 provided to type-generic macro 'fabs' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:178:8:178:8 | c | Argument 1 provided to type-generic macro 'fdim' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:179:11:179:11 | c | Argument 2 provided to type-generic macro 'fdim' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:180:9:180:9 | c | Argument 1 provided to type-generic macro 'floor' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:181:7:181:7 | c | Argument 1 provided to type-generic macro 'fma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:182:10:182:10 | c | Argument 2 provided to type-generic macro 'fma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:183:13:183:13 | c | Argument 3 provided to type-generic macro 'fma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:184:8:184:8 | c | Argument 1 provided to type-generic macro 'fmax' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:185:11:185:11 | c | Argument 2 provided to type-generic macro 'fmax' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:186:8:186:8 | c | Argument 1 provided to type-generic macro 'fmin' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:187:11:187:11 | c | Argument 2 provided to type-generic macro 'fmin' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:188:8:188:8 | c | Argument 1 provided to type-generic macro 'fmod' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:189:11:189:11 | c | Argument 2 provided to type-generic macro 'fmod' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:190:9:190:9 | c | Argument 1 provided to type-generic macro 'frexp' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:191:9:191:9 | c | Argument 1 provided to type-generic macro 'hypot' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:192:12:192:12 | c | Argument 2 provided to type-generic macro 'hypot' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:193:9:193:9 | c | Argument 1 provided to type-generic macro 'ilogb' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:194:9:194:9 | c | Argument 1 provided to type-generic macro 'ldexp' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:195:12:195:12 | c | Argument 2 provided to type-generic macro 'ldexp' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:196:10:196:10 | c | Argument 1 provided to type-generic macro 'lgamma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:197:10:197:10 | c | Argument 1 provided to type-generic macro 'llrint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:198:11:198:11 | c | Argument 1 provided to type-generic macro 'llround' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:199:7:199:7 | c | Argument 1 provided to type-generic macro 'log' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:200:9:200:9 | c | Argument 1 provided to type-generic macro 'log10' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:201:9:201:9 | c | Argument 1 provided to type-generic macro 'log1p' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:202:8:202:8 | c | Argument 1 provided to type-generic macro 'log2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:203:8:203:8 | c | Argument 1 provided to type-generic macro 'logb' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:204:9:204:9 | c | Argument 1 provided to type-generic macro 'lrint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:205:10:205:10 | c | Argument 1 provided to type-generic macro 'lround' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:206:13:206:13 | c | Argument 1 provided to type-generic macro 'nearbyint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:207:13:207:13 | c | Argument 1 provided to type-generic macro 'nextafter' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:208:16:208:16 | c | Argument 2 provided to type-generic macro 'nextafter' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:209:14:209:14 | c | Argument 1 provided to type-generic macro 'nexttoward' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:210:17:210:17 | c | Argument 2 provided to type-generic macro 'nexttoward' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:211:7:211:7 | c | Argument 1 provided to type-generic macro 'pow' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:212:10:212:10 | c | Argument 2 provided to type-generic macro 'pow' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:213:13:213:13 | c | Argument 1 provided to type-generic macro 'remainder' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:214:16:214:16 | c | Argument 2 provided to type-generic macro 'remainder' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:215:10:215:10 | c | Argument 1 provided to type-generic macro 'remquo' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:216:13:216:13 | c | Argument 2 provided to type-generic macro 'remquo' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:217:8:217:8 | c | Argument 1 provided to type-generic macro 'rint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:218:9:218:9 | c | Argument 1 provided to type-generic macro 'round' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:219:10:219:10 | c | Argument 1 provided to type-generic macro 'scalbn' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:220:13:220:13 | c | Argument 2 provided to type-generic macro 'scalbn' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:221:11:221:11 | c | Argument 1 provided to type-generic macro 'scalbln' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:222:14:222:14 | c | Argument 2 provided to type-generic macro 'scalbln' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:223:7:223:7 | c | Argument 1 provided to type-generic macro 'sin' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:224:8:224:8 | c | Argument 1 provided to type-generic macro 'sinh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:225:8:225:8 | c | Argument 1 provided to type-generic macro 'sqrt' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:226:7:226:7 | c | Argument 1 provided to type-generic macro 'tan' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:227:8:227:8 | c | Argument 1 provided to type-generic macro 'tanh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:228:10:228:10 | c | Argument 1 provided to type-generic macro 'tgamma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:229:9:229:9 | c | Argument 1 provided to type-generic macro 'trunc' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:239:9:239:10 | cf | Argument 1 provided to type-generic macro 'atan2' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:240:12:240:13 | cf | Argument 2 provided to type-generic macro 'atan2' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:243:8:243:9 | cf | Argument 1 provided to type-generic macro 'cbrt' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:244:8:244:9 | cf | Argument 1 provided to type-generic macro 'ceil' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:247:15:247:16 | cf | Argument 2 provided to type-generic macro 'copysign' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:248:12:248:13 | cf | Argument 1 provided to type-generic macro 'copysign' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:249:15:249:16 | cf | Argument 2 provided to type-generic macro 'copysign' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:254:7:254:8 | cf | Argument 1 provided to type-generic macro 'erf' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:255:8:255:9 | cf | Argument 1 provided to type-generic macro 'erfc' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:257:8:257:9 | cf | Argument 1 provided to type-generic macro 'exp2' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:258:9:258:10 | cf | Argument 1 provided to type-generic macro 'expm1' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:260:8:260:9 | cf | Argument 1 provided to type-generic macro 'fdim' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:261:11:261:12 | cf | Argument 2 provided to type-generic macro 'fdim' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:262:9:262:10 | cf | Argument 1 provided to type-generic macro 'floor' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:263:7:263:8 | cf | Argument 1 provided to type-generic macro 'fma' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:264:10:264:11 | cf | Argument 2 provided to type-generic macro 'fma' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:265:13:265:14 | cf | Argument 3 provided to type-generic macro 'fma' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:266:8:266:9 | cf | Argument 1 provided to type-generic macro 'fmax' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:267:11:267:12 | cf | Argument 2 provided to type-generic macro 'fmax' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:268:8:268:9 | cf | Argument 1 provided to type-generic macro 'fmin' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:269:11:269:12 | cf | Argument 2 provided to type-generic macro 'fmin' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:270:8:270:9 | cf | Argument 1 provided to type-generic macro 'fmod' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:271:11:271:12 | cf | Argument 2 provided to type-generic macro 'fmod' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:272:9:272:10 | cf | Argument 1 provided to type-generic macro 'frexp' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:273:9:273:10 | cf | Argument 1 provided to type-generic macro 'hypot' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:274:12:274:13 | cf | Argument 2 provided to type-generic macro 'hypot' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:275:9:275:10 | cf | Argument 1 provided to type-generic macro 'ilogb' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:276:9:276:10 | cf | Argument 1 provided to type-generic macro 'ldexp' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:277:12:277:13 | cf | Argument 2 provided to type-generic macro 'ldexp' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:278:10:278:11 | cf | Argument 1 provided to type-generic macro 'lgamma' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:279:10:279:11 | cf | Argument 1 provided to type-generic macro 'llrint' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:280:11:280:12 | cf | Argument 1 provided to type-generic macro 'llround' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:282:9:282:10 | cf | Argument 1 provided to type-generic macro 'log10' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:283:9:283:10 | cf | Argument 1 provided to type-generic macro 'log1p' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:284:8:284:9 | cf | Argument 1 provided to type-generic macro 'log2' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:285:8:285:9 | cf | Argument 1 provided to type-generic macro 'logb' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:286:9:286:10 | cf | Argument 1 provided to type-generic macro 'lrint' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:287:10:287:11 | cf | Argument 1 provided to type-generic macro 'lround' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:288:13:288:14 | cf | Argument 1 provided to type-generic macro 'nearbyint' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:289:13:289:14 | cf | Argument 1 provided to type-generic macro 'nextafter' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:290:16:290:17 | cf | Argument 2 provided to type-generic macro 'nextafter' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:291:14:291:15 | cf | Argument 1 provided to type-generic macro 'nexttoward' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:292:17:292:18 | cf | Argument 2 provided to type-generic macro 'nexttoward' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:294:13:294:14 | cf | Argument 1 provided to type-generic macro 'remainder' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:295:16:295:17 | cf | Argument 2 provided to type-generic macro 'remainder' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:296:10:296:11 | cf | Argument 1 provided to type-generic macro 'remquo' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:297:13:297:14 | cf | Argument 2 provided to type-generic macro 'remquo' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:298:8:298:9 | cf | Argument 1 provided to type-generic macro 'rint' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:299:9:299:10 | cf | Argument 1 provided to type-generic macro 'round' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:300:10:300:11 | cf | Argument 1 provided to type-generic macro 'scalbn' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:301:13:301:14 | cf | Argument 2 provided to type-generic macro 'scalbn' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:302:11:302:12 | cf | Argument 1 provided to type-generic macro 'scalbln' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:303:14:303:15 | cf | Argument 2 provided to type-generic macro 'scalbln' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:309:10:309:11 | cf | Argument 1 provided to type-generic macro 'tgamma' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:310:9:310:10 | cf | Argument 1 provided to type-generic macro 'trunc' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:325:13:325:13 | i | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:328:18:328:18 | c | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | diff --git a/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected.clang b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected.clang new file mode 100644 index 0000000000..313438ea6c --- /dev/null +++ b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected.clang @@ -0,0 +1,76 @@ +| test.c:29:7:29:7 | c | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:40:7:40:7 | e | Argument 1 provided to type-generic macro 'cos' has essentially enum type, which is not essentially signed, unsigned, or floating type. | +| test.c:41:7:41:7 | b | Argument 1 provided to type-generic macro 'cos' has essentially boolean type, which is not essentially signed, unsigned, or floating type. | +| test.c:156:8:156:8 | c | Argument 1 provided to type-generic macro 'acos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:157:9:157:9 | c | Argument 1 provided to type-generic macro 'acosh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:158:8:158:8 | c | Argument 1 provided to type-generic macro 'asin' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:159:9:159:9 | c | Argument 1 provided to type-generic macro 'asinh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:160:9:160:9 | c | Argument 1 provided to type-generic macro 'atan2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:161:12:161:12 | c | Argument 2 provided to type-generic macro 'atan2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:162:9:162:9 | c | Argument 1 provided to type-generic macro 'atanh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:163:8:163:8 | c | Argument 1 provided to type-generic macro 'carg' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:164:8:164:8 | c | Argument 1 provided to type-generic macro 'ceil' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:165:9:165:9 | c | Argument 1 provided to type-generic macro 'cimag' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:166:8:166:8 | c | Argument 1 provided to type-generic macro 'conj' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:167:15:167:15 | c | Argument 2 provided to type-generic macro 'copysign' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:168:12:168:12 | c | Argument 1 provided to type-generic macro 'copysign' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:169:8:169:8 | c | Argument 1 provided to type-generic macro 'cosh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:170:9:170:9 | c | Argument 1 provided to type-generic macro 'cproj' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:171:9:171:9 | c | Argument 1 provided to type-generic macro 'creal' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:172:7:172:7 | c | Argument 1 provided to type-generic macro 'erf' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:173:8:173:8 | c | Argument 1 provided to type-generic macro 'erfc' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:174:7:174:7 | c | Argument 1 provided to type-generic macro 'exp' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:175:8:175:8 | c | Argument 1 provided to type-generic macro 'exp2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:176:9:176:9 | c | Argument 1 provided to type-generic macro 'expm1' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:177:8:177:8 | c | Argument 1 provided to type-generic macro 'fabs' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:178:8:178:8 | c | Argument 1 provided to type-generic macro 'fdim' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:179:11:179:11 | c | Argument 2 provided to type-generic macro 'fdim' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:180:9:180:9 | c | Argument 1 provided to type-generic macro 'floor' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:181:7:181:7 | c | Argument 1 provided to type-generic macro 'fma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:182:10:182:10 | c | Argument 2 provided to type-generic macro 'fma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:183:13:183:13 | c | Argument 3 provided to type-generic macro 'fma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:184:8:184:8 | c | Argument 1 provided to type-generic macro 'fmax' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:185:11:185:11 | c | Argument 2 provided to type-generic macro 'fmax' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:186:8:186:8 | c | Argument 1 provided to type-generic macro 'fmin' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:187:11:187:11 | c | Argument 2 provided to type-generic macro 'fmin' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:188:8:188:8 | c | Argument 1 provided to type-generic macro 'fmod' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:189:11:189:11 | c | Argument 2 provided to type-generic macro 'fmod' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:191:9:191:9 | c | Argument 1 provided to type-generic macro 'hypot' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:192:12:192:12 | c | Argument 2 provided to type-generic macro 'hypot' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:193:9:193:9 | c | Argument 1 provided to type-generic macro 'ilogb' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:194:9:194:9 | c | Argument 1 provided to type-generic macro 'ldexp' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:195:12:195:12 | c | Argument 2 provided to type-generic macro 'ldexp' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:196:10:196:10 | c | Argument 1 provided to type-generic macro 'lgamma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:197:10:197:10 | c | Argument 1 provided to type-generic macro 'llrint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:198:11:198:11 | c | Argument 1 provided to type-generic macro 'llround' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:199:7:199:7 | c | Argument 1 provided to type-generic macro 'log' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:200:9:200:9 | c | Argument 1 provided to type-generic macro 'log10' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:201:9:201:9 | c | Argument 1 provided to type-generic macro 'log1p' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:202:8:202:8 | c | Argument 1 provided to type-generic macro 'log2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:203:8:203:8 | c | Argument 1 provided to type-generic macro 'logb' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:204:9:204:9 | c | Argument 1 provided to type-generic macro 'lrint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:205:10:205:10 | c | Argument 1 provided to type-generic macro 'lround' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:206:13:206:13 | c | Argument 1 provided to type-generic macro 'nearbyint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:207:13:207:13 | c | Argument 1 provided to type-generic macro 'nextafter' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:208:16:208:16 | c | Argument 2 provided to type-generic macro 'nextafter' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:209:14:209:14 | c | Argument 1 provided to type-generic macro 'nexttoward' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:210:17:210:17 | c | Argument 2 provided to type-generic macro 'nexttoward' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:211:7:211:7 | c | Argument 1 provided to type-generic macro 'pow' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:212:10:212:10 | c | Argument 2 provided to type-generic macro 'pow' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:213:13:213:13 | c | Argument 1 provided to type-generic macro 'remainder' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:214:16:214:16 | c | Argument 2 provided to type-generic macro 'remainder' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:217:8:217:8 | c | Argument 1 provided to type-generic macro 'rint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:218:9:218:9 | c | Argument 1 provided to type-generic macro 'round' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:219:10:219:10 | c | Argument 1 provided to type-generic macro 'scalbn' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:220:13:220:13 | c | Argument 2 provided to type-generic macro 'scalbn' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:221:11:221:11 | c | Argument 1 provided to type-generic macro 'scalbln' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:222:14:222:14 | c | Argument 2 provided to type-generic macro 'scalbln' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:223:7:223:7 | c | Argument 1 provided to type-generic macro 'sin' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:224:8:224:8 | c | Argument 1 provided to type-generic macro 'sinh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:225:8:225:8 | c | Argument 1 provided to type-generic macro 'sqrt' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:226:7:226:7 | c | Argument 1 provided to type-generic macro 'tan' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:227:8:227:8 | c | Argument 1 provided to type-generic macro 'tanh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:228:10:228:10 | c | Argument 1 provided to type-generic macro 'tgamma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:229:9:229:9 | c | Argument 1 provided to type-generic macro 'trunc' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:325:14:325:14 | i | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:328:20:328:20 | c | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | diff --git a/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected.gcc b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected.gcc new file mode 100644 index 0000000000..79b070ae84 --- /dev/null +++ b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected.gcc @@ -0,0 +1,79 @@ +| test.c:29:7:29:7 | c | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:40:7:40:7 | e | Argument 1 provided to type-generic macro 'cos' has essentially enum type, which is not essentially signed, unsigned, or floating type. | +| test.c:41:7:41:7 | b | Argument 1 provided to type-generic macro 'cos' has essentially boolean type, which is not essentially signed, unsigned, or floating type. | +| test.c:156:8:156:8 | c | Argument 1 provided to type-generic macro 'acos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:157:9:157:9 | c | Argument 1 provided to type-generic macro 'acosh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:158:8:158:8 | c | Argument 1 provided to type-generic macro 'asin' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:159:9:159:9 | c | Argument 1 provided to type-generic macro 'asinh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:160:9:160:9 | c | Argument 1 provided to type-generic macro 'atan2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:161:12:161:12 | c | Argument 2 provided to type-generic macro 'atan2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:162:9:162:9 | c | Argument 1 provided to type-generic macro 'atanh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:163:8:163:8 | c | Argument 1 provided to type-generic macro 'carg' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:164:8:164:8 | c | Argument 1 provided to type-generic macro 'ceil' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:165:9:165:9 | c | Argument 1 provided to type-generic macro 'cimag' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:166:8:166:8 | c | Argument 1 provided to type-generic macro 'conj' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:167:15:167:15 | c | Argument 2 provided to type-generic macro 'copysign' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:168:12:168:12 | c | Argument 1 provided to type-generic macro 'copysign' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:169:8:169:8 | c | Argument 1 provided to type-generic macro 'cosh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:170:9:170:9 | c | Argument 1 provided to type-generic macro 'cproj' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:171:9:171:9 | c | Argument 1 provided to type-generic macro 'creal' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:172:7:172:7 | c | Argument 1 provided to type-generic macro 'erf' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:173:8:173:8 | c | Argument 1 provided to type-generic macro 'erfc' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:174:7:174:7 | c | Argument 1 provided to type-generic macro 'exp' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:175:8:175:8 | c | Argument 1 provided to type-generic macro 'exp2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:176:9:176:9 | c | Argument 1 provided to type-generic macro 'expm1' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:177:8:177:8 | c | Argument 1 provided to type-generic macro 'fabs' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:178:8:178:8 | c | Argument 1 provided to type-generic macro 'fdim' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:179:11:179:11 | c | Argument 2 provided to type-generic macro 'fdim' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:180:9:180:9 | c | Argument 1 provided to type-generic macro 'floor' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:181:7:181:7 | c | Argument 1 provided to type-generic macro 'fma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:182:10:182:10 | c | Argument 2 provided to type-generic macro 'fma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:183:13:183:13 | c | Argument 3 provided to type-generic macro 'fma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:184:8:184:8 | c | Argument 1 provided to type-generic macro 'fmax' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:185:11:185:11 | c | Argument 2 provided to type-generic macro 'fmax' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:186:8:186:8 | c | Argument 1 provided to type-generic macro 'fmin' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:187:11:187:11 | c | Argument 2 provided to type-generic macro 'fmin' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:188:8:188:8 | c | Argument 1 provided to type-generic macro 'fmod' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:189:11:189:11 | c | Argument 2 provided to type-generic macro 'fmod' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:190:9:190:9 | c | Argument 1 provided to type-generic macro 'frexp' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:191:9:191:9 | c | Argument 1 provided to type-generic macro 'hypot' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:192:12:192:12 | c | Argument 2 provided to type-generic macro 'hypot' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:193:9:193:9 | c | Argument 1 provided to type-generic macro 'ilogb' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:194:9:194:9 | c | Argument 1 provided to type-generic macro 'ldexp' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:195:12:195:12 | c | Argument 2 provided to type-generic macro 'ldexp' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:196:10:196:10 | c | Argument 1 provided to type-generic macro 'lgamma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:197:10:197:10 | c | Argument 1 provided to type-generic macro 'llrint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:198:11:198:11 | c | Argument 1 provided to type-generic macro 'llround' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:199:7:199:7 | c | Argument 1 provided to type-generic macro 'log' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:200:9:200:9 | c | Argument 1 provided to type-generic macro 'log10' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:201:9:201:9 | c | Argument 1 provided to type-generic macro 'log1p' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:202:8:202:8 | c | Argument 1 provided to type-generic macro 'log2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:203:8:203:8 | c | Argument 1 provided to type-generic macro 'logb' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:204:9:204:9 | c | Argument 1 provided to type-generic macro 'lrint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:205:10:205:10 | c | Argument 1 provided to type-generic macro 'lround' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:206:13:206:13 | c | Argument 1 provided to type-generic macro 'nearbyint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:207:13:207:13 | c | Argument 1 provided to type-generic macro 'nextafter' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:208:16:208:16 | c | Argument 2 provided to type-generic macro 'nextafter' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:209:14:209:14 | c | Argument 1 provided to type-generic macro 'nexttoward' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:210:17:210:17 | c | Argument 2 provided to type-generic macro 'nexttoward' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:211:7:211:7 | c | Argument 1 provided to type-generic macro 'pow' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:212:10:212:10 | c | Argument 2 provided to type-generic macro 'pow' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:213:13:213:13 | c | Argument 1 provided to type-generic macro 'remainder' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:214:16:214:16 | c | Argument 2 provided to type-generic macro 'remainder' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:215:10:215:10 | c | Argument 1 provided to type-generic macro 'remquo' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:216:13:216:13 | c | Argument 2 provided to type-generic macro 'remquo' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:217:8:217:8 | c | Argument 1 provided to type-generic macro 'rint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:218:9:218:9 | c | Argument 1 provided to type-generic macro 'round' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:219:10:219:10 | c | Argument 1 provided to type-generic macro 'scalbn' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:220:13:220:13 | c | Argument 2 provided to type-generic macro 'scalbn' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:221:11:221:11 | c | Argument 1 provided to type-generic macro 'scalbln' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:222:14:222:14 | c | Argument 2 provided to type-generic macro 'scalbln' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:223:7:223:7 | c | Argument 1 provided to type-generic macro 'sin' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:224:8:224:8 | c | Argument 1 provided to type-generic macro 'sinh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:225:8:225:8 | c | Argument 1 provided to type-generic macro 'sqrt' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:226:7:226:7 | c | Argument 1 provided to type-generic macro 'tan' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:227:8:227:8 | c | Argument 1 provided to type-generic macro 'tanh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:228:10:228:10 | c | Argument 1 provided to type-generic macro 'tgamma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:229:9:229:9 | c | Argument 1 provided to type-generic macro 'trunc' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:325:14:325:14 | i | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:328:20:328:20 | c | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | diff --git a/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.qlref b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.qlref new file mode 100644 index 0000000000..cb7206db11 --- /dev/null +++ b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.qlref @@ -0,0 +1 @@ +rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-22/test.c b/c/misra/test/rules/RULE-21-22/test.c new file mode 100644 index 0000000000..970df4fd56 --- /dev/null +++ b/c/misra/test/rules/RULE-21-22/test.c @@ -0,0 +1,329 @@ +#include +#include +#include +#include + +void f1() { + int i = 0; + unsigned int ui = 0; + short s = 0; + unsigned short us = 0; + char c = 0; + unsigned char uc = 0; + signed char sc = 0; + long l = 0; + unsigned long ul = 0; + float f = 0.0f; + float _Complex cf = 0.0f + 0.0f * I; + double d = 0.0; + char *p = 0; + void *vp = 0; + uintptr_t uip = p; + enum { e1 } e = e1; + bool b = true; + + cos(i); // COMPLIANT + cos(ui); // COMPLIANT + cos(s); // COMPLIANT + cos(us); // COMPLIANT + cos(c); // NON-COMPLIANT + cos(uc); // COMPLIANT + cos(sc); // COMPLIANT + cos(l); // COMPLIANT + cos(ul); // COMPLIANT + cos(f); // COMPLIANT + cos(cf); // COMPLIANT + cos(d); // COMPLIANT + // cos(p); // Doesn't compile + // cos(vp); // Doesn't compile + cos(uip); // COMPLIANT + cos(e); // NON-COMPLIANT + cos(b); // NON-COMPLIANT + cos(1); // COMPLIANT + cos(1.1f); // COMPLIANT + cos('a'); // NON-COMPLIANT[false negative] + + /** + * Int, float, and complex allowed: + */ + acos(i); // COMPLIANT + acos(f); // COMPLIANT + acosh(i); // COMPLIANT + acosh(f); // COMPLIANT + asin(i); // COMPLIANT + asin(f); // COMPLIANT + asinh(i); // COMPLIANT + asinh(f); // COMPLIANT + atan(i); // COMPLIANT + atan(f); // COMPLIANT + atan2(i, i); // COMPLIANT + atan2(f, f); // COMPLIANT + atanh(i); // COMPLIANT + atanh(f); // COMPLIANT + carg(i); // COMPLIANT + carg(f); // COMPLIANT + cbrt(i); // COMPLIANT + cbrt(f); // COMPLIANT + ceil(i); // COMPLIANT + ceil(f); // COMPLIANT + cimag(i); // COMPLIANT + cimag(f); // COMPLIANT + conj(i); // COMPLIANT + conj(f); // COMPLIANT + copysign(i, i); // COMPLIANT + copysign(f, f); // COMPLIANT + cos(i); // COMPLIANT + cos(f); // COMPLIANT + cosh(i); // COMPLIANT + cosh(f); // COMPLIANT + cproj(i); // COMPLIANT + cproj(f); // COMPLIANT + creal(i); // COMPLIANT + creal(f); // COMPLIANT + erf(i); // COMPLIANT + erf(f); // COMPLIANT + erfc(i); // COMPLIANT + erfc(f); // COMPLIANT + exp(i); // COMPLIANT + exp(f); // COMPLIANT + exp2(i); // COMPLIANT + exp2(f); // COMPLIANT + expm1(i); // COMPLIANT + expm1(f); // COMPLIANT + fabs(i); // COMPLIANT + fabs(f); // COMPLIANT + fdim(i, i); // COMPLIANT + fdim(f, f); // COMPLIANT + floor(i); // COMPLIANT + floor(f); // COMPLIANT + fma(i, i, i); // COMPLIANT + fma(f, f, f); // COMPLIANT + fmax(i, i); // COMPLIANT + fmax(f, f); // COMPLIANT + fmin(i, i); // COMPLIANT + fmin(f, f); // COMPLIANT + fmod(i, i); // COMPLIANT + fmod(f, f); // COMPLIANT + frexp(i, &i); // COMPLIANT + frexp(f, &p); // COMPLIANT + hypot(i, i); // COMPLIANT + hypot(f, f); // COMPLIANT + ilogb(i); // COMPLIANT + ilogb(f); // COMPLIANT + llrint(i); // COMPLIANT + llrint(f); // COMPLIANT + ldexp(i, i); // COMPLIANT + ldexp(f, f); // COMPLIANT + lgamma(i); // COMPLIANT + lgamma(f); // COMPLIANT + llround(i); // COMPLIANT + llround(f); // COMPLIANT + log(i); // COMPLIANT + log(f); // COMPLIANT + pow(i, i); // COMPLIANT + pow(f, f); // COMPLIANT + remainder(i, i); // COMPLIANT + remainder(f, f); // COMPLIANT + remquo(i, i, &i); // COMPLIANT + remquo(f, f, &f); // COMPLIANT + rint(i); // COMPLIANT + rint(f); // COMPLIANT + round(i); // COMPLIANT + round(f); // COMPLIANT + scalbn(i, i); // COMPLIANT + scalbn(f, f); // COMPLIANT + scalbln(i, i); // COMPLIANT + scalbln(f, f); // COMPLIANT + sin(i); // COMPLIANT + sin(f); // COMPLIANT + sin(cf); // COMPLIANT + sinh(i); // COMPLIANT + sinh(f); // COMPLIANT + sqrt(i); // COMPLIANT + sqrt(f); // COMPLIANT + tan(i); // COMPLIANT + tan(f); // COMPLIANT + tanh(i); // COMPLIANT + tanh(f); // COMPLIANT + tgamma(i); // COMPLIANT + tgamma(f); // COMPLIANT + trunc(i); // COMPLIANT + trunc(f); // COMPLIANT + + /** + * Char not allowed: + */ + acos(c); // NON-COMPLIANT + acosh(c); // NON-COMPLIANT + asin(c); // NON-COMPLIANT + asinh(c); // NON-COMPLIANT + atan2(c, i); // NON-COMPLIANT + atan2(i, c); // NON-COMPLIANT + atanh(c); // NON-COMPLIANT + carg(c); // NON-COMPLIANT + ceil(c); // NON-COMPLIANT + cimag(c); // NON-COMPLIANT + conj(c); // NON-COMPLIANT + copysign(i, c); // NON-COMPLIANT + copysign(c, i); // NON-COMPLIANT + cosh(c); // NON-COMPLIANT + cproj(c); // NON-COMPLIANT + creal(c); // NON-COMPLIANT + erf(c); // NON-COMPLIANT + erfc(c); // NON-COMPLIANT + exp(c); // NON-COMPLIANT + exp2(c); // NON-COMPLIANT + expm1(c); // NON-COMPLIANT + fabs(c); // NON-COMPLIANT + fdim(c, i); // NON-COMPLIANT + fdim(i, c); // NON-COMPLIANT + floor(c); // NON-COMPLIANT + fma(c, i, i); // NON-COMPLIANT + fma(i, c, i); // NON-COMPLIANT + fma(i, i, c); // NON-COMPLIANT + fmax(c, i); // NON-COMPLIANT + fmax(i, c); // NON-COMPLIANT + fmin(c, i); // NON-COMPLIANT + fmin(i, c); // NON-COMPLIANT + fmod(c, i); // NON-COMPLIANT + fmod(i, c); // NON-COMPLIANT + frexp(c, i); // NON-COMPLIANT + hypot(c, i); // NON-COMPLIANT + hypot(i, c); // NON-COMPLIANT + ilogb(c); // NON-COMPLIANT + ldexp(c, i); // NON-COMPLIANT + ldexp(i, c); // NON-COMPLIANT + lgamma(c); // NON-COMPLIANT + llrint(c); // NON-COMPLIANT + llround(c); // NON-COMPLIANT + log(c); // NON-COMPLIANT + log10(c); // NON-COMPLIANT + log1p(c); // NON-COMPLIANT + log2(c); // NON-COMPLIANT + logb(c); // NON-COMPLIANT + lrint(c); // NON-COMPLIANT + lround(c); // NON-COMPLIANT + nearbyint(c); // NON-COMPLIANT + nextafter(c, i); // NON-COMPLIANT + nextafter(i, c); // NON-COMPLIANT + nexttoward(c, i); // NON-COMPLIANT + nexttoward(i, c); // NON-COMPLIANT + pow(c, i); // NON-COMPLIANT + pow(i, c); // NON-COMPLIANT + remainder(c, i); // NON-COMPLIANT + remainder(i, c); // NON-COMPLIANT + remquo(c, i, i); // NON-COMPLIANT + remquo(i, c, i); // NON-COMPLIANT + rint(c); // NON-COMPLIANT + round(c); // NON-COMPLIANT + scalbn(c, i); // NON-COMPLIANT + scalbn(i, c); // NON-COMPLIANT + scalbln(c, i); // NON-COMPLIANT + scalbln(i, c); // NON-COMPLIANT + sin(c); // NON-COMPLIANT + sinh(c); // NON-COMPLIANT + sqrt(c); // NON-COMPLIANT + tan(c); // NON-COMPLIANT + tanh(c); // NON-COMPLIANT + tgamma(c); // NON-COMPLIANT + trunc(c); // NON-COMPLIANT + + /** + * Complex types allowed in some calls, not others: + */ + acos(cf); // COMPLIANT + acosh(cf); // COMPLIANT + asin(cf); // COMPLIANT + asinh(cf); // COMPLIANT + atan(cf); // COMPLIANT + atan2(cf, i); // NON-COMPLIANT + atan2(i, cf); // NON-COMPLIANT + atanh(cf); // COMPLIANT + carg(cf); // COMPLIANT + cbrt(cf); // NON-COMPLIANT + ceil(cf); // NON-COMPLIANT + cimag(cf); // COMPLIANT + conj(cf); // COMPLIANT + copysign(i, cf); // NON-COMPLIANT + copysign(cf, i); // NON-COMPLIANT + copysign(i, cf); // NON-COMPLIANT + cos(cf); // COMPLIANT + cosh(cf); // COMPLIANT + cproj(cf); // COMPLIANT + creal(cf); // COMPLIANT + erf(cf); // NON-COMPLIANT + erfc(cf); // NON-COMPLIANT + exp(cf); // COMPLIANT + exp2(cf); // NON-COMPLIANT + expm1(cf); // NON-COMPLIANT + fabs(cf); // COMPLIANT + fdim(cf, i); // NON-COMPLIANT + fdim(i, cf); // NON-COMPLIANT + floor(cf); // NON-COMPLIANT + fma(cf, i, i); // NON-COMPLIANT + fma(i, cf, i); // NON-COMPLIANT + fma(i, i, cf); // NON-COMPLIANT + fmax(cf, i); // NON-COMPLIANT + fmax(i, cf); // NON-COMPLIANT + fmin(cf, i); // NON-COMPLIANT + fmin(i, cf); // NON-COMPLIANT + fmod(cf, i); // NON-COMPLIANT + fmod(i, cf); // NON-COMPLIANT + frexp(cf, i); // NON-COMPLIANT + hypot(cf, i); // NON-COMPLIANT + hypot(i, cf); // NON-COMPLIANT + ilogb(cf); // NON-COMPLIANT + ldexp(cf, i); // NON-COMPLIANT + ldexp(i, cf); // NON-COMPLIANT + lgamma(cf); // NON-COMPLIANT + llrint(cf); // NON-COMPLIANT + llround(cf); // NON-COMPLIANT + log(cf); // COMPLIANT + log10(cf); // NON-COMPLIANT + log1p(cf); // NON-COMPLIANT + log2(cf); // NON-COMPLIANT + logb(cf); // NON-COMPLIANT + lrint(cf); // NON-COMPLIANT + lround(cf); // NON-COMPLIANT + nearbyint(cf); // NON-COMPLIANT + nextafter(cf, i); // NON-COMPLIANT + nextafter(i, cf); // NON-COMPLIANT + nexttoward(cf, i); // NON-COMPLIANT + nexttoward(i, cf); // NON-COMPLIANT + pow(cf, cf); // COMPLIANT + remainder(cf, i); // NON-COMPLIANT + remainder(i, cf); // NON-COMPLIANT + remquo(cf, i, i); // NON-COMPLIANT + remquo(i, cf, i); // NON-COMPLIANT + rint(cf); // NON-COMPLIANT + round(cf); // NON-COMPLIANT + scalbn(cf, i); // NON-COMPLIANT + scalbn(i, cf); // NON-COMPLIANT + scalbln(cf, i); // NON-COMPLIANT + scalbln(i, cf); // NON-COMPLIANT + sin(cf); // COMPLIANT + sinh(cf); // COMPLIANT + sqrt(cf); // COMPLIANT + tan(cf); // COMPLIANT + tanh(cf); // COMPLIANT + tgamma(cf); // NON-COMPLIANT + trunc(cf); // NON-COMPLIANT + + /* Test output arguments thoroughly */ + frexp(i, &i); // COMPLIANT + frexp(i, vp); // COMPLIANT + frexp(i, 0); // COMPLIANT + frexp(i, 'c' - 'c'); // COMPLIANT + frexp(i, c); // COMPLIANT + remquo(i, i, &i); // COMPLIANT + remquo(i, i, vp); // COMPLIANT + remquo(i, i, 0); // COMPLIANT + remquo(i, i, 'c' - 'c'); // COMPLIANT + remquo(i, i, c); // COMPLIANT + + /* Test casts */ + cos((char)i); // NON-COMPLIANT + cos((int)c); // COMPLIANT + cos((int)(char)i); // COMPLIANT + cos((char)(int)c); // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-22/test.c.clang b/c/misra/test/rules/RULE-21-22/test.c.clang new file mode 100644 index 0000000000..d28576e058 --- /dev/null +++ b/c/misra/test/rules/RULE-21-22/test.c.clang @@ -0,0 +1,329 @@ +#include +#include +#include +#include + +void f1() { + int i = 0; + unsigned int ui = 0; + short s = 0; + unsigned short us = 0; + char c = 0; + unsigned char uc = 0; + signed char sc = 0; + long l = 0; + unsigned long ul = 0; + float f = 0.0f; + float _Complex cf = 0.0f + 0.0f * I; + double d = 0.0; + char *p = 0; + void *vp = 0; + uintptr_t uip = p; + enum { e1 } e = e1; + bool b = true; + + cos(i); // COMPLIANT + cos(ui); // COMPLIANT + cos(s); // COMPLIANT + cos(us); // COMPLIANT + cos(c); // NON-COMPLIANT + cos(uc); // COMPLIANT + cos(sc); // COMPLIANT + cos(l); // COMPLIANT + cos(ul); // COMPLIANT + cos(f); // COMPLIANT + cos(cf); // COMPLIANT + cos(d); // COMPLIANT + // cos(p); // Doesn't compile + // cos(vp); // Doesn't compile + cos(uip); // COMPLIANT + cos(e); // NON-COMPLIANT + cos(b); // NON-COMPLIANT + cos(1); // COMPLIANT + cos(1.1f); // COMPLIANT + cos('a'); // NON-COMPLIANT[false negative] + + /** + * Int, float, and complex allowed: + */ + acos(i); // COMPLIANT + acos(f); // COMPLIANT + acosh(i); // COMPLIANT + acosh(f); // COMPLIANT + asin(i); // COMPLIANT + asin(f); // COMPLIANT + asinh(i); // COMPLIANT + asinh(f); // COMPLIANT + atan(i); // COMPLIANT + atan(f); // COMPLIANT + atan2(i, i); // COMPLIANT + atan2(f, f); // COMPLIANT + atanh(i); // COMPLIANT + atanh(f); // COMPLIANT + carg(i); // COMPLIANT + carg(f); // COMPLIANT + cbrt(i); // COMPLIANT + cbrt(f); // COMPLIANT + ceil(i); // COMPLIANT + ceil(f); // COMPLIANT + cimag(i); // COMPLIANT + cimag(f); // COMPLIANT + conj(i); // COMPLIANT + conj(f); // COMPLIANT + copysign(i, i); // COMPLIANT + copysign(f, f); // COMPLIANT + cos(i); // COMPLIANT + cos(f); // COMPLIANT + cosh(i); // COMPLIANT + cosh(f); // COMPLIANT + cproj(i); // COMPLIANT + cproj(f); // COMPLIANT + creal(i); // COMPLIANT + creal(f); // COMPLIANT + erf(i); // COMPLIANT + erf(f); // COMPLIANT + erfc(i); // COMPLIANT + erfc(f); // COMPLIANT + exp(i); // COMPLIANT + exp(f); // COMPLIANT + exp2(i); // COMPLIANT + exp2(f); // COMPLIANT + expm1(i); // COMPLIANT + expm1(f); // COMPLIANT + fabs(i); // COMPLIANT + fabs(f); // COMPLIANT + fdim(i, i); // COMPLIANT + fdim(f, f); // COMPLIANT + floor(i); // COMPLIANT + floor(f); // COMPLIANT + fma(i, i, i); // COMPLIANT + fma(f, f, f); // COMPLIANT + fmax(i, i); // COMPLIANT + fmax(f, f); // COMPLIANT + fmin(i, i); // COMPLIANT + fmin(f, f); // COMPLIANT + fmod(i, i); // COMPLIANT + fmod(f, f); // COMPLIANT + frexp(i, &i); // COMPLIANT + frexp(f, &p); // COMPLIANT + hypot(i, i); // COMPLIANT + hypot(f, f); // COMPLIANT + ilogb(i); // COMPLIANT + ilogb(f); // COMPLIANT + llrint(i); // COMPLIANT + llrint(f); // COMPLIANT + ldexp(i, i); // COMPLIANT + ldexp(f, f); // COMPLIANT + lgamma(i); // COMPLIANT + lgamma(f); // COMPLIANT + llround(i); // COMPLIANT + llround(f); // COMPLIANT + log(i); // COMPLIANT + log(f); // COMPLIANT + pow(i, i); // COMPLIANT + pow(f, f); // COMPLIANT + remainder(i, i); // COMPLIANT + remainder(f, f); // COMPLIANT + remquo(i, i, &i); // COMPLIANT + remquo(f, f, &f); // COMPLIANT + rint(i); // COMPLIANT + rint(f); // COMPLIANT + round(i); // COMPLIANT + round(f); // COMPLIANT + scalbn(i, i); // COMPLIANT + scalbn(f, f); // COMPLIANT + scalbln(i, i); // COMPLIANT + scalbln(f, f); // COMPLIANT + sin(i); // COMPLIANT + sin(f); // COMPLIANT + sin(cf); // COMPLIANT + sinh(i); // COMPLIANT + sinh(f); // COMPLIANT + sqrt(i); // COMPLIANT + sqrt(f); // COMPLIANT + tan(i); // COMPLIANT + tan(f); // COMPLIANT + tanh(i); // COMPLIANT + tanh(f); // COMPLIANT + tgamma(i); // COMPLIANT + tgamma(f); // COMPLIANT + trunc(i); // COMPLIANT + trunc(f); // COMPLIANT + + /** + * Char not allowed: + */ + acos(c); // NON-COMPLIANT + acosh(c); // NON-COMPLIANT + asin(c); // NON-COMPLIANT + asinh(c); // NON-COMPLIANT + atan2(c, i); // NON-COMPLIANT + atan2(i, c); // NON-COMPLIANT + atanh(c); // NON-COMPLIANT + carg(c); // NON-COMPLIANT + ceil(c); // NON-COMPLIANT + cimag(c); // NON-COMPLIANT + conj(c); // NON-COMPLIANT + copysign(i, c); // NON-COMPLIANT + copysign(c, i); // NON-COMPLIANT + cosh(c); // NON-COMPLIANT + cproj(c); // NON-COMPLIANT + creal(c); // NON-COMPLIANT + erf(c); // NON-COMPLIANT + erfc(c); // NON-COMPLIANT + exp(c); // NON-COMPLIANT + exp2(c); // NON-COMPLIANT + expm1(c); // NON-COMPLIANT + fabs(c); // NON-COMPLIANT + fdim(c, i); // NON-COMPLIANT + fdim(i, c); // NON-COMPLIANT + floor(c); // NON-COMPLIANT + fma(c, i, i); // NON-COMPLIANT + fma(i, c, i); // NON-COMPLIANT + fma(i, i, c); // NON-COMPLIANT + fmax(c, i); // NON-COMPLIANT + fmax(i, c); // NON-COMPLIANT + fmin(c, i); // NON-COMPLIANT + fmin(i, c); // NON-COMPLIANT + fmod(c, i); // NON-COMPLIANT + fmod(i, c); // NON-COMPLIANT + //frexp(c, i); // NON-COMPLIANT + hypot(c, i); // NON-COMPLIANT + hypot(i, c); // NON-COMPLIANT + ilogb(c); // NON-COMPLIANT + ldexp(c, i); // NON-COMPLIANT + ldexp(i, c); // NON-COMPLIANT + lgamma(c); // NON-COMPLIANT + llrint(c); // NON-COMPLIANT + llround(c); // NON-COMPLIANT + log(c); // NON-COMPLIANT + log10(c); // NON-COMPLIANT + log1p(c); // NON-COMPLIANT + log2(c); // NON-COMPLIANT + logb(c); // NON-COMPLIANT + lrint(c); // NON-COMPLIANT + lround(c); // NON-COMPLIANT + nearbyint(c); // NON-COMPLIANT + nextafter(c, i); // NON-COMPLIANT + nextafter(i, c); // NON-COMPLIANT + nexttoward(c, i); // NON-COMPLIANT + nexttoward(i, c); // NON-COMPLIANT + pow(c, i); // NON-COMPLIANT + pow(i, c); // NON-COMPLIANT + remainder(c, i); // NON-COMPLIANT + remainder(i, c); // NON-COMPLIANT + //remquo(c, i, i); // NON-COMPLIANT + //remquo(i, c, i); // NON-COMPLIANT + rint(c); // NON-COMPLIANT + round(c); // NON-COMPLIANT + scalbn(c, i); // NON-COMPLIANT + scalbn(i, c); // NON-COMPLIANT + scalbln(c, i); // NON-COMPLIANT + scalbln(i, c); // NON-COMPLIANT + sin(c); // NON-COMPLIANT + sinh(c); // NON-COMPLIANT + sqrt(c); // NON-COMPLIANT + tan(c); // NON-COMPLIANT + tanh(c); // NON-COMPLIANT + tgamma(c); // NON-COMPLIANT + trunc(c); // NON-COMPLIANT + + /** + * Complex types allowed in some calls, not others: + */ + acos(cf); // COMPLIANT + acosh(cf); // COMPLIANT + asin(cf); // COMPLIANT + asinh(cf); // COMPLIANT + atan(cf); // COMPLIANT + //atan2(cf, i); // NON-COMPLIANT + //atan2(i, cf); // NON-COMPLIANT + atanh(cf); // COMPLIANT + carg(cf); // COMPLIANT + //cbrt(cf); // NON-COMPLIANT + //ceil(cf); // NON-COMPLIANT + cimag(cf); // COMPLIANT + conj(cf); // COMPLIANT + //copysign(i, cf); // NON-COMPLIANT + //copysign(cf, i); // NON-COMPLIANT + //copysign(i, cf); // NON-COMPLIANT + cos(cf); // COMPLIANT + cosh(cf); // COMPLIANT + cproj(cf); // COMPLIANT + creal(cf); // COMPLIANT + //erf(cf); // NON-COMPLIANT + //erfc(cf); // NON-COMPLIANT + exp(cf); // COMPLIANT + //exp2(cf); // NON-COMPLIANT + //expm1(cf); // NON-COMPLIANT + fabs(cf); // COMPLIANT + //fdim(cf, i); // NON-COMPLIANT + //fdim(i, cf); // NON-COMPLIANT + //floor(cf); // NON-COMPLIANT + //fma(cf, i, i); // NON-COMPLIANT + //fma(i, cf, i); // NON-COMPLIANT + //fma(i, i, cf); // NON-COMPLIANT + //fmax(cf, i); // NON-COMPLIANT + //fmax(i, cf); // NON-COMPLIANT + //fmin(cf, i); // NON-COMPLIANT + //fmin(i, cf); // NON-COMPLIANT + //fmod(cf, i); // NON-COMPLIANT + //fmod(i, cf); // NON-COMPLIANT + //frexp(cf, i); // NON-COMPLIANT + //hypot(cf, i); // NON-COMPLIANT + //hypot(i, cf); // NON-COMPLIANT + //ilogb(cf); // NON-COMPLIANT + //ldexp(cf, i); // NON-COMPLIANT + //ldexp(i, cf); // NON-COMPLIANT + //lgamma(cf); // NON-COMPLIANT + //llrint(cf); // NON-COMPLIANT + //llround(cf); // NON-COMPLIANT + log(cf); // COMPLIANT + //log10(cf); // NON-COMPLIANT + //log1p(cf); // NON-COMPLIANT + //log2(cf); // NON-COMPLIANT + //logb(cf); // NON-COMPLIANT + //lrint(cf); // NON-COMPLIANT + //lround(cf); // NON-COMPLIANT + //nearbyint(cf); // NON-COMPLIANT + //nextafter(cf, i); // NON-COMPLIANT + //nextafter(i, cf); // NON-COMPLIANT + //nexttoward(cf, i); // NON-COMPLIANT + //nexttoward(i, cf); // NON-COMPLIANT + pow(cf, cf); // COMPLIANT + //remainder(cf, i); // NON-COMPLIANT + //remainder(i, cf); // NON-COMPLIANT + //remquo(cf, i, i); // NON-COMPLIANT + //remquo(i, cf, i); // NON-COMPLIANT + //rint(cf); // NON-COMPLIANT + //round(cf); // NON-COMPLIANT + //scalbn(cf, i); // NON-COMPLIANT + //scalbn(i, cf); // NON-COMPLIANT + //scalbln(cf, i); // NON-COMPLIANT + //scalbln(i, cf); // NON-COMPLIANT + sin(cf); // COMPLIANT + sinh(cf); // COMPLIANT + sqrt(cf); // COMPLIANT + tan(cf); // COMPLIANT + tanh(cf); // COMPLIANT + //tgamma(cf); // NON-COMPLIANT + //trunc(cf); // NON-COMPLIANT + + /* Test output arguments thoroughly */ + frexp(i, &i); // COMPLIANT + frexp(i, vp); // COMPLIANT + frexp(i, 0); // COMPLIANT + frexp(i, 'c' - 'c'); // COMPLIANT + //frexp(i, c); // COMPLIANT + remquo(i, i, &i); // COMPLIANT + remquo(i, i, vp); // COMPLIANT + remquo(i, i, 0); // COMPLIANT + remquo(i, i, 'c' - 'c'); // COMPLIANT + //remquo(i, i, c); // COMPLIANT + + /* Test casts */ + cos((char) i); // NON-COMPLIANT + cos((int) c); // COMPLIANT + cos((int) (char) i); // COMPLIANT + cos((char) (int) c); // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-22/test.c.gcc b/c/misra/test/rules/RULE-21-22/test.c.gcc new file mode 100644 index 0000000000..4661a0b4f7 --- /dev/null +++ b/c/misra/test/rules/RULE-21-22/test.c.gcc @@ -0,0 +1,329 @@ +#include +#include +#include +#include + +void f1() { + int i = 0; + unsigned int ui = 0; + short s = 0; + unsigned short us = 0; + char c = 0; + unsigned char uc = 0; + signed char sc = 0; + long l = 0; + unsigned long ul = 0; + float f = 0.0f; + float _Complex cf = 0.0f + 0.0f * I; + double d = 0.0; + char *p = 0; + void *vp = 0; + uintptr_t uip = p; + enum { e1 } e = e1; + bool b = true; + + cos(i); // COMPLIANT + cos(ui); // COMPLIANT + cos(s); // COMPLIANT + cos(us); // COMPLIANT + cos(c); // NON-COMPLIANT + cos(uc); // COMPLIANT + cos(sc); // COMPLIANT + cos(l); // COMPLIANT + cos(ul); // COMPLIANT + cos(f); // COMPLIANT + cos(cf); // COMPLIANT + cos(d); // COMPLIANT + // cos(p); // Doesn't compile + // cos(vp); // Doesn't compile + cos(uip); // COMPLIANT + cos(e); // NON-COMPLIANT + cos(b); // NON-COMPLIANT + cos(1); // COMPLIANT + cos(1.1f); // COMPLIANT + cos('a'); // NON-COMPLIANT[false negative] + + /** + * Int, float, and complex allowed: + */ + acos(i); // COMPLIANT + acos(f); // COMPLIANT + acosh(i); // COMPLIANT + acosh(f); // COMPLIANT + asin(i); // COMPLIANT + asin(f); // COMPLIANT + asinh(i); // COMPLIANT + asinh(f); // COMPLIANT + atan(i); // COMPLIANT + atan(f); // COMPLIANT + atan2(i, i); // COMPLIANT + atan2(f, f); // COMPLIANT + atanh(i); // COMPLIANT + atanh(f); // COMPLIANT + carg(i); // COMPLIANT + carg(f); // COMPLIANT + cbrt(i); // COMPLIANT + cbrt(f); // COMPLIANT + ceil(i); // COMPLIANT + ceil(f); // COMPLIANT + cimag(i); // COMPLIANT + cimag(f); // COMPLIANT + conj(i); // COMPLIANT + conj(f); // COMPLIANT + copysign(i, i); // COMPLIANT + copysign(f, f); // COMPLIANT + cos(i); // COMPLIANT + cos(f); // COMPLIANT + cosh(i); // COMPLIANT + cosh(f); // COMPLIANT + cproj(i); // COMPLIANT + cproj(f); // COMPLIANT + creal(i); // COMPLIANT + creal(f); // COMPLIANT + erf(i); // COMPLIANT + erf(f); // COMPLIANT + erfc(i); // COMPLIANT + erfc(f); // COMPLIANT + exp(i); // COMPLIANT + exp(f); // COMPLIANT + exp2(i); // COMPLIANT + exp2(f); // COMPLIANT + expm1(i); // COMPLIANT + expm1(f); // COMPLIANT + fabs(i); // COMPLIANT + fabs(f); // COMPLIANT + fdim(i, i); // COMPLIANT + fdim(f, f); // COMPLIANT + floor(i); // COMPLIANT + floor(f); // COMPLIANT + fma(i, i, i); // COMPLIANT + fma(f, f, f); // COMPLIANT + fmax(i, i); // COMPLIANT + fmax(f, f); // COMPLIANT + fmin(i, i); // COMPLIANT + fmin(f, f); // COMPLIANT + fmod(i, i); // COMPLIANT + fmod(f, f); // COMPLIANT + frexp(i, &i); // COMPLIANT + frexp(f, &p); // COMPLIANT + hypot(i, i); // COMPLIANT + hypot(f, f); // COMPLIANT + ilogb(i); // COMPLIANT + ilogb(f); // COMPLIANT + llrint(i); // COMPLIANT + llrint(f); // COMPLIANT + ldexp(i, i); // COMPLIANT + ldexp(f, f); // COMPLIANT + lgamma(i); // COMPLIANT + lgamma(f); // COMPLIANT + llround(i); // COMPLIANT + llround(f); // COMPLIANT + log(i); // COMPLIANT + log(f); // COMPLIANT + pow(i, i); // COMPLIANT + pow(f, f); // COMPLIANT + remainder(i, i); // COMPLIANT + remainder(f, f); // COMPLIANT + remquo(i, i, &i); // COMPLIANT + remquo(f, f, &f); // COMPLIANT + rint(i); // COMPLIANT + rint(f); // COMPLIANT + round(i); // COMPLIANT + round(f); // COMPLIANT + scalbn(i, i); // COMPLIANT + scalbn(f, f); // COMPLIANT + scalbln(i, i); // COMPLIANT + scalbln(f, f); // COMPLIANT + sin(i); // COMPLIANT + sin(f); // COMPLIANT + sin(cf); // COMPLIANT + sinh(i); // COMPLIANT + sinh(f); // COMPLIANT + sqrt(i); // COMPLIANT + sqrt(f); // COMPLIANT + tan(i); // COMPLIANT + tan(f); // COMPLIANT + tanh(i); // COMPLIANT + tanh(f); // COMPLIANT + tgamma(i); // COMPLIANT + tgamma(f); // COMPLIANT + trunc(i); // COMPLIANT + trunc(f); // COMPLIANT + + /** + * Char not allowed: + */ + acos(c); // NON-COMPLIANT + acosh(c); // NON-COMPLIANT + asin(c); // NON-COMPLIANT + asinh(c); // NON-COMPLIANT + atan2(c, i); // NON-COMPLIANT + atan2(i, c); // NON-COMPLIANT + atanh(c); // NON-COMPLIANT + carg(c); // NON-COMPLIANT + ceil(c); // NON-COMPLIANT + cimag(c); // NON-COMPLIANT + conj(c); // NON-COMPLIANT + copysign(i, c); // NON-COMPLIANT + copysign(c, i); // NON-COMPLIANT + cosh(c); // NON-COMPLIANT + cproj(c); // NON-COMPLIANT + creal(c); // NON-COMPLIANT + erf(c); // NON-COMPLIANT + erfc(c); // NON-COMPLIANT + exp(c); // NON-COMPLIANT + exp2(c); // NON-COMPLIANT + expm1(c); // NON-COMPLIANT + fabs(c); // NON-COMPLIANT + fdim(c, i); // NON-COMPLIANT + fdim(i, c); // NON-COMPLIANT + floor(c); // NON-COMPLIANT + fma(c, i, i); // NON-COMPLIANT + fma(i, c, i); // NON-COMPLIANT + fma(i, i, c); // NON-COMPLIANT + fmax(c, i); // NON-COMPLIANT + fmax(i, c); // NON-COMPLIANT + fmin(c, i); // NON-COMPLIANT + fmin(i, c); // NON-COMPLIANT + fmod(c, i); // NON-COMPLIANT + fmod(i, c); // NON-COMPLIANT + frexp(c, i); // NON-COMPLIANT + hypot(c, i); // NON-COMPLIANT + hypot(i, c); // NON-COMPLIANT + ilogb(c); // NON-COMPLIANT + ldexp(c, i); // NON-COMPLIANT + ldexp(i, c); // NON-COMPLIANT + lgamma(c); // NON-COMPLIANT + llrint(c); // NON-COMPLIANT + llround(c); // NON-COMPLIANT + log(c); // NON-COMPLIANT + log10(c); // NON-COMPLIANT + log1p(c); // NON-COMPLIANT + log2(c); // NON-COMPLIANT + logb(c); // NON-COMPLIANT + lrint(c); // NON-COMPLIANT + lround(c); // NON-COMPLIANT + nearbyint(c); // NON-COMPLIANT + nextafter(c, i); // NON-COMPLIANT + nextafter(i, c); // NON-COMPLIANT + nexttoward(c, i); // NON-COMPLIANT + nexttoward(i, c); // NON-COMPLIANT + pow(c, i); // NON-COMPLIANT + pow(i, c); // NON-COMPLIANT + remainder(c, i); // NON-COMPLIANT + remainder(i, c); // NON-COMPLIANT + remquo(c, i, i); // NON-COMPLIANT + remquo(i, c, i); // NON-COMPLIANT + rint(c); // NON-COMPLIANT + round(c); // NON-COMPLIANT + scalbn(c, i); // NON-COMPLIANT + scalbn(i, c); // NON-COMPLIANT + scalbln(c, i); // NON-COMPLIANT + scalbln(i, c); // NON-COMPLIANT + sin(c); // NON-COMPLIANT + sinh(c); // NON-COMPLIANT + sqrt(c); // NON-COMPLIANT + tan(c); // NON-COMPLIANT + tanh(c); // NON-COMPLIANT + tgamma(c); // NON-COMPLIANT + trunc(c); // NON-COMPLIANT + + /** + * Complex types allowed in some calls, not others: + */ + acos(cf); // COMPLIANT + acosh(cf); // COMPLIANT + asin(cf); // COMPLIANT + asinh(cf); // COMPLIANT + atan(cf); // COMPLIANT + //atan2(cf, i); // NON-COMPLIANT + //atan2(i, cf); // NON-COMPLIANT + atanh(cf); // COMPLIANT + carg(cf); // COMPLIANT + //cbrt(cf); // NON-COMPLIANT + //ceil(cf); // NON-COMPLIANT + cimag(cf); // COMPLIANT + conj(cf); // COMPLIANT + //copysign(i, cf); // NON-COMPLIANT + //copysign(cf, i); // NON-COMPLIANT + //copysign(i, cf); // NON-COMPLIANT + cos(cf); // COMPLIANT + cosh(cf); // COMPLIANT + cproj(cf); // COMPLIANT + creal(cf); // COMPLIANT + //erf(cf); // NON-COMPLIANT + //erfc(cf); // NON-COMPLIANT + exp(cf); // COMPLIANT + //exp2(cf); // NON-COMPLIANT + //expm1(cf); // NON-COMPLIANT + fabs(cf); // COMPLIANT + //fdim(cf, i); // NON-COMPLIANT + //fdim(i, cf); // NON-COMPLIANT + //floor(cf); // NON-COMPLIANT + //fma(cf, i, i); // NON-COMPLIANT + //fma(i, cf, i); // NON-COMPLIANT + //fma(i, i, cf); // NON-COMPLIANT + //fmax(cf, i); // NON-COMPLIANT + //fmax(i, cf); // NON-COMPLIANT + //fmin(cf, i); // NON-COMPLIANT + //fmin(i, cf); // NON-COMPLIANT + //fmod(cf, i); // NON-COMPLIANT + //fmod(i, cf); // NON-COMPLIANT + //frexp(cf, i); // NON-COMPLIANT + //hypot(cf, i); // NON-COMPLIANT + //hypot(i, cf); // NON-COMPLIANT + //ilogb(cf); // NON-COMPLIANT + //ldexp(cf, i); // NON-COMPLIANT + //ldexp(i, cf); // NON-COMPLIANT + //lgamma(cf); // NON-COMPLIANT + //llrint(cf); // NON-COMPLIANT + //llround(cf); // NON-COMPLIANT + log(cf); // COMPLIANT + //log10(cf); // NON-COMPLIANT + //log1p(cf); // NON-COMPLIANT + //log2(cf); // NON-COMPLIANT + //logb(cf); // NON-COMPLIANT + //lrint(cf); // NON-COMPLIANT + //lround(cf); // NON-COMPLIANT + //nearbyint(cf); // NON-COMPLIANT + //nextafter(cf, i); // NON-COMPLIANT + //nextafter(i, cf); // NON-COMPLIANT + //nexttoward(cf, i); // NON-COMPLIANT + //nexttoward(i, cf); // NON-COMPLIANT + pow(cf, cf); // COMPLIANT + //remainder(cf, i); // NON-COMPLIANT + //remainder(i, cf); // NON-COMPLIANT + //remquo(cf, i, i); // NON-COMPLIANT + //remquo(i, cf, i); // NON-COMPLIANT + //rint(cf); // NON-COMPLIANT + //round(cf); // NON-COMPLIANT + //scalbn(cf, i); // NON-COMPLIANT + //scalbn(i, cf); // NON-COMPLIANT + //scalbln(cf, i); // NON-COMPLIANT + //scalbln(i, cf); // NON-COMPLIANT + sin(cf); // COMPLIANT + sinh(cf); // COMPLIANT + sqrt(cf); // COMPLIANT + tan(cf); // COMPLIANT + tanh(cf); // COMPLIANT + //tgamma(cf); // NON-COMPLIANT + //trunc(cf); // NON-COMPLIANT + + /* Test output arguments thoroughly */ + frexp(i, &i); // COMPLIANT + frexp(i, vp); // COMPLIANT + frexp(i, 0); // COMPLIANT + frexp(i, 'c' - 'c'); // COMPLIANT + frexp(i, c); // COMPLIANT + remquo(i, i, &i); // COMPLIANT + remquo(i, i, vp); // COMPLIANT + remquo(i, i, 0); // COMPLIANT + remquo(i, i, 'c' - 'c'); // COMPLIANT + remquo(i, i, c); // COMPLIANT + + /* Test casts */ + cos((char) i); // NON-COMPLIANT + cos((int) c); // COMPLIANT + cos((int) (char) i); // COMPLIANT + cos((char) (int) c); // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected b/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected new file mode 100644 index 0000000000..6136aa4314 --- /dev/null +++ b/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected @@ -0,0 +1,139 @@ +| test.c:95:3:95:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:96:3:96:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:97:3:97:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:98:3:98:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:99:3:99:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:100:3:100:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:101:3:101:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:102:3:102:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:103:3:103:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:104:3:104:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:105:3:105:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:106:3:106:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:107:3:107:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:108:3:108:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:109:3:109:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:110:3:110:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:111:3:111:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:112:3:112:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:113:3:113:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:114:3:114:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:121:3:121:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:122:3:122:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:123:3:123:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:124:3:124:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:125:3:125:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:126:3:126:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:127:3:127:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:128:3:128:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:131:3:131:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:132:3:132:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:133:3:133:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:134:3:134:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:135:3:135:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:136:3:136:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:137:3:137:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:138:3:138:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:139:3:139:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:140:3:140:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:141:3:141:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:142:3:142:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:143:3:143:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:144:3:144:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:145:3:145:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:146:3:146:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:147:3:147:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:148:3:148:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:149:3:149:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:150:3:150:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:151:3:151:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:152:3:152:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:153:3:153:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:154:3:154:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:155:3:155:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:156:3:156:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:157:3:157:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:158:3:158:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:159:3:159:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:160:3:160:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:161:3:161:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:162:3:162:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:165:3:165:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:166:3:166:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:167:3:167:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:168:3:168:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:169:3:169:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:170:3:170:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:171:3:171:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:172:3:172:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:175:3:175:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (float, double). | +| test.c:176:3:176:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (float, long double). | +| test.c:177:3:177:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (double, float). | +| test.c:178:3:178:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (double, long double). | +| test.c:179:3:179:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long double, float). | +| test.c:180:3:180:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long double, double). | +| test.c:183:3:183:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:184:3:184:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:185:3:185:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:186:3:186:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:187:3:187:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:188:3:188:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:189:3:189:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:190:3:190:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:191:3:191:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:192:3:192:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:193:3:193:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:194:3:194:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:195:3:195:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:196:3:196:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:197:3:197:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:198:3:198:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:199:3:199:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:200:3:200:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:201:3:201:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:202:3:202:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:203:3:203:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:204:3:204:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:205:3:205:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:206:3:206:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:207:3:207:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:208:3:208:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:209:3:209:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:210:3:210:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:211:3:211:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:212:3:212:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:213:3:213:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, float). | +| test.c:214:3:214:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, double). | +| test.c:215:3:215:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long double). | +| test.c:216:3:216:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, float). | +| test.c:217:3:217:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, double). | +| test.c:218:3:218:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long double). | +| test.c:219:3:219:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, float). | +| test.c:220:3:220:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, double). | +| test.c:221:3:221:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, long double). | +| test.c:222:3:222:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, float). | +| test.c:223:3:223:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, double). | +| test.c:224:3:224:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, long double). | +| test.c:225:3:225:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, float). | +| test.c:226:3:226:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, double). | +| test.c:227:3:227:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long double). | +| test.c:228:3:228:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, float). | +| test.c:229:3:229:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, double). | +| test.c:230:3:230:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long double). | +| test.c:235:3:235:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:242:3:242:16 | copysign(x,y) | Call to type-generic macro 'copysign' has arguments with differing standard types (int, float). | +| test.c:245:3:245:12 | fdim(x,y) | Call to type-generic macro 'fdim' has arguments with differing standard types (int, float). | +| test.c:248:3:248:14 | fma(x,y,z) | Call to type-generic macro 'fma' has arguments with differing standard types (float, int, int). | +| test.c:249:3:249:14 | fma(x,y,z) | Call to type-generic macro 'fma' has arguments with differing standard types (int, float, int). | +| test.c:250:3:250:14 | fma(x,y,z) | Call to type-generic macro 'fma' has arguments with differing standard types (int, int, float). | +| test.c:253:3:253:12 | fmax(x,y) | Call to type-generic macro 'fmax' has arguments with differing standard types (int, float). | +| test.c:256:3:256:12 | fmin(x,y) | Call to type-generic macro 'fmin' has arguments with differing standard types (int, float). | +| test.c:259:3:259:12 | fmod(x,y) | Call to type-generic macro 'fmod' has arguments with differing standard types (int, float). | +| test.c:262:3:262:13 | hypot(x,y) | Call to type-generic macro 'hypot' has arguments with differing standard types (int, float). | +| test.c:265:3:265:13 | ldexp(x,y) | Call to type-generic macro 'ldexp' has arguments with differing standard types (int, float). | +| test.c:268:3:268:17 | nextafter(x,y) | Call to type-generic macro 'nextafter' has arguments with differing standard types (int, float). | +| test.c:271:3:271:18 | nexttoward(x,y) | Call to type-generic macro 'nexttoward' has arguments with differing standard types (int, float). | +| test.c:274:3:274:17 | remainder(x,y) | Call to type-generic macro 'remainder' has arguments with differing standard types (int, float). | +| test.c:277:3:277:17 | remquo(x,y,z) | Call to type-generic macro 'remquo' has arguments with differing standard types (int, float). | +| test.c:280:3:280:15 | scalbln(x,y) | Call to type-generic macro 'scalbln' has arguments with differing standard types (int, float). | +| test.c:283:3:283:14 | scalbn(x,y) | Call to type-generic macro 'scalbn' has arguments with differing standard types (int, float). | diff --git a/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected.clang b/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected.clang new file mode 100644 index 0000000000..e6ad5c62e4 --- /dev/null +++ b/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected.clang @@ -0,0 +1,139 @@ +| test.c:95:3:95:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:96:3:96:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:97:3:97:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:98:3:98:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:99:3:99:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:100:3:100:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:101:3:101:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:102:3:102:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:103:3:103:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:104:3:104:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:105:3:105:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:106:3:106:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:107:3:107:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:108:3:108:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:109:3:109:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:110:3:110:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:111:3:111:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:112:3:112:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:113:3:113:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:114:3:114:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:121:3:121:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:122:3:122:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:123:3:123:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:124:3:124:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:125:3:125:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:126:3:126:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:127:3:127:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:128:3:128:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:131:3:131:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:132:3:132:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:133:3:133:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:134:3:134:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:135:3:135:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:136:3:136:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:137:3:137:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:138:3:138:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:139:3:139:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:140:3:140:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:141:3:141:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:142:3:142:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:143:3:143:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:144:3:144:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:145:3:145:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:146:3:146:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:147:3:147:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:148:3:148:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:149:3:149:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:150:3:150:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:151:3:151:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:152:3:152:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:153:3:153:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:154:3:154:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:155:3:155:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:156:3:156:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:157:3:157:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:158:3:158:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:159:3:159:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:160:3:160:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:161:3:161:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:162:3:162:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:165:3:165:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:166:3:166:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:167:3:167:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:168:3:168:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:169:3:169:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:170:3:170:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:171:3:171:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:172:3:172:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:175:3:175:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (float, double). | +| test.c:176:3:176:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (float, long double). | +| test.c:177:3:177:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (double, float). | +| test.c:178:3:178:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (double, long double). | +| test.c:179:3:179:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long double, float). | +| test.c:180:3:180:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long double, double). | +| test.c:183:3:183:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:184:3:184:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:185:3:185:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:186:3:186:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:187:3:187:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:188:3:188:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:189:3:189:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:190:3:190:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:191:3:191:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:192:3:192:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:193:3:193:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:194:3:194:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:195:3:195:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:196:3:196:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:197:3:197:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:198:3:198:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:199:3:199:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:200:3:200:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:201:3:201:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:202:3:202:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:203:3:203:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:204:3:204:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:205:3:205:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:206:3:206:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:207:3:207:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:208:3:208:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:209:3:209:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:210:3:210:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:211:3:211:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:212:3:212:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:213:3:213:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, float). | +| test.c:214:3:214:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, double). | +| test.c:215:3:215:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long double). | +| test.c:216:3:216:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, float). | +| test.c:217:3:217:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, double). | +| test.c:218:3:218:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long double). | +| test.c:219:3:219:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, float). | +| test.c:220:3:220:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, double). | +| test.c:221:3:221:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, long double). | +| test.c:222:3:222:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, float). | +| test.c:223:3:223:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, double). | +| test.c:224:3:224:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, long double). | +| test.c:225:3:225:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, float). | +| test.c:226:3:226:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, double). | +| test.c:227:3:227:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long double). | +| test.c:228:3:228:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, float). | +| test.c:229:3:229:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, double). | +| test.c:230:3:230:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long double). | +| test.c:235:3:235:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:242:3:242:16 | copysign(__x,__y) | Call to type-generic macro 'copysign' has arguments with differing standard types (int, float). | +| test.c:245:3:245:12 | fdim(__x,__y) | Call to type-generic macro 'fdim' has arguments with differing standard types (int, float). | +| test.c:248:3:248:14 | fma(__x,__y,__z) | Call to type-generic macro 'fma' has arguments with differing standard types (float, int, int). | +| test.c:249:3:249:14 | fma(__x,__y,__z) | Call to type-generic macro 'fma' has arguments with differing standard types (int, float, int). | +| test.c:250:3:250:14 | fma(__x,__y,__z) | Call to type-generic macro 'fma' has arguments with differing standard types (int, int, float). | +| test.c:253:3:253:12 | fmax(__x,__y) | Call to type-generic macro 'fmax' has arguments with differing standard types (int, float). | +| test.c:256:3:256:12 | fmin(__x,__y) | Call to type-generic macro 'fmin' has arguments with differing standard types (int, float). | +| test.c:259:3:259:12 | fmod(__x,__y) | Call to type-generic macro 'fmod' has arguments with differing standard types (int, float). | +| test.c:262:3:262:13 | hypot(__x,__y) | Call to type-generic macro 'hypot' has arguments with differing standard types (int, float). | +| test.c:265:3:265:13 | ldexp(__x,__y) | Call to type-generic macro 'ldexp' has arguments with differing standard types (int, float). | +| test.c:268:3:268:17 | nextafter(__x,__y) | Call to type-generic macro 'nextafter' has arguments with differing standard types (int, float). | +| test.c:271:3:271:18 | nexttoward(__x,__y) | Call to type-generic macro 'nexttoward' has arguments with differing standard types (int, float). | +| test.c:274:3:274:17 | remainder(__x,__y) | Call to type-generic macro 'remainder' has arguments with differing standard types (int, float). | +| test.c:277:3:277:17 | remquo(__x,__y,__z) | Call to type-generic macro 'remquo' has arguments with differing standard types (int, float). | +| test.c:280:3:280:15 | scalbln(__x,__y) | Call to type-generic macro 'scalbln' has arguments with differing standard types (int, float). | +| test.c:283:3:283:14 | scalbn(__x,__y) | Call to type-generic macro 'scalbn' has arguments with differing standard types (int, float). | diff --git a/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected.gcc b/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected.gcc new file mode 100644 index 0000000000..f8c610f8c2 --- /dev/null +++ b/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected.gcc @@ -0,0 +1,139 @@ +| test.c:95:3:95:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:96:3:96:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:97:3:97:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:98:3:98:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:99:3:99:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:100:3:100:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:101:3:101:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:102:3:102:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:103:3:103:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:104:3:104:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:105:3:105:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:106:3:106:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:107:3:107:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:108:3:108:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:109:3:109:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:110:3:110:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:111:3:111:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:112:3:112:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:113:3:113:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:114:3:114:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:121:3:121:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:122:3:122:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:123:3:123:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:124:3:124:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:125:3:125:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:126:3:126:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:127:3:127:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:128:3:128:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:131:3:131:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:132:3:132:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:133:3:133:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:134:3:134:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:135:3:135:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:136:3:136:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:137:3:137:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:138:3:138:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:139:3:139:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:140:3:140:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:141:3:141:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:142:3:142:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:143:3:143:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:144:3:144:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:145:3:145:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:146:3:146:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:147:3:147:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:148:3:148:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:149:3:149:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:150:3:150:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:151:3:151:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:152:3:152:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:153:3:153:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:154:3:154:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:155:3:155:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:156:3:156:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:157:3:157:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:158:3:158:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:159:3:159:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:160:3:160:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:161:3:161:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:162:3:162:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:165:3:165:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:166:3:166:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:167:3:167:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:168:3:168:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:169:3:169:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:170:3:170:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:171:3:171:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:172:3:172:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:175:3:175:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (float, double). | +| test.c:176:3:176:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (float, long double). | +| test.c:177:3:177:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (double, float). | +| test.c:178:3:178:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (double, long double). | +| test.c:179:3:179:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long double, float). | +| test.c:180:3:180:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long double, double). | +| test.c:183:3:183:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:184:3:184:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:185:3:185:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:186:3:186:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:187:3:187:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:188:3:188:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:189:3:189:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:190:3:190:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:191:3:191:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:192:3:192:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:193:3:193:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:194:3:194:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:195:3:195:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:196:3:196:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:197:3:197:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:198:3:198:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:199:3:199:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:200:3:200:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:201:3:201:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:202:3:202:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:203:3:203:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:204:3:204:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:205:3:205:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:206:3:206:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:207:3:207:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:208:3:208:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:209:3:209:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:210:3:210:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:211:3:211:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:212:3:212:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:213:3:213:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, float). | +| test.c:214:3:214:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, double). | +| test.c:215:3:215:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long double). | +| test.c:216:3:216:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, float). | +| test.c:217:3:217:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, double). | +| test.c:218:3:218:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long double). | +| test.c:219:3:219:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, float). | +| test.c:220:3:220:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, double). | +| test.c:221:3:221:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, long double). | +| test.c:222:3:222:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, float). | +| test.c:223:3:223:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, double). | +| test.c:224:3:224:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, long double). | +| test.c:225:3:225:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, float). | +| test.c:226:3:226:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, double). | +| test.c:227:3:227:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long double). | +| test.c:228:3:228:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, float). | +| test.c:229:3:229:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, double). | +| test.c:230:3:230:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long double). | +| test.c:235:3:235:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:242:3:242:16 | copysign(Val1,Val2) | Call to type-generic macro 'copysign' has arguments with differing standard types (int, float). | +| test.c:245:3:245:12 | fdim(Val1,Val2) | Call to type-generic macro 'fdim' has arguments with differing standard types (int, float). | +| test.c:248:3:248:14 | fma(Val1,Val2,Val3) | Call to type-generic macro 'fma' has arguments with differing standard types (float, int, int). | +| test.c:249:3:249:14 | fma(Val1,Val2,Val3) | Call to type-generic macro 'fma' has arguments with differing standard types (int, float, int). | +| test.c:250:3:250:14 | fma(Val1,Val2,Val3) | Call to type-generic macro 'fma' has arguments with differing standard types (int, int, float). | +| test.c:253:3:253:12 | fmax(Val1,Val2) | Call to type-generic macro 'fmax' has arguments with differing standard types (int, float). | +| test.c:256:3:256:12 | fmin(Val1,Val2) | Call to type-generic macro 'fmin' has arguments with differing standard types (int, float). | +| test.c:259:3:259:12 | fmod(Val1,Val2) | Call to type-generic macro 'fmod' has arguments with differing standard types (int, float). | +| test.c:262:3:262:13 | hypot(Val1,Val2) | Call to type-generic macro 'hypot' has arguments with differing standard types (int, float). | +| test.c:265:3:265:13 | ldexp(Val1,Val2) | Call to type-generic macro 'ldexp' has arguments with differing standard types (int, float). | +| test.c:268:3:268:17 | nextafter(Val1,Val2) | Call to type-generic macro 'nextafter' has arguments with differing standard types (int, float). | +| test.c:271:3:271:18 | nexttoward(Val1,Val2) | Call to type-generic macro 'nexttoward' has arguments with differing standard types (int, float). | +| test.c:274:3:274:17 | remainder(Val1,Val2) | Call to type-generic macro 'remainder' has arguments with differing standard types (int, float). | +| test.c:277:3:277:17 | remquo(Val1,Val2,Val3) | Call to type-generic macro 'remquo' has arguments with differing standard types (int, float). | +| test.c:280:3:280:15 | scalbln(Val1,Val2) | Call to type-generic macro 'scalbln' has arguments with differing standard types (int, float). | +| test.c:283:3:283:14 | scalbn(Val1,Val2) | Call to type-generic macro 'scalbn' has arguments with differing standard types (int, float). | diff --git a/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.qlref b/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.qlref new file mode 100644 index 0000000000..550893822f --- /dev/null +++ b/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.qlref @@ -0,0 +1 @@ +rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-23/test.c b/c/misra/test/rules/RULE-21-23/test.c new file mode 100644 index 0000000000..08df1184a7 --- /dev/null +++ b/c/misra/test/rules/RULE-21-23/test.c @@ -0,0 +1,288 @@ +#include +#include + +void f1() { + signed char c = 0; + unsigned char uc = 0; + short s = 0; + unsigned short us = 0; + int i = 0; + unsigned int ui = 0; + long l = 0; + unsigned long ul = 0; + float f = 0.0f; + double d = 0.0; + long double ld = 0.0; + uint8_t u8 = 0; + int8_t i8 = 0; + uint16_t u16 = 0; + int16_t i16 = 0; + uint32_t u32 = 0; + int32_t i32 = 0; + uint64_t u64 = 0; + int64_t i64 = 0; + + /** + * Test exact types + */ + atan2(c, c); // COMPLIANT + atan2(uc, uc); // COMPLIANT + atan2(s, s); // COMPLIANT + atan2(us, us); // COMPLIANT + atan2(i, i); // COMPLIANT + atan2(ui, ui); // COMPLIANT + atan2(ui, ui); // COMPLIANT + atan2(l, l); // COMPLIANT + atan2(ul, ul); // COMPLIANT + atan2(f, f); // COMPLIANT + atan2(d, d); // COMPLIANT + atan2(ld, ld); // COMPLIANT + atan2(u8, u8); // COMPLIANT + atan2(i8, i8); // COMPLIANT + atan2(u16, u16); // COMPLIANT + atan2(i16, i16); // COMPLIANT + atan2(u32, u32); // COMPLIANT + atan2(i32, i32); // COMPLIANT + atan2(u64, u64); // COMPLIANT + atan2(i64, i64); // COMPLIANT + + /** Test equivalent types */ + atan2(c, i8); // COMPLIANT + atan2(i8, c); // COMPLIANT + atan2(uc, u8); // COMPLIANT + atan2(u8, uc); // COMPLIANT + atan2(s, i16); // COMPLIANT + atan2(i16, s); // COMPLIANT + atan2(us, u16); // COMPLIANT + atan2(u16, us); // COMPLIANT + atan2(i, i32); // COMPLIANT + atan2(i32, i); // COMPLIANT + atan2(ui, u32); // COMPLIANT + atan2(u32, ui); // COMPLIANT + atan2(l, i64); // COMPLIANT + atan2(i64, l); // COMPLIANT + atan2(ul, u64); // COMPLIANT + atan2(u64, ul); // COMPLIANT + + /** Types are the same after integer promotion */ + atan2(c, i8); // COMPLIANT + atan2(c, u8); // COMPLIANT + atan2(c, i16); // COMPLIANT + atan2(c, u16); // COMPLIANT + atan2(c, i32); // COMPLIANT + atan2(uc, i8); // COMPLIANT + atan2(uc, u8); // COMPLIANT + atan2(uc, i16); // COMPLIANT + atan2(uc, u16); // COMPLIANT + atan2(uc, i32); // COMPLIANT + atan2(s, i8); // COMPLIANT + atan2(s, u8); // COMPLIANT + atan2(s, i16); // COMPLIANT + atan2(s, u16); // COMPLIANT + atan2(s, i32); // COMPLIANT + atan2(us, i8); // COMPLIANT + atan2(us, u8); // COMPLIANT + atan2(us, i16); // COMPLIANT + atan2(us, u16); // COMPLIANT + atan2(us, i32); // COMPLIANT + atan2(i, i8); // COMPLIANT + atan2(i, u8); // COMPLIANT + atan2(i, i16); // COMPLIANT + atan2(i, u16); // COMPLIANT + atan2(i, i32); // COMPLIANT + + /** Integer promotion makes a signed int, not an unsigned int */ + atan2(c, ui); // NON-COMPLIANT + atan2(c, u32); // NON-COMPLIANT + atan2(i8, ui); // NON-COMPLIANT + atan2(i8, u32); // NON-COMPLIANT + atan2(uc, ui); // NON-COMPLIANT + atan2(uc, u32); // NON-COMPLIANT + atan2(u8, ui); // NON-COMPLIANT + atan2(u8, u32); // NON-COMPLIANT + atan2(s, ui); // NON-COMPLIANT + atan2(s, u32); // NON-COMPLIANT + atan2(i16, ui); // NON-COMPLIANT + atan2(i16, u32); // NON-COMPLIANT + atan2(us, ui); // NON-COMPLIANT + atan2(us, u32); // NON-COMPLIANT + atan2(u16, ui); // NON-COMPLIANT + atan2(u16, u32); // NON-COMPLIANT + atan2(i, ui); // NON-COMPLIANT + atan2(i, u32); // NON-COMPLIANT + atan2(i32, ui); // NON-COMPLIANT + atan2(i32, u32); // NON-COMPLIANT + atan2(ui, ui); // COMPLIANT + atan2(ui, u32); // COMPLIANT + atan2(u32, ui); // COMPLIANT + atan2(u32, u32); // COMPLIANT + + /** Integer promotion makes int, not long */ + atan2(c, l); // NON-COMPLIANT + atan2(i8, l); // NON-COMPLIANT + atan2(uc, l); // NON-COMPLIANT + atan2(u8, l); // NON-COMPLIANT + atan2(s, l); // NON-COMPLIANT + atan2(i16, l); // NON-COMPLIANT + atan2(us, l); // NON-COMPLIANT + atan2(u16, l); // NON-COMPLIANT + + /** Integer vs long */ + atan2(i, l); // NON-COMPLIANT + atan2(i32, l); // NON-COMPLIANT + atan2(ui, l); // NON-COMPLIANT + atan2(u32, l); // NON-COMPLIANT + atan2(l, i); // NON-COMPLIANT + atan2(l, ui); // NON-COMPLIANT + atan2(l, i32); // NON-COMPLIANT + atan2(l, u32); // NON-COMPLIANT + atan2(i, ul); // NON-COMPLIANT + atan2(i32, ul); // NON-COMPLIANT + atan2(ui, ul); // NON-COMPLIANT + atan2(u32, ul); // NON-COMPLIANT + atan2(ul, i); // NON-COMPLIANT + atan2(ul, ui); // NON-COMPLIANT + atan2(ul, i32); // NON-COMPLIANT + atan2(ul, u32); // NON-COMPLIANT + atan2(i, i64); // NON-COMPLIANT + atan2(i32, i64); // NON-COMPLIANT + atan2(ui, i64); // NON-COMPLIANT + atan2(u32, i64); // NON-COMPLIANT + atan2(i64, i); // NON-COMPLIANT + atan2(i64, ui); // NON-COMPLIANT + atan2(i64, i32); // NON-COMPLIANT + atan2(i64, u32); // NON-COMPLIANT + atan2(i, u64); // NON-COMPLIANT + atan2(i32, u64); // NON-COMPLIANT + atan2(ui, u64); // NON-COMPLIANT + atan2(u32, u64); // NON-COMPLIANT + atan2(u64, i); // NON-COMPLIANT + atan2(u64, ui); // NON-COMPLIANT + atan2(u64, i32); // NON-COMPLIANT + atan2(u64, u32); // NON-COMPLIANT + + /** Signed vs unsigned long, since those don't promote */ + atan2(l, ul); // NON-COMPLIANT + atan2(l, u64); // NON-COMPLIANT + atan2(i64, ul); // NON-COMPLIANT + atan2(i64, u64); // NON-COMPLIANT + atan2(ul, l); // NON-COMPLIANT + atan2(ul, i64); // NON-COMPLIANT + atan2(u64, l); // NON-COMPLIANT + atan2(u64, i64); // NON-COMPLIANT + + /** Mismatched float sizes */ + atan2(f, d); // NON-COMPLIANT + atan2(f, ld); // NON-COMPLIANT + atan2(d, f); // NON-COMPLIANT + atan2(d, ld); // NON-COMPLIANT + atan2(ld, f); // NON-COMPLIANT + atan2(ld, d); // NON-COMPLIANT + + /** Float vs int */ + atan2(c, f); // NON-COMPLIANT + atan2(c, d); // NON-COMPLIANT + atan2(c, ld); // NON-COMPLIANT + atan2(i8, f); // NON-COMPLIANT + atan2(i8, d); // NON-COMPLIANT + atan2(i8, ld); // NON-COMPLIANT + atan2(uc, f); // NON-COMPLIANT + atan2(uc, d); // NON-COMPLIANT + atan2(uc, ld); // NON-COMPLIANT + atan2(u8, f); // NON-COMPLIANT + atan2(u8, d); // NON-COMPLIANT + atan2(u8, ld); // NON-COMPLIANT + atan2(s, f); // NON-COMPLIANT + atan2(s, d); // NON-COMPLIANT + atan2(s, ld); // NON-COMPLIANT + atan2(i16, f); // NON-COMPLIANT + atan2(i16, d); // NON-COMPLIANT + atan2(i16, ld); // NON-COMPLIANT + atan2(us, f); // NON-COMPLIANT + atan2(us, d); // NON-COMPLIANT + atan2(us, ld); // NON-COMPLIANT + atan2(u16, f); // NON-COMPLIANT + atan2(u16, d); // NON-COMPLIANT + atan2(u16, ld); // NON-COMPLIANT + atan2(i, f); // NON-COMPLIANT + atan2(i, d); // NON-COMPLIANT + atan2(i, ld); // NON-COMPLIANT + atan2(i32, f); // NON-COMPLIANT + atan2(i32, d); // NON-COMPLIANT + atan2(i32, ld); // NON-COMPLIANT + atan2(ui, f); // NON-COMPLIANT + atan2(ui, d); // NON-COMPLIANT + atan2(ui, ld); // NON-COMPLIANT + atan2(u32, f); // NON-COMPLIANT + atan2(u32, d); // NON-COMPLIANT + atan2(u32, ld); // NON-COMPLIANT + atan2(l, f); // NON-COMPLIANT + atan2(l, d); // NON-COMPLIANT + atan2(l, ld); // NON-COMPLIANT + atan2(i64, f); // NON-COMPLIANT + atan2(i64, d); // NON-COMPLIANT + atan2(i64, ld); // NON-COMPLIANT + atan2(ul, f); // NON-COMPLIANT + atan2(ul, d); // NON-COMPLIANT + atan2(ul, ld); // NON-COMPLIANT + atan2(u64, f); // NON-COMPLIANT + atan2(u64, d); // NON-COMPLIANT + atan2(u64, ld); // NON-COMPLIANT + + /** Casts and conversions */ + atan2((float)i, f); // COMPLIANT + atan2(i, (int)f); // COMPLIANT + atan2((i), f); // NON-COMPLIANT + atan2(((float)i), f); // COMPLIANT + atan2((float)((int)l), f); // COMPLIANT + + /** Other functions */ + copysign(f, f); // COMPLIANT + copysign(i, i); // COMPLIANT + copysign(i, f); // NON-COMPLIANT + fdim(f, f); // COMPLIANT + fdim(i, i); // COMPLIANT + fdim(i, f); // NON-COMPLIANT + fma(f, f, f); // COMPLIANT + fma(i, i, i); // COMPLIANT + fma(f, i, i); // NON-COMPLIANT + fma(i, f, i); // NON-COMPLIANT + fma(i, i, f); // NON-COMPLIANT + fmax(f, f); // COMPLIANT + fmax(i, i); // COMPLIANT + fmax(i, f); // NON-COMPLIANT + fmin(f, f); // COMPLIANT + fmin(i, i); // COMPLIANT + fmin(i, f); // NON-COMPLIANT + fmod(f, f); // COMPLIANT + fmod(i, i); // COMPLIANT + fmod(i, f); // NON-COMPLIANT + hypot(f, f); // COMPLIANT + hypot(i, i); // COMPLIANT + hypot(i, f); // NON-COMPLIANT + ldexp(f, f); // COMPLIANT + ldexp(i, i); // COMPLIANT + ldexp(i, f); // NON-COMPLIANT + nextafter(f, f); // COMPLIANT + nextafter(i, i); // COMPLIANT + nextafter(i, f); // NON-COMPLIANT + nexttoward(f, f); // COMPLIANT + nexttoward(i, i); // COMPLIANT + nexttoward(i, f); // NON-COMPLIANT + remainder(f, f); // COMPLIANT + remainder(i, i); // COMPLIANT + remainder(i, f); // NON-COMPLIANT + remquo(f, f, 0); // COMPLIANT + remquo(i, i, 0); // COMPLIANT + remquo(i, f, 0); // NON-COMPLIANT + scalbln(f, f); // COMPLIANT + scalbln(i, i); // COMPLIANT + scalbln(i, f); // NON-COMPLIANT + scalbn(f, f); // COMPLIANT + scalbn(i, i); // COMPLIANT + scalbn(i, f); // NON-COMPLIANT + + // `frexp` has two parameters, but the second is an output parameter, and + // should not be covered by this rule. + frexp(f, 0); // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-24/CallToBannedRandomFunction.expected b/c/misra/test/rules/RULE-21-24/CallToBannedRandomFunction.expected new file mode 100644 index 0000000000..b3953d166b --- /dev/null +++ b/c/misra/test/rules/RULE-21-24/CallToBannedRandomFunction.expected @@ -0,0 +1,2 @@ +| test.c:5:3:5:7 | call to srand | Call to banned random number generation function 'srand'. | +| test.c:6:11:6:14 | call to rand | Call to banned random number generation function 'rand'. | diff --git a/c/misra/test/rules/RULE-21-24/CallToBannedRandomFunction.qlref b/c/misra/test/rules/RULE-21-24/CallToBannedRandomFunction.qlref new file mode 100644 index 0000000000..b229c0e84f --- /dev/null +++ b/c/misra/test/rules/RULE-21-24/CallToBannedRandomFunction.qlref @@ -0,0 +1 @@ +rules/RULE-21-24/CallToBannedRandomFunction.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-24/test.c b/c/misra/test/rules/RULE-21-24/test.c new file mode 100644 index 0000000000..56cfae3cb1 --- /dev/null +++ b/c/misra/test/rules/RULE-21-24/test.c @@ -0,0 +1,11 @@ +#include "stdlib.h" + +void f() { + // rand() is banned -- and thus, so is srand(). + srand(0); // NON-COMPLIANT + int x = rand(); // NON-COMPLIANT + + // Other functions from stdlib are not banned by this rule. + x = abs(-4); // COMPLIANT + getenv("ENV_VAR"); // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected b/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected new file mode 100644 index 0000000000..0b17405a0e --- /dev/null +++ b/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected @@ -0,0 +1,106 @@ +edges +| test.c:4:5:4:6 | *g2 | test.c:54:33:54:34 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:55:29:55:30 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:56:42:56:43 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:57:35:57:36 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:58:36:58:37 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:59:56:59:57 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:60:60:60:61 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:61:54:61:55 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:62:58:62:59 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:63:37:63:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:64:37:64:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:65:36:65:37 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:66:37:66:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:67:37:67:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:68:23:68:24 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:69:23:69:24 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:72:23:72:24 | g2 | provenance | | +| test.c:4:10:4:29 | memory_order_relaxed | test.c:4:5:4:6 | *g2 | provenance | | +| test.c:4:10:4:29 | memory_order_relaxed | test.c:4:10:4:29 | memory_order_relaxed | provenance | | +| test.c:5:5:5:6 | *g3 | test.c:73:23:73:24 | g3 | provenance | | +| test.c:5:10:5:29 | memory_order_acquire | test.c:5:5:5:6 | *g3 | provenance | | +| test.c:5:10:5:29 | memory_order_acquire | test.c:5:10:5:29 | memory_order_acquire | provenance | | +| test.c:6:5:6:6 | *g4 | test.c:74:23:74:24 | g4 | provenance | | +| test.c:6:10:6:29 | memory_order_consume | test.c:6:5:6:6 | *g4 | provenance | | +| test.c:6:10:6:29 | memory_order_consume | test.c:6:10:6:29 | memory_order_consume | provenance | | +| test.c:7:5:7:6 | *g5 | test.c:75:23:75:24 | g5 | provenance | | +| test.c:7:10:7:29 | memory_order_acq_rel | test.c:7:5:7:6 | *g5 | provenance | | +| test.c:7:10:7:29 | memory_order_acq_rel | test.c:7:10:7:29 | memory_order_acq_rel | provenance | | +| test.c:8:5:8:6 | *g6 | test.c:76:23:76:24 | g6 | provenance | | +| test.c:8:10:8:29 | memory_order_release | test.c:8:5:8:6 | *g6 | provenance | | +| test.c:8:10:8:29 | memory_order_release | test.c:8:10:8:29 | memory_order_release | provenance | | +nodes +| test.c:4:5:4:6 | *g2 | semmle.label | *g2 | +| test.c:4:10:4:29 | memory_order_relaxed | semmle.label | memory_order_relaxed | +| test.c:4:10:4:29 | memory_order_relaxed | semmle.label | memory_order_relaxed | +| test.c:5:5:5:6 | *g3 | semmle.label | *g3 | +| test.c:5:10:5:29 | memory_order_acquire | semmle.label | memory_order_acquire | +| test.c:5:10:5:29 | memory_order_acquire | semmle.label | memory_order_acquire | +| test.c:6:5:6:6 | *g4 | semmle.label | *g4 | +| test.c:6:10:6:29 | memory_order_consume | semmle.label | memory_order_consume | +| test.c:6:10:6:29 | memory_order_consume | semmle.label | memory_order_consume | +| test.c:7:5:7:6 | *g5 | semmle.label | *g5 | +| test.c:7:10:7:29 | memory_order_acq_rel | semmle.label | memory_order_acq_rel | +| test.c:7:10:7:29 | memory_order_acq_rel | semmle.label | memory_order_acq_rel | +| test.c:8:5:8:6 | *g6 | semmle.label | *g6 | +| test.c:8:10:8:29 | memory_order_release | semmle.label | memory_order_release | +| test.c:8:10:8:29 | memory_order_release | semmle.label | memory_order_release | +| test.c:17:29:17:48 | memory_order_relaxed | semmle.label | memory_order_relaxed | +| test.c:18:29:18:48 | memory_order_acquire | semmle.label | memory_order_acquire | +| test.c:19:29:19:48 | memory_order_consume | semmle.label | memory_order_consume | +| test.c:20:29:20:48 | memory_order_acq_rel | semmle.label | memory_order_acq_rel | +| test.c:21:29:21:48 | memory_order_release | semmle.label | memory_order_release | +| test.c:54:33:54:34 | g2 | semmle.label | g2 | +| test.c:55:29:55:30 | g2 | semmle.label | g2 | +| test.c:56:42:56:43 | g2 | semmle.label | g2 | +| test.c:57:35:57:36 | g2 | semmle.label | g2 | +| test.c:58:36:58:37 | g2 | semmle.label | g2 | +| test.c:59:56:59:57 | g2 | semmle.label | g2 | +| test.c:60:60:60:61 | g2 | semmle.label | g2 | +| test.c:61:54:61:55 | g2 | semmle.label | g2 | +| test.c:62:58:62:59 | g2 | semmle.label | g2 | +| test.c:63:37:63:38 | g2 | semmle.label | g2 | +| test.c:64:37:64:38 | g2 | semmle.label | g2 | +| test.c:65:36:65:37 | g2 | semmle.label | g2 | +| test.c:66:37:66:38 | g2 | semmle.label | g2 | +| test.c:67:37:67:38 | g2 | semmle.label | g2 | +| test.c:68:23:68:24 | g2 | semmle.label | g2 | +| test.c:69:23:69:24 | g2 | semmle.label | g2 | +| test.c:72:23:72:24 | g2 | semmle.label | g2 | +| test.c:73:23:73:24 | g3 | semmle.label | g3 | +| test.c:74:23:74:24 | g4 | semmle.label | g4 | +| test.c:75:23:75:24 | g5 | semmle.label | g5 | +| test.c:76:23:76:24 | g6 | semmle.label | g6 | +| test.c:80:23:80:23 | 1 | semmle.label | 1 | +| test.c:81:23:81:25 | 100 | semmle.label | 100 | +subpaths +#select +| test.c:17:29:17:48 | memory_order_relaxed | test.c:17:29:17:48 | memory_order_relaxed | test.c:17:29:17:48 | memory_order_relaxed | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:18:29:18:48 | memory_order_acquire | test.c:18:29:18:48 | memory_order_acquire | test.c:18:29:18:48 | memory_order_acquire | Invalid memory order '$@' in call to function '$@'. | memory_order_acquire | memory_order_acquire | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:19:29:19:48 | memory_order_consume | test.c:19:29:19:48 | memory_order_consume | test.c:19:29:19:48 | memory_order_consume | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:20:29:20:48 | memory_order_acq_rel | test.c:20:29:20:48 | memory_order_acq_rel | test.c:20:29:20:48 | memory_order_acq_rel | Invalid memory order '$@' in call to function '$@'. | memory_order_acq_rel | memory_order_acq_rel | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:21:29:21:48 | memory_order_release | test.c:21:29:21:48 | memory_order_release | test.c:21:29:21:48 | memory_order_release | Invalid memory order '$@' in call to function '$@'. | memory_order_release | memory_order_release | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:54:33:54:34 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:54:33:54:34 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_store_explicit | +| test.c:55:29:55:30 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:55:29:55:30 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:56:42:56:43 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:56:42:56:43 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_flag_test_and_set_explicit | +| test.c:57:35:57:36 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:57:35:57:36 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_flag_clear_explicit | +| test.c:58:36:58:37 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:58:36:58:37 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_exchange_explicit | +| test.c:59:56:59:57 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:59:56:59:57 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_compare_exchange_strong_explicit | +| test.c:60:60:60:61 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:60:60:60:61 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_compare_exchange_strong_explicit | +| test.c:61:54:61:55 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:61:54:61:55 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_compare_exchange_weak_explicit | +| test.c:62:58:62:59 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:62:58:62:59 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_compare_exchange_weak_explicit | +| test.c:63:37:63:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:63:37:63:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_add_explicit | +| test.c:64:37:64:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:64:37:64:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_sub_explicit | +| test.c:65:36:65:37 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:65:36:65:37 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_or_explicit | +| test.c:66:37:66:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:66:37:66:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_xor_explicit | +| test.c:67:37:67:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:67:37:67:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_and_explicit | +| test.c:68:23:68:24 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:68:23:68:24 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:69:23:69:24 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:69:23:69:24 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_signal_fence | +| test.c:72:23:72:24 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:72:23:72:24 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:73:23:73:24 | g3 | test.c:5:10:5:29 | memory_order_acquire | test.c:73:23:73:24 | g3 | Invalid memory order '$@' in call to function '$@'. | memory_order_acquire | memory_order_acquire | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:74:23:74:24 | g4 | test.c:6:10:6:29 | memory_order_consume | test.c:74:23:74:24 | g4 | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:75:23:75:24 | g5 | test.c:7:10:7:29 | memory_order_acq_rel | test.c:75:23:75:24 | g5 | Invalid memory order '$@' in call to function '$@'. | memory_order_acq_rel | memory_order_acq_rel | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:76:23:76:24 | g6 | test.c:8:10:8:29 | memory_order_release | test.c:76:23:76:24 | g6 | Invalid memory order '$@' in call to function '$@'. | memory_order_release | memory_order_release | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:80:23:80:23 | 1 | test.c:80:23:80:23 | 1 | test.c:80:23:80:23 | 1 | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:81:23:81:25 | 100 | test.c:81:23:81:25 | 100 | test.c:81:23:81:25 | 100 | Invalid memory order '$@' in call to function '$@'. | 100 | 100 | Invocation of a standard function implemented as a macro | atomic_thread_fence | diff --git a/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected.gcc b/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected.gcc new file mode 100644 index 0000000000..db07e0aa33 --- /dev/null +++ b/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected.gcc @@ -0,0 +1,106 @@ +edges +| test.c:4:5:4:6 | *g2 | test.c:54:33:54:34 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:55:29:55:30 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:56:42:56:43 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:57:35:57:36 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:58:36:58:37 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:59:56:59:57 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:60:60:60:61 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:61:54:61:55 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:62:58:62:59 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:63:37:63:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:64:37:64:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:65:36:65:37 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:66:37:66:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:67:37:67:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:68:23:68:24 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:69:23:69:24 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:72:23:72:24 | g2 | provenance | | +| test.c:4:10:4:29 | memory_order_relaxed | test.c:4:5:4:6 | *g2 | provenance | | +| test.c:4:10:4:29 | memory_order_relaxed | test.c:4:10:4:29 | memory_order_relaxed | provenance | | +| test.c:5:5:5:6 | *g3 | test.c:73:23:73:24 | g3 | provenance | | +| test.c:5:10:5:29 | memory_order_acquire | test.c:5:5:5:6 | *g3 | provenance | | +| test.c:5:10:5:29 | memory_order_acquire | test.c:5:10:5:29 | memory_order_acquire | provenance | | +| test.c:6:5:6:6 | *g4 | test.c:74:23:74:24 | g4 | provenance | | +| test.c:6:10:6:29 | memory_order_consume | test.c:6:5:6:6 | *g4 | provenance | | +| test.c:6:10:6:29 | memory_order_consume | test.c:6:10:6:29 | memory_order_consume | provenance | | +| test.c:7:5:7:6 | *g5 | test.c:75:23:75:24 | g5 | provenance | | +| test.c:7:10:7:29 | memory_order_acq_rel | test.c:7:5:7:6 | *g5 | provenance | | +| test.c:7:10:7:29 | memory_order_acq_rel | test.c:7:10:7:29 | memory_order_acq_rel | provenance | | +| test.c:8:5:8:6 | *g6 | test.c:76:23:76:24 | g6 | provenance | | +| test.c:8:10:8:29 | memory_order_release | test.c:8:5:8:6 | *g6 | provenance | | +| test.c:8:10:8:29 | memory_order_release | test.c:8:10:8:29 | memory_order_release | provenance | | +nodes +| test.c:4:5:4:6 | *g2 | semmle.label | *g2 | +| test.c:4:10:4:29 | memory_order_relaxed | semmle.label | memory_order_relaxed | +| test.c:4:10:4:29 | memory_order_relaxed | semmle.label | memory_order_relaxed | +| test.c:5:5:5:6 | *g3 | semmle.label | *g3 | +| test.c:5:10:5:29 | memory_order_acquire | semmle.label | memory_order_acquire | +| test.c:5:10:5:29 | memory_order_acquire | semmle.label | memory_order_acquire | +| test.c:6:5:6:6 | *g4 | semmle.label | *g4 | +| test.c:6:10:6:29 | memory_order_consume | semmle.label | memory_order_consume | +| test.c:6:10:6:29 | memory_order_consume | semmle.label | memory_order_consume | +| test.c:7:5:7:6 | *g5 | semmle.label | *g5 | +| test.c:7:10:7:29 | memory_order_acq_rel | semmle.label | memory_order_acq_rel | +| test.c:7:10:7:29 | memory_order_acq_rel | semmle.label | memory_order_acq_rel | +| test.c:8:5:8:6 | *g6 | semmle.label | *g6 | +| test.c:8:10:8:29 | memory_order_release | semmle.label | memory_order_release | +| test.c:8:10:8:29 | memory_order_release | semmle.label | memory_order_release | +| test.c:17:3:17:49 | memory_order_relaxed | semmle.label | memory_order_relaxed | +| test.c:18:3:18:49 | memory_order_acquire | semmle.label | memory_order_acquire | +| test.c:19:3:19:49 | memory_order_consume | semmle.label | memory_order_consume | +| test.c:20:3:20:49 | memory_order_acq_rel | semmle.label | memory_order_acq_rel | +| test.c:21:3:21:49 | memory_order_release | semmle.label | memory_order_release | +| test.c:54:33:54:34 | g2 | semmle.label | g2 | +| test.c:55:29:55:30 | g2 | semmle.label | g2 | +| test.c:56:42:56:43 | g2 | semmle.label | g2 | +| test.c:57:35:57:36 | g2 | semmle.label | g2 | +| test.c:58:36:58:37 | g2 | semmle.label | g2 | +| test.c:59:56:59:57 | g2 | semmle.label | g2 | +| test.c:60:60:60:61 | g2 | semmle.label | g2 | +| test.c:61:54:61:55 | g2 | semmle.label | g2 | +| test.c:62:58:62:59 | g2 | semmle.label | g2 | +| test.c:63:37:63:38 | g2 | semmle.label | g2 | +| test.c:64:37:64:38 | g2 | semmle.label | g2 | +| test.c:65:36:65:37 | g2 | semmle.label | g2 | +| test.c:66:37:66:38 | g2 | semmle.label | g2 | +| test.c:67:37:67:38 | g2 | semmle.label | g2 | +| test.c:68:23:68:24 | g2 | semmle.label | g2 | +| test.c:69:23:69:24 | g2 | semmle.label | g2 | +| test.c:72:23:72:24 | g2 | semmle.label | g2 | +| test.c:73:23:73:24 | g3 | semmle.label | g3 | +| test.c:74:23:74:24 | g4 | semmle.label | g4 | +| test.c:75:23:75:24 | g5 | semmle.label | g5 | +| test.c:76:23:76:24 | g6 | semmle.label | g6 | +| test.c:80:23:80:23 | 1 | semmle.label | 1 | +| test.c:81:23:81:25 | 100 | semmle.label | 100 | +subpaths +#select +| test.c:17:3:17:49 | memory_order_relaxed | test.c:17:3:17:49 | memory_order_relaxed | test.c:17:3:17:49 | memory_order_relaxed | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:18:3:18:49 | memory_order_acquire | test.c:18:3:18:49 | memory_order_acquire | test.c:18:3:18:49 | memory_order_acquire | Invalid memory order '$@' in call to function '$@'. | memory_order_acquire | memory_order_acquire | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:19:3:19:49 | memory_order_consume | test.c:19:3:19:49 | memory_order_consume | test.c:19:3:19:49 | memory_order_consume | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:20:3:20:49 | memory_order_acq_rel | test.c:20:3:20:49 | memory_order_acq_rel | test.c:20:3:20:49 | memory_order_acq_rel | Invalid memory order '$@' in call to function '$@'. | memory_order_acq_rel | memory_order_acq_rel | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:21:3:21:49 | memory_order_release | test.c:21:3:21:49 | memory_order_release | test.c:21:3:21:49 | memory_order_release | Invalid memory order '$@' in call to function '$@'. | memory_order_release | memory_order_release | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:54:33:54:34 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:54:33:54:34 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_store_explicit | +| test.c:55:29:55:30 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:55:29:55:30 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:56:42:56:43 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:56:42:56:43 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_flag_test_and_set_explicit | +| test.c:57:35:57:36 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:57:35:57:36 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_flag_clear_explicit | +| test.c:58:36:58:37 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:58:36:58:37 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_exchange_explicit | +| test.c:59:56:59:57 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:59:56:59:57 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_compare_exchange_strong_explicit | +| test.c:60:60:60:61 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:60:60:60:61 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_compare_exchange_strong_explicit | +| test.c:61:54:61:55 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:61:54:61:55 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_compare_exchange_weak_explicit | +| test.c:62:58:62:59 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:62:58:62:59 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_compare_exchange_weak_explicit | +| test.c:63:37:63:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:63:37:63:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_add_explicit | +| test.c:64:37:64:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:64:37:64:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_sub_explicit | +| test.c:65:36:65:37 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:65:36:65:37 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_or_explicit | +| test.c:66:37:66:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:66:37:66:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_xor_explicit | +| test.c:67:37:67:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:67:37:67:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_and_explicit | +| test.c:68:23:68:24 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:68:23:68:24 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:69:23:69:24 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:69:23:69:24 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_signal_fence | +| test.c:72:23:72:24 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:72:23:72:24 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:73:23:73:24 | g3 | test.c:5:10:5:29 | memory_order_acquire | test.c:73:23:73:24 | g3 | Invalid memory order '$@' in call to function '$@'. | memory_order_acquire | memory_order_acquire | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:74:23:74:24 | g4 | test.c:6:10:6:29 | memory_order_consume | test.c:74:23:74:24 | g4 | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:75:23:75:24 | g5 | test.c:7:10:7:29 | memory_order_acq_rel | test.c:75:23:75:24 | g5 | Invalid memory order '$@' in call to function '$@'. | memory_order_acq_rel | memory_order_acq_rel | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:76:23:76:24 | g6 | test.c:8:10:8:29 | memory_order_release | test.c:76:23:76:24 | g6 | Invalid memory order '$@' in call to function '$@'. | memory_order_release | memory_order_release | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:80:23:80:23 | 1 | test.c:80:23:80:23 | 1 | test.c:80:23:80:23 | 1 | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:81:23:81:25 | 100 | test.c:81:23:81:25 | 100 | test.c:81:23:81:25 | 100 | Invalid memory order '$@' in call to function '$@'. | 100 | 100 | Invocation of a standard function implemented as a macro | atomic_thread_fence | diff --git a/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.qlref b/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.qlref new file mode 100644 index 0000000000..5c205adc24 --- /dev/null +++ b/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.qlref @@ -0,0 +1 @@ +rules/RULE-21-25/InvalidMemoryOrderArgument.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-25/test.c b/c/misra/test/rules/RULE-21-25/test.c new file mode 100644 index 0000000000..d096634d30 --- /dev/null +++ b/c/misra/test/rules/RULE-21-25/test.c @@ -0,0 +1,86 @@ +#include + +int g1 = memory_order_seq_cst; +int g2 = memory_order_relaxed; +int g3 = memory_order_acquire; +int g4 = memory_order_consume; +int g5 = memory_order_acq_rel; +int g6 = memory_order_release; +int *ptr; + +void f(int p) { + _Atomic int l1; + atomic_flag l2; + + // Directly specified values: + atomic_load_explicit(&l1, memory_order_seq_cst); // COMPLIANT + atomic_load_explicit(&l1, memory_order_relaxed); // NON-COMPLIANT + atomic_load_explicit(&l1, memory_order_acquire); // NON-COMPLIANT + atomic_load_explicit(&l1, memory_order_consume); // NON-COMPLIANT + atomic_load_explicit(&l1, memory_order_acq_rel); // NON-COMPLIANT + atomic_load_explicit(&l1, memory_order_release); // NON-COMPLIANT + + // Implicit values: + atomic_store(&l1, 0); // COMPLIANT + atomic_load(&l1); // COMPLIANT + atomic_flag_test_and_set(&l2); // COMPLIANT + atomic_flag_clear(&l2); // COMPLIANT + atomic_exchange(&l1, 0); // COMPLIANT + atomic_compare_exchange_strong(&l1, ptr, 1); // COMPLIANT + atomic_compare_exchange_weak(&l1, ptr, 1); // COMPLIANT + atomic_fetch_add(&l1, 0); // COMPLIANT + atomic_fetch_sub(&l1, 0); // COMPLIANT + atomic_fetch_or(&l1, 0); // COMPLIANT + atomic_fetch_xor(&l1, 0); // COMPLIANT + atomic_fetch_and(&l1, 0); // COMPLIANT + + // Compliant flowed values (one test per sink): + atomic_store_explicit(&l1, 0, g1); // COMPLIANT + atomic_load_explicit(&l1, g1); // COMPLIANT + atomic_flag_test_and_set_explicit(&l2, g1); // COMPLIANT + atomic_flag_clear_explicit(&l2, g1); // COMPLIANT + atomic_exchange_explicit(&l1, 0, g1); // COMPLIANT + atomic_compare_exchange_strong_explicit(&l1, ptr, 1, g1, g1); // COMPLIANT + atomic_compare_exchange_weak_explicit(&l1, ptr, 1, g1, g1); // COMPLIANT + atomic_fetch_add_explicit(&l1, 0, g1); // COMPLIANT + atomic_fetch_sub_explicit(&l1, 0, g1); // COMPLIANT + atomic_fetch_or_explicit(&l1, 0, g1); // COMPLIANT + atomic_fetch_xor_explicit(&l1, 0, g1); // COMPLIANT + atomic_fetch_and_explicit(&l1, 0, g1); // COMPLIANT + atomic_thread_fence(g1); // COMPLIANT + atomic_signal_fence(g1); // COMPLIANT + + // Non-compliant flowed values (one test per sink): + atomic_store_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_load_explicit(&l1, g2); // NON-COMPLIANT + atomic_flag_test_and_set_explicit(&l2, g2); // NON-COMPLIANT + atomic_flag_clear_explicit(&l2, g2); // NON-COMPLIANT + atomic_exchange_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_compare_exchange_strong_explicit(&l1, ptr, 1, g2, g1); // NON-COMPLIANT + atomic_compare_exchange_strong_explicit(&l1, ptr, 1, g1, g2); // NON-COMPLIANT + atomic_compare_exchange_weak_explicit(&l1, ptr, 1, g2, g1); // NON-COMPLIANT + atomic_compare_exchange_weak_explicit(&l1, ptr, 1, g1, g2); // NON-COMPLIANT + atomic_fetch_add_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_fetch_sub_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_fetch_or_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_fetch_xor_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_fetch_and_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_thread_fence(g2); // NON-COMPLIANT + atomic_signal_fence(g2); // NON-COMPLIANT + + // Non-compliant flowed values (one test per source): + atomic_thread_fence(g2); // NON-COMPLIANT + atomic_thread_fence(g3); // NON-COMPLIANT + atomic_thread_fence(g4); // NON-COMPLIANT + atomic_thread_fence(g5); // NON-COMPLIANT + atomic_thread_fence(g6); // NON-COMPLIANT + + // Computed flow sources: + atomic_thread_fence(memory_order_seq_cst * 1); // COMPLIANT + atomic_thread_fence(1); // NON-COMPLIANT + atomic_thread_fence(100); // NON-COMPLIANT + atomic_thread_fence(g1 + 1); // NON_COMPLIANT[FALSE_NEGATIVE] + + // No unsafe flow, currently accepted: + atomic_thread_fence(p); // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-26/TimedlockOnInappropriateMutexType.expected b/c/misra/test/rules/RULE-21-26/TimedlockOnInappropriateMutexType.expected new file mode 100644 index 0000000000..0a4c0a496a --- /dev/null +++ b/c/misra/test/rules/RULE-21-26/TimedlockOnInappropriateMutexType.expected @@ -0,0 +1,45 @@ +edges +| test.c:10:24:10:24 | *m | test.c:10:43:10:43 | *m | provenance | | +| test.c:13:12:13:14 | mtx_init output argument | test.c:14:17:14:19 | *& ... | provenance | | +| test.c:13:12:13:14 | mtx_init output argument | test.c:15:14:15:16 | *& ... | provenance | | +| test.c:15:14:15:16 | *& ... | test.c:10:24:10:24 | *m | provenance | | +| test.c:17:12:17:14 | mtx_init output argument | test.c:18:17:18:19 | *& ... | provenance | | +| test.c:17:12:17:14 | mtx_init output argument | test.c:19:14:19:16 | *& ... | provenance | | +| test.c:19:14:19:16 | *& ... | test.c:10:24:10:24 | *m | provenance | | +| test.c:30:12:30:14 | mtx_init output argument | test.c:31:17:31:19 | *& ... | provenance | | +| test.c:30:12:30:14 | mtx_init output argument | test.c:32:14:32:16 | *& ... | provenance | | +| test.c:32:14:32:16 | *& ... | test.c:10:24:10:24 | *m | provenance | | +| test.c:42:12:42:16 | mtx_init output argument | test.c:42:13:42:14 | *l3 [post update] [m] | provenance | | +| test.c:42:13:42:14 | *l3 [post update] [m] | test.c:43:18:43:19 | *l3 [m] | provenance | | +| test.c:42:13:42:14 | *l3 [post update] [m] | test.c:44:15:44:16 | *l3 [m] | provenance | | +| test.c:43:18:43:19 | *l3 [m] | test.c:43:17:43:21 | *& ... | provenance | | +| test.c:44:14:44:18 | *& ... | test.c:10:24:10:24 | *m | provenance | | +| test.c:44:15:44:16 | *l3 [m] | test.c:44:14:44:18 | *& ... | provenance | | +nodes +| test.c:10:24:10:24 | *m | semmle.label | *m | +| test.c:10:43:10:43 | *m | semmle.label | *m | +| test.c:13:12:13:14 | mtx_init output argument | semmle.label | mtx_init output argument | +| test.c:14:17:14:19 | *& ... | semmle.label | *& ... | +| test.c:15:14:15:16 | *& ... | semmle.label | *& ... | +| test.c:17:12:17:14 | mtx_init output argument | semmle.label | mtx_init output argument | +| test.c:18:17:18:19 | *& ... | semmle.label | *& ... | +| test.c:19:14:19:16 | *& ... | semmle.label | *& ... | +| test.c:30:12:30:14 | mtx_init output argument | semmle.label | mtx_init output argument | +| test.c:31:17:31:19 | *& ... | semmle.label | *& ... | +| test.c:32:14:32:16 | *& ... | semmle.label | *& ... | +| test.c:42:12:42:16 | mtx_init output argument | semmle.label | mtx_init output argument | +| test.c:42:13:42:14 | *l3 [post update] [m] | semmle.label | *l3 [post update] [m] | +| test.c:43:17:43:21 | *& ... | semmle.label | *& ... | +| test.c:43:18:43:19 | *l3 [m] | semmle.label | *l3 [m] | +| test.c:44:14:44:18 | *& ... | semmle.label | *& ... | +| test.c:44:15:44:16 | *l3 [m] | semmle.label | *l3 [m] | +subpaths +#select +| test.c:10:43:10:43 | *m | test.c:13:12:13:14 | mtx_init output argument | test.c:10:43:10:43 | *m | Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'. | test.c:13:12:13:14 | mtx_init output argument | initialized | +| test.c:10:43:10:43 | *m | test.c:17:12:17:14 | mtx_init output argument | test.c:10:43:10:43 | *m | Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'. | test.c:17:12:17:14 | mtx_init output argument | initialized | +| test.c:10:43:10:43 | *m | test.c:30:12:30:14 | mtx_init output argument | test.c:10:43:10:43 | *m | Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'. | test.c:30:12:30:14 | mtx_init output argument | initialized | +| test.c:10:43:10:43 | *m | test.c:42:12:42:16 | mtx_init output argument | test.c:10:43:10:43 | *m | Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'. | test.c:42:12:42:16 | mtx_init output argument | initialized | +| test.c:14:17:14:19 | *& ... | test.c:13:12:13:14 | mtx_init output argument | test.c:14:17:14:19 | *& ... | Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'. | test.c:13:12:13:14 | mtx_init output argument | initialized | +| test.c:18:17:18:19 | *& ... | test.c:17:12:17:14 | mtx_init output argument | test.c:18:17:18:19 | *& ... | Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'. | test.c:17:12:17:14 | mtx_init output argument | initialized | +| test.c:31:17:31:19 | *& ... | test.c:30:12:30:14 | mtx_init output argument | test.c:31:17:31:19 | *& ... | Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'. | test.c:30:12:30:14 | mtx_init output argument | initialized | +| test.c:43:17:43:21 | *& ... | test.c:42:12:42:16 | mtx_init output argument | test.c:43:17:43:21 | *& ... | Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'. | test.c:42:12:42:16 | mtx_init output argument | initialized | diff --git a/c/misra/test/rules/RULE-21-26/TimedlockOnInappropriateMutexType.qlref b/c/misra/test/rules/RULE-21-26/TimedlockOnInappropriateMutexType.qlref new file mode 100644 index 0000000000..9ffe7e7494 --- /dev/null +++ b/c/misra/test/rules/RULE-21-26/TimedlockOnInappropriateMutexType.qlref @@ -0,0 +1 @@ +rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-26/test.c b/c/misra/test/rules/RULE-21-26/test.c new file mode 100644 index 0000000000..b08f7e54a1 --- /dev/null +++ b/c/misra/test/rules/RULE-21-26/test.c @@ -0,0 +1,45 @@ +#include "threads.h" + +mtx_t g1; +mtx_t g2; +mtx_t g3; +mtx_t g4; + +struct timespec ts = {0, 0}; + +void doTimeLock(mtx_t *m) { mtx_timedlock(m, &ts); } + +int main(int argc, char *argv[]) { + mtx_init(&g1, mtx_plain); + mtx_timedlock(&g1, &ts); // NON-COMPLIANT + doTimeLock(&g1); // NON-COMPLIANT + + mtx_init(&g2, mtx_plain | mtx_recursive); + mtx_timedlock(&g2, &ts); // NON-COMPLIANT + doTimeLock(&g2); // NON-COMPLIANT + + mtx_init(&g3, mtx_timed); + mtx_timedlock(&g3, &ts); // COMPLIANT + doTimeLock(&g3); // COMPLIANT + + mtx_init(&g4, mtx_timed | mtx_recursive); + mtx_timedlock(&g4, &ts); // COMPLIANT + doTimeLock(&g4); // COMPLIANT + + mtx_t l1; + mtx_init(&l1, mtx_plain); + mtx_timedlock(&l1, &ts); // NON-COMPLIANT + doTimeLock(&l1); // NON-COMPLIANT + + mtx_t l2; + mtx_init(&l2, mtx_timed); + mtx_timedlock(&l2, &ts); // COMPLIANT + doTimeLock(&l2); // COMPLIANT + + struct s { + mtx_t m; + } l3; + mtx_init(&l3.m, mtx_plain); + mtx_timedlock(&l3.m, &ts); // NON-COMPLIANT + doTimeLock(&l3.m); // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-3/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected b/c/misra/test/rules/RULE-21-3/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected index 0215c2e5b8..e9ea6daecc 100644 --- a/c/misra/test/rules/RULE-21-3/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected +++ b/c/misra/test/rules/RULE-21-3/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected @@ -1,5 +1,5 @@ -| test.c:8:15:8:20 | call to malloc | Use of banned dynamic memory allocation. | -| test.c:9:15:9:20 | call to calloc | Use of banned dynamic memory allocation. | -| test.c:10:8:10:14 | call to realloc | Use of banned dynamic memory allocation. | -| test.c:11:3:11:6 | call to free | Use of banned dynamic memory deallocation. | -| test.c:12:3:12:6 | call to free | Use of banned dynamic memory deallocation. | +| test.c:13:15:13:20 | call to malloc | Use of banned dynamic memory allocation. | +| test.c:14:15:14:20 | call to calloc | Use of banned dynamic memory allocation. | +| test.c:15:8:15:14 | call to realloc | Use of banned dynamic memory allocation. | +| test.c:16:3:16:6 | call to free | Use of banned dynamic memory deallocation. | +| test.c:17:3:17:6 | call to free | Use of banned dynamic memory deallocation. | diff --git a/c/misra/test/rules/RULE-21-3/test.c b/c/misra/test/rules/RULE-21-3/test.c index d9aee3a322..fd4543faaf 100644 --- a/c/misra/test/rules/RULE-21-3/test.c +++ b/c/misra/test/rules/RULE-21-3/test.c @@ -1,3 +1,8 @@ +// Note: A subset of these cases are also tested in c/misra/test/rules/RULE-1-5 +// via a MemoryAllocDeallocFunctionsOfStdlibhUsed.qlref and .expected file in +// that directory. Changes to these tests may require updating the test code or +// expectations in that directory as well. + #include #include void f2(); diff --git a/c/misra/test/rules/RULE-21-6/StandardLibraryInputoutputFunctionsUsed.expected b/c/misra/test/rules/RULE-21-6/StandardLibraryInputoutputFunctionsUsed.expected index 0dee7e9b3d..672480db33 100644 --- a/c/misra/test/rules/RULE-21-6/StandardLibraryInputoutputFunctionsUsed.expected +++ b/c/misra/test/rules/RULE-21-6/StandardLibraryInputoutputFunctionsUsed.expected @@ -1,7 +1,7 @@ -| test.c:8:10:8:14 | call to scanf | Call to banned function scanf. | -| test.c:9:5:9:10 | call to printf | Call to banned function printf. | -| test.c:16:16:16:21 | call to fgetwc | Call to banned function fgetwc. | -| test.c:17:5:17:12 | call to putwchar | Call to banned function putwchar. | -| test.c:22:7:22:10 | call to puts | Call to banned function puts. | -| test.c:24:7:24:10 | call to puts | Call to banned function puts. | -| test.c:26:5:26:8 | call to puts | Call to banned function puts. | +| test.c:13:10:13:14 | call to scanf | Call to banned function scanf. | +| test.c:14:5:14:10 | call to printf | Call to banned function printf. | +| test.c:21:16:21:21 | call to fgetwc | Call to banned function fgetwc. | +| test.c:22:5:22:12 | call to putwchar | Call to banned function putwchar. | +| test.c:27:7:27:10 | call to puts | Call to banned function puts. | +| test.c:29:7:29:10 | call to puts | Call to banned function puts. | +| test.c:31:5:31:8 | call to puts | Call to banned function puts. | diff --git a/c/misra/test/rules/RULE-21-6/test.c b/c/misra/test/rules/RULE-21-6/test.c index 0ae580164e..b66bb9b6b7 100644 --- a/c/misra/test/rules/RULE-21-6/test.c +++ b/c/misra/test/rules/RULE-21-6/test.c @@ -1,3 +1,8 @@ +// Note: A subset of these cases are also tested in c/misra/test/rules/RULE-1-5 +// via a StandardLibraryInputoutputFunctionsUsed.qlref and .expected file in +// that directory. Changes to these tests may require updating the test code or +// expectations in that directory as well. + #include #include #include diff --git a/c/misra/test/rules/RULE-21-7/AtofAtoiAtolAndAtollOfStdlibhUsed.expected b/c/misra/test/rules/RULE-21-7/AtofAtoiAtolAndAtollOfStdlibhUsed.expected deleted file mode 100644 index 29a0c6fac1..0000000000 --- a/c/misra/test/rules/RULE-21-7/AtofAtoiAtolAndAtollOfStdlibhUsed.expected +++ /dev/null @@ -1,4 +0,0 @@ -| test.c:6:14:6:17 | call to atof | Call to banned function atof. | -| test.c:7:12:7:15 | call to atoi | Call to banned function atoi. | -| test.c:8:13:8:16 | call to atol | Call to banned function atol. | -| test.c:9:18:9:22 | call to atoll | Call to banned function atoll. | diff --git a/c/misra/test/rules/RULE-21-7/AtofAtoiAtolAndAtollOfStdlibhUsed.qlref b/c/misra/test/rules/RULE-21-7/AtofAtoiAtolAndAtollOfStdlibhUsed.qlref deleted file mode 100644 index 52e70db92b..0000000000 --- a/c/misra/test/rules/RULE-21-7/AtofAtoiAtolAndAtollOfStdlibhUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-21-7/AtofAtoiAtolAndAtollOfStdlibhUsed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-7/AtofAtoiAtolAndAtollOfStdlibhUsed.testref b/c/misra/test/rules/RULE-21-7/AtofAtoiAtolAndAtollOfStdlibhUsed.testref new file mode 100644 index 0000000000..fccafa2049 --- /dev/null +++ b/c/misra/test/rules/RULE-21-7/AtofAtoiAtolAndAtollOfStdlibhUsed.testref @@ -0,0 +1 @@ +c/common/test/rules/atofatoiatolandatollused/AtofAtoiAtolAndAtollUsed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-7/test.c b/c/misra/test/rules/RULE-21-7/test.c deleted file mode 100644 index 141dd061d3..0000000000 --- a/c/misra/test/rules/RULE-21-7/test.c +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include -void f2(); -void f1() { - char l1[5] = "abcde"; - float l2 = atof(l1); // NON_COMLIANT - int l3 = atoi(l1); // NON_COMPLIANT - long l4 = atol(l1); // NON_COMPLIANT - long long l5 = atoll(l1); // NON_COMPLIANT - f2(); // COMPLIANT -} diff --git a/c/misra/test/rules/RULE-22-11/ThreadPreviouslyJoinedOrDetached.testref b/c/misra/test/rules/RULE-22-11/ThreadPreviouslyJoinedOrDetached.testref new file mode 100644 index 0000000000..61fa88fd08 --- /dev/null +++ b/c/misra/test/rules/RULE-22-11/ThreadPreviouslyJoinedOrDetached.testref @@ -0,0 +1 @@ +c/common/test/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-11/ThreadWasPreviouslyJoinedOrDetached.testref b/c/misra/test/rules/RULE-22-11/ThreadWasPreviouslyJoinedOrDetached.testref new file mode 100644 index 0000000000..61fa88fd08 --- /dev/null +++ b/c/misra/test/rules/RULE-22-11/ThreadWasPreviouslyJoinedOrDetached.testref @@ -0,0 +1 @@ +c/common/test/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-12/NonstandardUseOfThreadingObject.expected b/c/misra/test/rules/RULE-22-12/NonstandardUseOfThreadingObject.expected new file mode 100644 index 0000000000..62a740f960 --- /dev/null +++ b/c/misra/test/rules/RULE-22-12/NonstandardUseOfThreadingObject.expected @@ -0,0 +1,27 @@ +| test.c:37:3:37:7 | mutex | Invalid usage of standard thread object type 'mtx_t'. | +| test.c:37:11:37:21 | * ... | Invalid usage of standard thread object type 'mtx_t'. | +| test.c:38:3:38:8 | thread | Invalid usage of standard thread object type 'thrd_t'. | +| test.c:38:12:38:23 | * ... | Invalid usage of standard thread object type 'thrd_t'. | +| test.c:39:3:39:13 | threadlocal | Invalid usage of standard thread object type 'tss_t'. | +| test.c:39:17:39:27 | * ... | Invalid usage of standard thread object type 'tss_t'. | +| test.c:40:3:40:11 | condition | Invalid usage of standard thread object type 'cnd_t'. | +| test.c:40:15:40:25 | * ... | Invalid usage of standard thread object type 'cnd_t'. | +| test.c:43:10:43:15 | & ... | Invalid usage of standard thread object type 'mtx_t *'. | +| test.c:44:10:44:16 | & ... | Invalid usage of standard thread object type 'thrd_t *'. | +| test.c:45:10:45:21 | & ... | Invalid usage of standard thread object type 'tss_t *'. | +| test.c:46:10:46:19 | & ... | Invalid usage of standard thread object type 'cnd_t *'. | +| test.c:48:3:48:13 | threadlocal | Invalid usage of standard thread object type 'tss_t'. | +| test.c:49:3:49:13 | threadlocal | Invalid usage of standard thread object type 'tss_t'. | +| test.c:50:3:50:13 | threadlocal | Invalid usage of standard thread object type 'tss_t'. | +| test.c:54:3:54:8 | thread | Invalid usage of standard thread object type 'thrd_t'. | +| test.c:54:13:54:18 | thread | Invalid usage of standard thread object type 'thrd_t'. | +| test.c:55:3:55:8 | thread | Invalid usage of standard thread object type 'thrd_t'. | +| test.c:55:13:55:18 | thread | Invalid usage of standard thread object type 'thrd_t'. | +| test.c:56:3:56:13 | threadlocal | Invalid usage of standard thread object type 'tss_t'. | +| test.c:56:18:56:28 | threadlocal | Invalid usage of standard thread object type 'tss_t'. | +| test.c:57:3:57:13 | threadlocal | Invalid usage of standard thread object type 'tss_t'. | +| test.c:57:18:57:28 | threadlocal | Invalid usage of standard thread object type 'tss_t'. | +| test.c:61:14:61:18 | mutex | Invalid usage of standard thread object type 'mtx_t'. | +| test.c:62:15:62:20 | thread | Invalid usage of standard thread object type 'thrd_t'. | +| test.c:63:20:63:30 | threadlocal | Invalid usage of standard thread object type 'tss_t'. | +| test.c:64:18:64:26 | condition | Invalid usage of standard thread object type 'cnd_t'. | diff --git a/c/misra/test/rules/RULE-22-12/NonstandardUseOfThreadingObject.qlref b/c/misra/test/rules/RULE-22-12/NonstandardUseOfThreadingObject.qlref new file mode 100644 index 0000000000..d1d345420d --- /dev/null +++ b/c/misra/test/rules/RULE-22-12/NonstandardUseOfThreadingObject.qlref @@ -0,0 +1 @@ +rules/RULE-22-12/NonstandardUseOfThreadingObject.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-12/test.c b/c/misra/test/rules/RULE-22-12/test.c new file mode 100644 index 0000000000..1c59c43d8c --- /dev/null +++ b/c/misra/test/rules/RULE-22-12/test.c @@ -0,0 +1,65 @@ +#include "string.h" +#include "threads.h" + +mtx_t mutex; +thrd_t thread; +tss_t threadlocal; +cnd_t condition; + +extern void use_mutex(mtx_t *m); +extern void use_thread(thrd_t *t); +extern void use_threadlocal(tss_t *t); +extern void use_condition(cnd_t *c); + +void valid_usages(void) { + mtx_init(&mutex, mtx_plain); // COMPLIANT + mtx_lock(&mutex); // COMPLIANT + mtx_unlock(&mutex); // COMPLIANT + thrd_create(&thread, NULL, NULL); // COMPLIANT + tss_create(&threadlocal, NULL); // COMPLIANT + tss_set(threadlocal, NULL); // COMPLIANT + cnd_init(&condition); // COMPLIANT + cnd_signal(&condition); // COMPLIANT + cnd_wait(&condition, &mutex); // COMPLIANT + + use_mutex(&mutex); // COMPLIANT + use_thread(&thread); // COMPLIANT + use_threadlocal(&threadlocal); // COMPLIANT + use_condition(&condition); // COMPLIANT +} + +extern void copy_mutex(mtx_t m); +extern void copy_thread(thrd_t t); +extern void copy_threadlocal(tss_t t); +extern void copy_condition(cnd_t t); + +void invalid_usages(void) { + mutex = *(mtx_t *)0; // NON-COMPLIANT + thread = *(thrd_t *)0; // NON-COMPLIANT + threadlocal = *(tss_t *)0; // NON-COMPLIANT + condition = *(cnd_t *)0; // NON-COMPLIANT + + int *buf; + memcpy(&mutex, buf, sizeof(mtx_t)); // NON-COMPLIANT + memcpy(&thread, buf, sizeof(thrd_t)); // NON-COMPLIANT + memcpy(&threadlocal, buf, sizeof(tss_t)); // NON-COMPLIANT + memcpy(&condition, buf, sizeof(cnd_t)); // NON-COMPLIANT + + threadlocal++; // NON-COMPLIANT + threadlocal += 1; // NON-COMPLIANT + threadlocal + 1; // NON-COMPLIANT + + // mutex == mutex; // NON-COMPLIANT + // mutex != mutex; // NON-COMPLIANT + thread == thread; // NON-COMPLIANT + thread != thread; // NON-COMPLIANT + threadlocal == threadlocal; // NON-COMPLIANT + threadlocal != threadlocal; // NON-COMPLIANT + // condition == condition; // NON-COMPLIANT + // condition != condition; // NON-COMPLIANT + + copy_mutex(mutex); // COMPLIANT + copy_thread(thread); // COMPLIANT + copy_threadlocal(threadlocal); // COMPLIANT + copy_condition(condition); // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.expected b/c/misra/test/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.expected new file mode 100644 index 0000000000..0fe033366d --- /dev/null +++ b/c/misra/test/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.expected @@ -0,0 +1,13 @@ +| test.c:14:21:14:22 | g9 | Object of type 'mtx_t' has invalid storage duration type 'thread'. | +| test.c:15:22:15:24 | g10 | Object of type 'thrd_t' has invalid storage duration type 'thread'. | +| test.c:16:21:16:23 | g11 | Object of type 'tss_t' has invalid storage duration type 'thread'. | +| test.c:17:21:17:23 | g12 | Object of type 'cnd_t' has invalid storage duration type 'thread'. | +| test.c:34:9:34:10 | l1 | Object of type 'mtx_t' has invalid storage duration type 'automatic'. | +| test.c:35:10:35:11 | l2 | Object of type 'thrd_t' has invalid storage duration type 'automatic'. | +| test.c:36:9:36:10 | l3 | Object of type 'tss_t' has invalid storage duration type 'automatic'. | +| test.c:37:9:37:10 | l4 | Object of type 'cnd_t' has invalid storage duration type 'automatic'. | +| test.c:44:9:44:10 | l9 | Object of type 'mtx_t[10]' has invalid storage duration type 'automatic'. | +| test.c:46:13:46:15 | l11 | Object of type 'has_mtx_t' has invalid storage duration type 'automatic'. | +| test.c:48:13:48:15 | l13 | Object of type 'has_mtx_t[10]' has invalid storage duration type 'automatic'. | +| test.c:51:9:51:14 | call to malloc | Object of type 'mtx_t' has invalid storage duration type 'allocated'. | +| test.c:52:9:52:14 | call to malloc | Object of type 'mtx_t' has invalid storage duration type 'allocated'. | diff --git a/c/misra/test/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.qlref b/c/misra/test/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.qlref new file mode 100644 index 0000000000..9c054fc623 --- /dev/null +++ b/c/misra/test/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.qlref @@ -0,0 +1 @@ +rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-13/test.c b/c/misra/test/rules/RULE-22-13/test.c new file mode 100644 index 0000000000..193f4be471 --- /dev/null +++ b/c/misra/test/rules/RULE-22-13/test.c @@ -0,0 +1,53 @@ +#include "stdlib.h" +#include "threads.h" + +mtx_t g1; // COMPLIANT +thrd_t g2; // COMPLIANT +tss_t g3; // COMPLIANT +cnd_t g4; // COMPLIANT + +static mtx_t g5; // COMPLIANT +static thrd_t g6; // COMPLIANT +static tss_t g7; // COMPLIANT +static cnd_t g8; // COMPLIANT + +_Thread_local mtx_t g9; // NON-COMPLIANT +_Thread_local thrd_t g10; // NON-COMPLIANT +_Thread_local tss_t g11; // NON-COMPLIANT +_Thread_local cnd_t g12; // NON-COMPLIANT + +typedef struct { + mtx_t m; +} has_mtx_t; + +typedef struct { + mtx_t *m; +} has_ptr_mtx_t; + +mtx_t g13[10]; // COMPLIANT +mtx_t *g14; // COMPLIANT +has_mtx_t g15; // COMPLIANT +has_ptr_mtx_t g16; // COMPLIANT +has_mtx_t g17[10]; // COMPLIANT + +void f1(void) { + mtx_t l1; // NON-COMPLIANT + thrd_t l2; // NON-COMPLIANT + tss_t l3; // NON-COMPLIANT + cnd_t l4; // NON-COMPLIANT + + static mtx_t l5; // COMPLIANT + static thrd_t l6; // COMPLIANT + static tss_t l7; // COMPLIANT + static cnd_t l8; // COMPLIANT + + mtx_t l9[10]; // NON-COMPLIANT + mtx_t *l10; // COMPLIANT + has_mtx_t l11; // NON-COMPLIANT + has_ptr_mtx_t l12; // COMPLIANT + has_mtx_t l13[10]; // NON-COMPLIANT + + l10 = &g1; // COMPLIANT + l10 = malloc(sizeof(mtx_t)); // NON-COMPLIANT + l10 = malloc(sizeof(mtx_t) * 4); // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-14/MutexInitWithInvalidMutexType.expected b/c/misra/test/rules/RULE-22-14/MutexInitWithInvalidMutexType.expected new file mode 100644 index 0000000000..1ea39b6b1d --- /dev/null +++ b/c/misra/test/rules/RULE-22-14/MutexInitWithInvalidMutexType.expected @@ -0,0 +1,5 @@ +| test.c:140:3:140:10 | call to mtx_init | Mutex initialized with incorrect type expression. | +| test.c:141:3:141:10 | call to mtx_init | Mutex initialized with incorrect type expression. | +| test.c:142:3:142:10 | call to mtx_init | Mutex initialized with incorrect type expression. | +| test.c:144:3:144:10 | call to mtx_init | Mutex initialized with incorrect type expression. | +| test.c:145:3:145:10 | call to mtx_init | Mutex initialized with incorrect type expression. | diff --git a/c/misra/test/rules/RULE-22-14/MutexInitWithInvalidMutexType.qlref b/c/misra/test/rules/RULE-22-14/MutexInitWithInvalidMutexType.qlref new file mode 100644 index 0000000000..32b57cfd07 --- /dev/null +++ b/c/misra/test/rules/RULE-22-14/MutexInitWithInvalidMutexType.qlref @@ -0,0 +1 @@ +rules/RULE-22-14/MutexInitWithInvalidMutexType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-14/MutexInitializedInsideThread.expected b/c/misra/test/rules/RULE-22-14/MutexInitializedInsideThread.expected new file mode 100644 index 0000000000..360c02f622 --- /dev/null +++ b/c/misra/test/rules/RULE-22-14/MutexInitializedInsideThread.expected @@ -0,0 +1 @@ +| test.c:110:3:110:10 | call to mtx_init | Mutex initialization reachable from threaded function '$@'. | test.c:105:6:105:32 | from_root7_use_thread_local | from_root7_use_thread_local | diff --git a/c/misra/test/rules/RULE-22-14/MutexInitializedInsideThread.qlref b/c/misra/test/rules/RULE-22-14/MutexInitializedInsideThread.qlref new file mode 100644 index 0000000000..83ada06139 --- /dev/null +++ b/c/misra/test/rules/RULE-22-14/MutexInitializedInsideThread.qlref @@ -0,0 +1 @@ +rules/RULE-22-14/MutexInitializedInsideThread.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-14/MutexNotInitializedBeforeUse.expected b/c/misra/test/rules/RULE-22-14/MutexNotInitializedBeforeUse.expected new file mode 100644 index 0000000000..b9560165ce --- /dev/null +++ b/c/misra/test/rules/RULE-22-14/MutexNotInitializedBeforeUse.expected @@ -0,0 +1,14 @@ +| test.c:6:12:6:14 | & ... | Mutex '$@' possibly used before initialization, from entry point function '$@'. | test.c:5:9:5:10 | l1 | l1 | test.c:4:6:4:19 | use_local_mtxs | use_local_mtxs | +| test.c:13:12:13:16 | & ... | Mutex in object '$@' possibly used before initialization, from entry point function '$@'. | test.c:12:5:12:6 | l2 | l2 | test.c:4:6:4:19 | use_local_mtxs | use_local_mtxs | +| test.c:18:12:18:17 | & ... | Mutex in object '$@' possibly used before initialization, from entry point function '$@'. | test.c:17:9:17:10 | l3 | l3 | test.c:4:6:4:19 | use_local_mtxs | use_local_mtxs | +| test.c:23:12:23:13 | l4 | Mutex '$@' possibly used before initialization, from entry point function '$@'. | test.c:22:15:22:20 | call to malloc | call to malloc | test.c:28:6:28:31 | root1_calls_use_local_mtxs | root1_calls_use_local_mtxs | +| test.c:41:12:41:14 | & ... | Mutex '$@' possibly used before initialization, from entry point function '$@'. | test.c:34:7:34:8 | g1 | g1 | test.c:40:6:40:30 | root2_uses_global_mutexes | root2_uses_global_mutexes | +| test.c:42:12:42:17 | & ... | Mutex in object '$@' possibly used before initialization, from entry point function '$@'. | test.c:37:3:37:4 | g2 | g2 | test.c:40:6:40:30 | root2_uses_global_mutexes | root2_uses_global_mutexes | +| test.c:43:12:43:13 | g3 | Mutex '$@' possibly used before initialization, from entry point function '$@'. | test.c:56:8:56:13 | call to malloc | call to malloc | test.c:40:6:40:30 | root2_uses_global_mutexes | root2_uses_global_mutexes | +| test.c:64:12:64:14 | & ... | Mutex '$@' possibly used before initialization, from entry point function '$@'. | test.c:34:7:34:8 | g1 | g1 | test.c:67:6:67:45 | root4_call_thread_without_initialization | root4_call_thread_without_initialization | +| test.c:88:12:88:14 | & ... | Mutex '$@' possibly used before initialization, from entry point function '$@'. | test.c:87:9:87:10 | l1 | l1 | test.c:86:6:86:36 | island1_use_uninitialized_mutex | island1_use_uninitialized_mutex | +| test.c:100:12:100:14 | & ... | Mutex '$@' possibly used before initialization, from entry point function '$@'. | test.c:98:21:98:22 | g5 | g5 | test.c:99:6:99:27 | root6_use_thread_local | root6_use_thread_local | +| test.c:107:12:107:14 | & ... | Mutex '$@' possibly used before initialization, from entry point function '$@'. | test.c:98:21:98:22 | g5 | g5 | test.c:105:6:105:32 | from_root7_use_thread_local | from_root7_use_thread_local | +| test.c:124:12:124:13 | & ... | Condition '$@' possibly used before initialization, from entry point function '$@'. | test.c:122:9:122:9 | c | c | test.c:121:6:121:28 | root8_uninitialized_cnd | root8_uninitialized_cnd | +| test.c:124:16:124:17 | & ... | Mutex '$@' possibly used before initialization, from entry point function '$@'. | test.c:123:9:123:9 | m | m | test.c:121:6:121:28 | root8_uninitialized_cnd | root8_uninitialized_cnd | +| test.c:127:12:127:13 | & ... | Condition '$@' possibly used before initialization, from entry point function '$@'. | test.c:122:9:122:9 | c | c | test.c:121:6:121:28 | root8_uninitialized_cnd | root8_uninitialized_cnd | diff --git a/c/misra/test/rules/RULE-22-14/MutexNotInitializedBeforeUse.qlref b/c/misra/test/rules/RULE-22-14/MutexNotInitializedBeforeUse.qlref new file mode 100644 index 0000000000..2827a9c571 --- /dev/null +++ b/c/misra/test/rules/RULE-22-14/MutexNotInitializedBeforeUse.qlref @@ -0,0 +1 @@ +rules/RULE-22-14/MutexNotInitializedBeforeUse.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-14/test.c b/c/misra/test/rules/RULE-22-14/test.c new file mode 100644 index 0000000000..c664a08dc3 --- /dev/null +++ b/c/misra/test/rules/RULE-22-14/test.c @@ -0,0 +1,158 @@ +#include "stdlib.h" +#include "threads.h" + +void use_local_mtxs(int x, int y) { + mtx_t l1; + mtx_lock(&l1); // NON-COMPLIANT + mtx_init(&l1, mtx_plain); + mtx_lock(&l1); // COMPLIANT + + struct { + mtx_t m; + } l2; + mtx_lock(&l2.m); // NON-COMPLIANT + mtx_init(&l2.m, mtx_plain); + mtx_lock(&l2.m); // COMPLIANT + + mtx_t l3[10]; + mtx_lock(&l3[y]); // NON-COMPLIANT + mtx_init(&l3[x], mtx_plain); + mtx_lock(&l3[y]); // COMPLIANT + + mtx_t *l4 = malloc(sizeof(mtx_t)); + mtx_lock(l4); // NON-COMPLIANT + mtx_init(l4, mtx_plain); + mtx_lock(l4); // COMPLIANT +} + +void root1_calls_use_local_mtxs() { + // Since a function exists which calls use_local_mtxs(), that function is not + // a root function. The query should still report unused locals in this case. + use_local_mtxs(1, 2); +} + +mtx_t g1; +struct { + mtx_t m1; +} g2; +mtx_t *g3; + +void root2_uses_global_mutexes() { + mtx_lock(&g1); // NON-COMPLIANT + mtx_lock(&g2.m1); // NON-COMPLIANT + mtx_lock(g3); // NON-COMPLIANT +} + +void from_root3_use_global_mutexes() { + mtx_lock(&g1); // COMPLIANT + mtx_lock(&g2.m1); // COMPLIANT + mtx_lock(g3); // COMPLIANT +} + +void root3_initializes_and_uses_global_mutexes() { + // Init global mutex with an allocated storage duration object. The existence + // of this malloc() is not checked by the query, but if its exists, the object + // and its uses should be trackable as a nice bonus. + g3 = malloc(sizeof(mtx_t)); + mtx_init(&g1, mtx_plain); + mtx_init(&g2.m1, mtx_plain); + mtx_init(g3, mtx_plain); + from_root3_use_global_mutexes(); +} + +void from_root4_use_global_mutex(void *arg) { + mtx_lock(&g1); // NON-COMPLIANT +} + +void root4_call_thread_without_initialization() { + thrd_t t; + thrd_create(&t, &from_root4_use_global_mutex, NULL); +} + +void from_root5_use_global_mutex(void *arg) { + mtx_lock(&g1); // COMPLIANT +} + +void root5_thread_with_initialization() { + mtx_init(&g1, mtx_plain); + thrd_t t; + thrd_create(&t, &from_root5_use_global_mutex, NULL); +} + +// Set up two functions such that a calls b and b calls a. This means there is +// no root function, but we should still report unused locals. +void island2_call_island1(); + +void island1_use_uninitialized_mutex() { + mtx_t l1; + mtx_lock(&l1); // NON-COMPLIANT + + // Globals are hard to detect + mtx_lock(&g1); // NON-COMPLIANT[False negative] + + island2_call_island1(); +} + +void island2_call_island1() { island1_use_uninitialized_mutex(); } + +_Thread_local mtx_t g5; +void root6_use_thread_local() { + mtx_lock(&g5); // NON-COMPLIANT + mtx_init(&g5, mtx_plain); + mtx_lock(&g5); // COMPLIANT +} + +void from_root7_use_thread_local() { + // Invalid, thread local g5 hasn't been initialized in this thread. + mtx_lock(&g5); // NON-COMPLIANT + + // Violates recommendation, mutexes initialized within a thread. + mtx_init(&g5, mtx_plain); // NON-COMPLIANT + + // Valid if we except the above initialization. + mtx_lock(&g5); // COMPLIANT +} + +void root7_spawn_thread_uninitialized_thread_local() { + thrd_t t; + thrd_create(&t, &from_root7_use_thread_local, NULL); +} + +void root8_uninitialized_cnd() { + cnd_t c; + mtx_t m; + cnd_wait(&c, &m); // NON-COMPLIANT + + mtx_init(&m, mtx_plain); + cnd_wait(&c, &m); // NON-COMPLIANT + + cnd_init(&c); + cnd_wait(&c, &m); // COMPLIANT +} + +void invalid_mtx_init_types() { + mtx_t m; + mtx_init(&m, mtx_plain); // COMPLIANT + mtx_init(&m, mtx_plain | mtx_recursive); // COMPLIANT + mtx_init(&m, mtx_timed); // COMPLIANT + mtx_init(&m, mtx_timed | mtx_recursive); // COMPLIANT + + mtx_init(&m, mtx_recursive); // NON-COMPLIANT + mtx_init(&m, mtx_plain | mtx_timed); // NON-COMPLIANT + mtx_init(&m, mtx_plain | mtx_plain); // NON-COMPLIANT + mtx_init(&m, mtx_plain & mtx_recursive); // NON-COMPLIANT + mtx_init(&m, mtx_plain * mtx_recursive); // NON-COMPLIANT + mtx_init(&m, -1); // NON-COMPLIANT +} + +void function_pointer_uses_global_mutexes() { + // If the function has been used as a function pointer, we don't attempt to + // analyze this. + mtx_lock(&g1); // COMPLIANT + mtx_lock(&g2.m1); // COMPLIANT + mtx_lock(g3); // COMPLIANT +} + +void take_function_pointer() { + void (*f)(void) = function_pointer_uses_global_mutexes; +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.expected b/c/misra/test/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.expected new file mode 100644 index 0000000000..49f1b74c15 --- /dev/null +++ b/c/misra/test/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.expected @@ -0,0 +1,12 @@ +| test.c:16:3:16:13 | call to mtx_destroy | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:3:7:3:8 | g1 | g1 | test.c:64:3:64:13 | call to thrd_create | t2_use_all | +| test.c:16:3:16:13 | call to mtx_destroy | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:3:7:3:8 | g1 | g1 | test.c:72:3:72:13 | call to thrd_create | t2_use_all | +| test.c:16:3:16:13 | call to mtx_destroy | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:3:7:3:8 | g1 | g1 | test.c:91:3:91:10 | call to mtx_lock | main thread | +| test.c:17:3:17:12 | call to tss_delete | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:4:7:4:8 | g2 | g2 | test.c:64:3:64:13 | call to thrd_create | t2_use_all | +| test.c:17:3:17:12 | call to tss_delete | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:4:7:4:8 | g2 | g2 | test.c:72:3:72:13 | call to thrd_create | t2_use_all | +| test.c:17:3:17:12 | call to tss_delete | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:4:7:4:8 | g2 | g2 | test.c:92:3:92:9 | call to tss_get | main thread | +| test.c:18:3:18:13 | call to cnd_destroy | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:5:7:5:8 | g3 | g3 | test.c:64:3:64:13 | call to thrd_create | t2_use_all | +| test.c:18:3:18:13 | call to cnd_destroy | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:5:7:5:8 | g3 | g3 | test.c:72:3:72:13 | call to thrd_create | t2_use_all | +| test.c:18:3:18:13 | call to cnd_destroy | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:5:7:5:8 | g3 | g3 | test.c:93:3:93:10 | call to cnd_wait | main thread | +| test.c:42:3:42:13 | call to mtx_destroy | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:3:7:3:8 | g1 | g1 | test.c:41:3:41:13 | call to thrd_create | t2_use_all | +| test.c:43:3:43:12 | call to tss_delete | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:4:7:4:8 | g2 | g2 | test.c:41:3:41:13 | call to thrd_create | t2_use_all | +| test.c:44:3:44:13 | call to cnd_destroy | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:5:7:5:8 | g3 | g3 | test.c:41:3:41:13 | call to thrd_create | t2_use_all | diff --git a/c/misra/test/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.qlref b/c/misra/test/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.qlref new file mode 100644 index 0000000000..809eae6faf --- /dev/null +++ b/c/misra/test/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.qlref @@ -0,0 +1 @@ +rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-15/test.c b/c/misra/test/rules/RULE-22-15/test.c new file mode 100644 index 0000000000..7679730fc9 --- /dev/null +++ b/c/misra/test/rules/RULE-22-15/test.c @@ -0,0 +1,113 @@ +#include "threads.h" + +mtx_t g1; +tss_t g2; +cnd_t g3; + +int t1_use_none(void *p) { return 0; } + +int t2_use_all(void *p) { + mtx_lock(&g1); + tss_get(&g2); + cnd_wait(&g3, &g1); +} + +int t3_dispose_all(void *p) { + mtx_destroy(&g1); + tss_delete(&g2); + cnd_destroy(&g3); +} + +int t4_use_then_dispose(void *p) { + mtx_lock(&g1); + tss_get(&g2); + cnd_wait(&g3, &g1); + + mtx_destroy(&g1); + tss_delete(&g2); + cnd_destroy(&g3); +} + +void f1() { + thrd_t t; + thrd_create(&t, t1_use_none, NULL); + mtx_destroy(&g1); + tss_delete(&g2); + cnd_destroy(&g3); +} + +void f2() { + thrd_t t; + thrd_create(&t, t2_use_all, NULL); + mtx_destroy(&g1); // NON-COMPLIANT + tss_delete(&g2); // NON-COMPLIANT + cnd_destroy(&g3); // NON-COMPLIANT +} + +void f3() { + thrd_t t; + thrd_create(&t, t2_use_all, NULL); // COMPLIANT +} + +void f4() { + thrd_t t; + thrd_create(&t, t2_use_all, NULL); // COMPLIANT + thrd_join(&t, NULL); + mtx_destroy(&g1); // COMPLIANT + tss_delete(&g2); // COMPLIANT + cnd_destroy(&g3); // COMPLIANT +} + +void f5() { + thrd_t t1; + thrd_t t2; + thrd_create(&t1, t2_use_all, NULL); // COMPLIANT + thrd_create(&t2, t3_dispose_all, NULL); // NON-COMPLIANT +} + +void f6() { + thrd_t t1; + thrd_t t2; + thrd_create(&t1, t3_dispose_all, NULL); // NON-COMPLIANT + thrd_create(&t2, t2_use_all, NULL); // COMPLIANT +} + +void f7() { + thrd_t t1; + thrd_t t2; + thrd_create(&t1, t2_use_all, NULL); // COMPLIANT + thrd_join(&t1, NULL); + thrd_create(&t2, t3_dispose_all, NULL); // COMPLIANT +} + +void f8() { + thrd_t t; + thrd_create(&t, t4_use_then_dispose, NULL); // COMPLIANT +} + +void f9() { + thrd_t t; + thrd_create(&t, t3_dispose_all, NULL); // NON-COMPLIANT + mtx_lock(&g1); + tss_get(&g2); + cnd_wait(&g3, &g1); +} + +void f10() { + thrd_t t; + mtx_lock(&g1); + tss_get(&g2); + cnd_wait(&g3, &g1); + thrd_create(&t, t3_dispose_all, NULL); // COMPLIANT +} + +void f11() { + thrd_t t; + thrd_create(&t, t1_use_none, NULL); + mtx_lock(&g1); + tss_get(&g2); + cnd_wait(&g3, &g1); + mtx_destroy(&g1); // COMPLIANT + tss_delete(&g2); // COMPLIANT + cnd_destroy(&g3); // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.expected b/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.expected new file mode 100644 index 0000000000..46a295d75f --- /dev/null +++ b/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.expected @@ -0,0 +1,10 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (MutexObjectsNotAlwaysUnlocked.ql:22,52-60) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (MutexObjectsNotAlwaysUnlocked.ql:30,42-50) +| test.c:16:3:16:10 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. | +| test.c:21:3:21:10 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. | +| test.c:39:3:39:10 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. | +| test.c:55:3:55:10 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. | +| test.c:72:3:72:10 | call to mtx_lock | Mutex 'g1' is locked here and may not always be subsequently unlocked. | +| test.c:79:3:79:10 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. | +| test.c:101:5:101:12 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. | +| test.c:113:3:113:10 | call to mtx_lock | Mutex 'ptr_m1' is locked here and may not always be subsequently unlocked. | diff --git a/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.qlref b/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.qlref new file mode 100644 index 0000000000..a1877f944d --- /dev/null +++ b/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.qlref @@ -0,0 +1 @@ +rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-16/test.c b/c/misra/test/rules/RULE-22-16/test.c new file mode 100644 index 0000000000..723516509f --- /dev/null +++ b/c/misra/test/rules/RULE-22-16/test.c @@ -0,0 +1,115 @@ +#include "threads.h" + +void f1() { + mtx_t m; + mtx_lock(&m); // COMPLIANT + mtx_unlock(&m); +} + +void f2() { + mtx_t m; + mtx_unlock(&m); // COMPLIANT +} + +void f3() { + mtx_t m; + mtx_lock(&m); // NON-COMPLIANT +} + +void f4(int p) { + mtx_t m; + mtx_lock(&m); // NON-COMPLIANT + if (p) { + mtx_unlock(&m); + } +} + +void f5(int p) { + mtx_t m; + mtx_lock(&m); // COMPLIANT + if (p) { + mtx_unlock(&m); + } else { + mtx_unlock(&m); + } +} + +void f6(int p) { + mtx_t m; + mtx_lock(&m); // NON-COMPLIANT + if (p) { + goto skipped; + } + mtx_unlock(&m); +skipped:; +} + +void f7(int p) { + mtx_t *m; + mtx_lock(m); // COMPLIANT + mtx_unlock(m); +} + +void f8(int p) { + mtx_t *m; + mtx_lock(m); // NON-COMPLIANT +} + +void f9(int p) { + mtx_t m; + mtx_lock(&m); // COMPLIANT + mtx_t *ptr_m = &m; + mtx_unlock(ptr_m); +} + +mtx_t g1; +void f10() { + mtx_lock(&g1); // COMPLIANT + mtx_unlock(&g1); +} + +void f11() { + mtx_lock(&g1); // NON-COMPLIANT +} + +void f12() { + struct { + mtx_t m; + } s; + mtx_lock(&s.m); // NON-COMPLIANT +} + +void f13() { + struct { + mtx_t m; + } s; + mtx_lock(&s.m); // COMPLIANT + mtx_unlock(&s.m); +} + +void f14() { + for (;;) { + mtx_t m; + mtx_lock(&m); // COMPLIANT + mtx_unlock(&m); + } +} + +void f15(int p) { + for (;;) { + mtx_t m; + mtx_lock(&m); // NON-COMPLIANT + if (p) { + break; + } + mtx_unlock(&m); + } +} + +void f16(int p) { + mtx_t *ptr; + mtx_t *ptr_m1 = ptr; + mtx_t *ptr_m2 = ptr; + mtx_lock(ptr_m1); // COMPLIANT[FALSE_POSITIVE] + mtx_unlock(ptr_m2); +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.expected b/c/misra/test/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.expected new file mode 100644 index 0000000000..254d55adc2 --- /dev/null +++ b/c/misra/test/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.expected @@ -0,0 +1,16 @@ +| test.c:19:3:19:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread. | test.c:11:9:11:10 | l1 | l1 | +| test.c:20:3:20:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread. | test.c:11:9:11:10 | l1 | l1 | +| test.c:25:3:25:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread. | test.c:14:5:14:6 | l2 | l2.m1 | +| test.c:26:3:26:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread. | test.c:14:5:14:6 | l2 | l2.m1 | +| test.c:31:3:31:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread. | test.c:3:7:3:8 | g1 | g1 | +| test.c:32:3:32:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread. | test.c:3:7:3:8 | g1 | g1 | +| test.c:37:3:37:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread. | test.c:6:3:6:4 | g2 | g2.m1 | +| test.c:38:3:38:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread. | test.c:6:3:6:4 | g2 | g2.m1 | +| test.c:47:3:47:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread. | test.c:11:9:11:10 | l1 | l1 | +| test.c:48:3:48:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread. | test.c:14:5:14:6 | l2 | l2.m1 | +| test.c:49:3:49:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread. | test.c:3:7:3:8 | g1 | g1 | +| test.c:50:3:50:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread. | test.c:6:3:6:4 | g2 | g2.m1 | +| test.c:51:3:51:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread. | test.c:11:9:11:10 | l1 | l1 | +| test.c:52:3:52:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread. | test.c:14:5:14:6 | l2 | l2.m1 | +| test.c:53:3:53:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread. | test.c:3:7:3:8 | g1 | g1 | +| test.c:54:3:54:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread. | test.c:6:3:6:4 | g2 | g2.m1 | diff --git a/c/misra/test/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.qlref b/c/misra/test/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.qlref new file mode 100644 index 0000000000..4ac06f10ed --- /dev/null +++ b/c/misra/test/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.qlref @@ -0,0 +1 @@ +rules/RULE-22-17/InvalidOperationOnUnlockedMutex.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-17/test.c b/c/misra/test/rules/RULE-22-17/test.c new file mode 100644 index 0000000000..fc841bb3e1 --- /dev/null +++ b/c/misra/test/rules/RULE-22-17/test.c @@ -0,0 +1,70 @@ +#include "threads.h" + +mtx_t g1; +struct { + mtx_t m1; +} g2; + +cnd_t cnd; + +void f1(int p) { + mtx_t l1; + struct { + mtx_t m1; + } l2; + + mtx_lock(&l1); + cnd_wait(&cnd, &l1); // COMPLIANT + mtx_unlock(&l1); // COMPLIANT + cnd_wait(&cnd, &l1); // NON-COMPLIANT + mtx_unlock(&l1); // NON-COMPLIANT + + mtx_lock(&l2.m1); + cnd_wait(&cnd, &l2.m1); // COMPLIANT + mtx_unlock(&l2.m1); // COMPLIANT + cnd_wait(&cnd, &l2.m1); // NON-COMPLIANT + mtx_unlock(&l2.m1); // NON-COMPLIANT + + mtx_lock(&g1); + cnd_wait(&cnd, &g1); // COMPLIANT + mtx_unlock(&g1); // COMPLIANT + cnd_wait(&cnd, &g1); // NON-COMPLIANT + mtx_unlock(&g1); // NON-COMPLIANT + + mtx_lock(&g2.m1); + cnd_wait(&cnd, &g2.m1); // COMPLIANT + mtx_unlock(&g2.m1); // COMPLIANT + cnd_wait(&cnd, &g2.m1); // NON-COMPLIANT + mtx_unlock(&g2.m1); // NON-COMPLIANT + + // We should report when a mutex is unlocked in the wrong block: + if (p) { + mtx_lock(&l1); + mtx_lock(&l2.m1); + mtx_lock(&g1); + mtx_lock(&g2.m1); + } + cnd_wait(&cnd, &l1); // NON-COMPLIANT + cnd_wait(&cnd, &l2.m1); // NON-COMPLIANT + cnd_wait(&cnd, &g1); // NON-COMPLIANT + cnd_wait(&cnd, &g2.m1); // NON-COMPLIANT + mtx_unlock(&l1); // NON-COMPLIANT + mtx_unlock(&l2.m1); // NON-COMPLIANT + mtx_unlock(&g1); // NON-COMPLIANT + mtx_unlock(&g2.m1); // NON-COMPLIANT + + // The above requires dominance analysis. Check dominator sets don't cause + // false positives: + if (p) { + mtx_lock(&l1); + } else { + mtx_lock(&l1); + } + mtx_unlock(&l1); // COMPLIANT + + // Invalid but satisfies the rule: + mtx_lock(&l1); + if (p) { + mtx_unlock(&l1); // COMPLIANT + } +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.expected b/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.expected new file mode 100644 index 0000000000..fd947dee51 --- /dev/null +++ b/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.expected @@ -0,0 +1,2 @@ +| test.c:19:3:19:10 | call to mtx_lock | Non-recursive mutex nonrec locked after it is $@. | test.c:18:3:18:10 | call to mtx_lock | already locked | +| test.c:22:3:22:10 | call to mtx_lock | Non-recursive mutex s.m locked after it is $@. | test.c:21:3:21:10 | call to mtx_lock | already locked | diff --git a/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.qlref b/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.qlref new file mode 100644 index 0000000000..131e0476bf --- /dev/null +++ b/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.qlref @@ -0,0 +1 @@ +rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.expected b/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.expected new file mode 100644 index 0000000000..e268f5367e --- /dev/null +++ b/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.expected @@ -0,0 +1,6 @@ +| test.c:44:3:44:10 | call to mtx_lock | Mutex locked after it was already $@. | test.c:43:3:43:10 | call to mtx_lock | previously locked | +| test.c:49:3:49:10 | call to mtx_lock | Mutex locked after it was already $@. | test.c:48:3:48:10 | call to mtx_lock | previously locked | +| test.c:54:3:54:10 | call to mtx_lock | Mutex locked after it was already $@. | test.c:53:3:53:10 | call to mtx_lock | previously locked | +| test.c:59:3:59:10 | call to mtx_lock | Mutex locked after it was already $@. | test.c:58:3:58:10 | call to mtx_lock | previously locked | +| test.c:76:3:76:10 | call to mtx_lock | Mutex locked after it was already $@. | test.c:75:3:75:10 | call to mtx_lock | previously locked | +| test.c:81:3:81:10 | call to mtx_lock | Mutex locked after it was already $@. | test.c:80:3:80:10 | call to mtx_lock | previously locked | diff --git a/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.qlref b/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.qlref new file mode 100644 index 0000000000..77a81deb69 --- /dev/null +++ b/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.qlref @@ -0,0 +1 @@ +rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-18/test.c b/c/misra/test/rules/RULE-22-18/test.c new file mode 100644 index 0000000000..f71066b1bc --- /dev/null +++ b/c/misra/test/rules/RULE-22-18/test.c @@ -0,0 +1,122 @@ +#include "threads.h" + +mtx_t rec; +mtx_t nonrec; +mtx_t both; +mtx_t unknown; + +struct { + mtx_t m; +} s; + +mtx_t arr[2]; + +int t1(void *arg) { + mtx_lock(&rec); // COMPLIANT + mtx_lock(&rec); // COMPLIANT + + mtx_lock(&nonrec); // COMPLIANT + mtx_lock(&nonrec); // NON-COMPLIANT + + mtx_lock(&s.m); // COMPLIANT + mtx_lock(&s.m); // NON-COMPLIANT +} + +void f1() { + mtx_init(&rec, mtx_plain | mtx_recursive); + mtx_init(&nonrec, mtx_plain); + mtx_init(&both, mtx_plain); + mtx_init(&both, mtx_plain | mtx_recursive); + // Do not initialize `unknown`. + mtx_init(&s.m, mtx_plain); + mtx_init(&arr[0], mtx_plain); + mtx_init(&arr[1], mtx_plain); + + thrd_t t; + thrd_create(t, t1, NULL); +} + +mtx_t *p; + +// Results for the audit query: +void t2(void *arg) { + mtx_lock(&arr[0]); + mtx_lock(&arr[(int)arg]); // NON-COMPLIANT +} + +void t3(void *arg) { + mtx_lock(arg); + mtx_lock(p); // NON-COMPLIANT +} + +void t4() { + mtx_lock(&both); + mtx_lock(&both); // NON-COMPLIANT +} + +void t5() { + mtx_lock(&unknown); + mtx_lock(&unknown); // NON-COMPLIANT +} + +void t6() { + // Cannot be locks of the same mutex: + mtx_lock(&nonrec); + mtx_lock(&unknown); // COMPLIANT +} + +void t7() { + mtx_lock(p); + // Definitely a recursive mutex: + mtx_lock(&rec); // COMPLIANT +} + +void t8() { + mtx_lock(p); + mtx_lock(&nonrec); // NON-COMPLIANT +} + +void t9() { + mtx_lock(&nonrec); + mtx_lock(p); // NON-COMPLIANT +} + +void f2() { + thrd_t t; + thrd_create(t, t2, NULL); +} + +void f3() { + thrd_t t; + thrd_create(t, t3, &rec); +} + +void f4() { + thrd_t t; + thrd_create(t, t4, NULL); +} + +void f5() { + thrd_t t; + thrd_create(t, t5, NULL); +} + +void f6() { + thrd_t t; + thrd_create(t, t6, NULL); +} + +void f7() { + thrd_t t; + thrd_create(t, t7, NULL); +} + +void f8() { + thrd_t t; + thrd_create(t, t8, NULL); +} + +void f9() { + thrd_t t; + thrd_create(t, t9, NULL); +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.expected b/c/misra/test/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.expected new file mode 100644 index 0000000000..c9785067c6 --- /dev/null +++ b/c/misra/test/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.expected @@ -0,0 +1,2 @@ +| test.c:19:3:19:10 | call to cnd_wait | Condition variable $@ associated with multiple mutexes, operation uses mutex $@ while $@ uses other mutex $@. | test.c:16:9:16:12 | cnd1 | cnd1 | test.c:17:9:17:12 | mtx1 | mtx1 | test.c:19:3:19:10 | call to cnd_wait | another operation | test.c:18:9:18:12 | mtx2 | mtx2 | +| test.c:41:3:41:10 | call to cnd_wait | Condition variable $@ associated with multiple mutexes, operation uses mutex $@ while $@ uses other mutex $@. | test.c:37:7:37:11 | gcnd1 | gcnd1 | test.c:38:7:38:11 | gmtx1 | gmtx1 | test.c:41:3:41:10 | call to cnd_wait | another operation | test.c:39:7:39:11 | gmtx2 | gmtx2 | diff --git a/c/misra/test/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.qlref b/c/misra/test/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.qlref new file mode 100644 index 0000000000..d43a824ec8 --- /dev/null +++ b/c/misra/test/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.qlref @@ -0,0 +1 @@ +rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-19/test.c b/c/misra/test/rules/RULE-22-19/test.c new file mode 100644 index 0000000000..f4b46d4077 --- /dev/null +++ b/c/misra/test/rules/RULE-22-19/test.c @@ -0,0 +1,46 @@ +#include "threads.h" + +void f1(void) { + cnd_t cnd1; + mtx_t mtx1; + cnd_wait(&cnd1, &mtx1); // COMPLIANT + cnd_wait(&cnd1, &mtx1); // COMPLIANT + + cnd_t cnd2; + mtx_t mtx2; + cnd_wait(&cnd2, &mtx2); // COMPLIANT + cnd_wait(&cnd2, &mtx2); // COMPLIANT +} + +void f2(void) { + cnd_t cnd1; + mtx_t mtx1; + mtx_t mtx2; + cnd_wait(&cnd1, &mtx1); // NON-COMPLIANT + cnd_wait(&cnd1, &mtx2); // NON-COMPLIANT +} + +void f3(void) { + cnd_t cnd1; + cnd_t cnd2; + mtx_t mtx1; + cnd_wait(&cnd1, &mtx1); // COMPLIANT + cnd_wait(&cnd2, &mtx1); // COMPLIANT +} + +void f4(cnd_t *cnd1, mtx_t *mtx1, mtx_t *mtx2) { + cnd_wait(cnd1, mtx1); // COMPLIANT + // Compliant, mtx1 and mtx2 may point to the same object + cnd_wait(cnd1, mtx2); // COMPLIANT +} + +cnd_t gcnd1; +mtx_t gmtx1; +mtx_t gmtx2; +void f5(void) { + cnd_wait(&gcnd1, &gmtx1); // NON-COMPLIANT +} + +void f6(void) { + cnd_wait(&gcnd1, &gmtx2); // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.expected b/c/misra/test/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.expected new file mode 100644 index 0000000000..301debd7e8 --- /dev/null +++ b/c/misra/test/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.expected @@ -0,0 +1,5 @@ +| test.c:6:11:6:13 | & ... | Thread specific storage pointer '$@' used before initialization from entry point function '$@'. | test.c:5:9:5:10 | l1 | l1 | test.c:4:6:4:19 | use_local_mtxs | use_local_mtxs | +| test.c:11:11:11:12 | l4 | Thread specific storage pointer '$@' used before initialization from entry point function '$@'. | test.c:10:15:10:20 | call to malloc | call to malloc | test.c:16:6:16:31 | root1_calls_use_local_mtxs | root1_calls_use_local_mtxs | +| test.c:25:11:25:13 | & ... | Thread specific storage pointer '$@' used before initialization from entry point function '$@'. | test.c:22:7:22:8 | g1 | g1 | test.c:24:6:24:28 | root2_uses_global_tss_t | root2_uses_global_tss_t | +| test.c:38:11:38:13 | & ... | Thread specific storage pointer '$@' used before initialization from entry point function '$@'. | test.c:22:7:22:8 | g1 | g1 | test.c:41:6:41:45 | root4_call_thread_without_initialization | root4_call_thread_without_initialization | +| test.c:58:11:58:13 | & ... | Thread specific storage pointer '$@' used before initialization from entry point function '$@'. | test.c:56:7:56:8 | g5 | g5 | test.c:67:6:67:50 | root6_spawn_thread_uninitialized_thread_local | root6_spawn_thread_uninitialized_thread_local | diff --git a/c/misra/test/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.qlref b/c/misra/test/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.qlref new file mode 100644 index 0000000000..10d9aadf1b --- /dev/null +++ b/c/misra/test/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.qlref @@ -0,0 +1 @@ +rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.expected b/c/misra/test/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.expected new file mode 100644 index 0000000000..75e9825074 --- /dev/null +++ b/c/misra/test/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.expected @@ -0,0 +1 @@ +| test.c:61:3:61:12 | call to tss_create | Thread specific storage object initialization reachable from threaded function '$@'. | test.c:57:6:57:41 | from_root6_init_and_use_thread_local | from_root6_init_and_use_thread_local | diff --git a/c/misra/test/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.qlref b/c/misra/test/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.qlref new file mode 100644 index 0000000000..d299808814 --- /dev/null +++ b/c/misra/test/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.qlref @@ -0,0 +1 @@ +rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-20/test.c b/c/misra/test/rules/RULE-22-20/test.c new file mode 100644 index 0000000000..0fe58abdcd --- /dev/null +++ b/c/misra/test/rules/RULE-22-20/test.c @@ -0,0 +1,70 @@ +#include "stdlib.h" +#include "threads.h" + +void use_local_mtxs(int x, int y) { + tss_t l1; + tss_get(&l1); // NON-COMPLIANT + tss_create(&l1, NULL); + tss_get(&l1); // COMPLIANT + + tss_t *l4 = malloc(sizeof(tss_t)); + tss_get(l4); // NON-COMPLIANT + tss_create(l4, NULL); + tss_get(l4); // COMPLIANT +} + +void root1_calls_use_local_mtxs() { + // Since a function exists which calls use_local_mtxs(), that function is not + // a root function. The query should still report unused locals in this case. + use_local_mtxs(1, 2); +} + +tss_t g1; + +void root2_uses_global_tss_t() { + tss_get(&g1); // NON-COMPLIANT +} + +void from_root3_use_global_tss_t() { + tss_get(&g1); // COMPLIANT +} + +void root3_initializes_and_uses_global_tss_t() { + tss_create(&g1, NULL); + from_root3_use_global_tss_t(); +} + +void from_root4_use_global_tss_t(void *arg) { + tss_get(&g1); // NON-COMPLIANT +} + +void root4_call_thread_without_initialization() { + thrd_t t; + thrd_create(&t, &from_root4_use_global_tss_t, NULL); +} + +void from_root5_use_global_tss_t(void *arg) { + tss_get(&g1); // COMPLIANT +} + +void root5_thread_with_initialization() { + tss_create(&g1, NULL); + thrd_t t; + thrd_create(&t, &from_root5_use_global_tss_t, NULL); +} + +mtx_t g5; +void from_root6_init_and_use_thread_local() { + tss_get(&g5); // NON-COMPLIANT + + // Violates recommendation, tss_t initialized within a thread. + tss_create(&g5, NULL); // NON-COMPLIANT + + // Valid if we except the above initialization. + tss_get(&g5); // COMPLIANT +} + +void root6_spawn_thread_uninitialized_thread_local() { + thrd_t t; + thrd_create(&t, &from_root6_init_and_use_thread_local, NULL); +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected b/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected index 6111072ba8..0365f4980d 100644 --- a/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected +++ b/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected @@ -1,3 +1,4 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (FileOpenForReadAndWriteOnDifferentStreams.ql:39,9-17) | test.c:6:14:6:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:5:14:5:18 | call to fopen | here | | test.c:17:14:17:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:16:14:16:18 | call to fopen | here | | test.c:33:14:33:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:32:14:32:18 | call to fopen | here | diff --git a/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected b/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected index 0bfce133c5..dbf08e3d3d 100644 --- a/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected +++ b/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected @@ -1,2 +1,8 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:19,32-40) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:20,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:25,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:31,21-29) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:33,6-14) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:36,28-36) | test.c:10:3:10:9 | call to fprintf | Attempt to write to a $@ opened as read-only. | test.c:9:14:9:18 | call to fopen | stream | | test.c:15:3:15:9 | call to fprintf | Attempt to write to a $@ opened as read-only. | test.c:18:14:18:18 | call to fopen | stream | diff --git a/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected b/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected index 709d8b002c..210a3a9218 100644 --- a/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected +++ b/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected @@ -1,2 +1,10 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:24,28-36) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:25,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:29,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:38,23-31) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:43,17-25) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:52,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:60,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:60,46-54) | test.c:6:7:6:20 | ... != ... | The check is not reliable as the type of the return value of $@ is converted. | test.c:5:14:5:20 | call to getchar | call to getchar | | test.c:13:7:13:15 | ... != ... | The check is not reliable as the type of the return value of $@ is converted. | test.c:12:14:12:20 | call to getchar | call to getchar | diff --git a/c/misra/test/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.expected b/c/misra/test/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.expected new file mode 100644 index 0000000000..03852b7cf2 --- /dev/null +++ b/c/misra/test/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.expected @@ -0,0 +1,3 @@ +| test.c:2:1:2:31 | #define M1 _Generic(1, int : 1) | Generic macro M1 doesn't refer to a macro parameter in controlling expr '1'. | +| test.c:4:1:4:34 | #define M2(X) _Generic(1, int : X) | Generic macro M2 doesn't refer to a macro parameter in controlling expr '1'. | +| test.c:18:1:18:39 | #define M9(X) g(_Generic((Y), int : 1)) | Generic macro M9 doesn't refer to a macro parameter in controlling expr '(Y)'. | diff --git a/c/misra/test/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.qlref b/c/misra/test/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.qlref new file mode 100644 index 0000000000..1ca5f792fa --- /dev/null +++ b/c/misra/test/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.qlref @@ -0,0 +1 @@ +rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.expected b/c/misra/test/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.expected new file mode 100644 index 0000000000..edc4b9270c --- /dev/null +++ b/c/misra/test/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.expected @@ -0,0 +1 @@ +| test.c:21:3:21:22 | _Generic | $@ in generic expression does not expand a macro parameter. | test.c:21:12:21:12 | 1 | Controlling expression | diff --git a/c/misra/test/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.qlref b/c/misra/test/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.qlref new file mode 100644 index 0000000000..59fae02b7f --- /dev/null +++ b/c/misra/test/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.qlref @@ -0,0 +1 @@ +rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-1/test.c b/c/misra/test/rules/RULE-23-1/test.c new file mode 100644 index 0000000000..c7d33b1a70 --- /dev/null +++ b/c/misra/test/rules/RULE-23-1/test.c @@ -0,0 +1,25 @@ +// NON_COMPLIANT: +#define M1 _Generic(1, int : 1) +// NON_COMPLIANT: +#define M2(X) _Generic(1, int : X) +// COMPLIANT: +#define M3(X) _Generic((X), int : 1) +// COMPLIANT: +#define M4(X) _Generic((X), int : 1) +// COMPLIANT: +#define M5(X) _Generic((X + X), int : 1) +int f1(int a, int b); +// COMPLIANT: +#define M6(X) _Generic(f(1, (X)), int : 1) +#define M7(X) 1 + _Generic((X), int : 1) +// COMPLIANT: +#define M8(X) g(_Generic((X), int : 1)) +// NON_COMPLIANT: +#define M9(X) g(_Generic((Y), int : 1)) + +void f2() { + _Generic(1, int : 1); // NON_COMPLIANT + M1; // NON_COMPLIANT + M2(1); // NON_COMPLIANT + M3(1); // COMPLIANT +} diff --git a/c/misra/test/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.expected b/c/misra/test/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.expected new file mode 100644 index 0000000000..b0a970bbcf --- /dev/null +++ b/c/misra/test/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.expected @@ -0,0 +1,3 @@ +| test.c:4:1:4:38 | #define M2(X) _Generic((X)++, int : 1) | Generic selection macro M2 contains a side effect '... ++', which is not from macro invocation arguments. | test.c:4:1:4:38 | #define M2(X) _Generic((X)++, int : 1) | (ignored) | +| test.c:7:1:7:39 | #define M3(X) _Generic(l1++, int : (X)) | Generic selection macro M3 contains a side effect '... ++', which is not from macro invocation arguments. | test.c:7:1:7:39 | #define M3(X) _Generic(l1++, int : (X)) | (ignored) | +| test.c:42:1:44:25 | #define M5(X) static volatile l ## X; _Generic(l ## X, int : 1) | Generic selection in macro M5 contains an invocation-dependent side effect which is not from macro invocation arguments, for example $@. | test.c:47:3:47:7 | _Generic | side effect 'la' | diff --git a/c/misra/test/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.qlref b/c/misra/test/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.qlref new file mode 100644 index 0000000000..bb3e39a58c --- /dev/null +++ b/c/misra/test/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.qlref @@ -0,0 +1 @@ +rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-2/test.c b/c/misra/test/rules/RULE-23-2/test.c new file mode 100644 index 0000000000..9e4c6ca6b2 --- /dev/null +++ b/c/misra/test/rules/RULE-23-2/test.c @@ -0,0 +1,49 @@ +#define M1(X) _Generic((X), int : 1) + +// NON_COMPLIANT: +#define M2(X) _Generic((X)++, int : 1) + +// NON_COMPLIANT: +#define M3(X) _Generic(l1++, int : (X)) + +// COMPLIANT: +#define M3_WRAPPER(X) M3(X) + +#define M4(X) _Generic((X)(), int : 1) + +void f1() { + int l1; + + _Generic(1, int : 1); // COMPLIANT + M1(1); // COMPLIANT + _Generic(l1, int : 1); // COMPLIANT + M1(l1); // COMPLIANT + + _Generic(l1++, + int : 1); // COMPLIANT: side effect is not from a macro argument. + M1(l1++); // COMPLIANT + M2(l1); // NON-COMPLIANT: at macro definition + M3(1); // NON-COMPLIANT: at macro definition + M3_WRAPPER(1); // NON-COMPLIANT: at definition of M3 +} + +int g1; +int pure() { return g1; } + +int impure() { return g1++; } + +void f2() { + M1(pure()); // COMPLIANT + M1(impure()); // COMPLIANT + M4(pure); // COMPLIANT + M4(impure); // NON_COMPLIANT[False negative] +} + +#define M5(X) \ + static volatile l##X; \ + _Generic(l##X, int : 1) + +void f3() { + M5(a); // NON-COMPLIANT + M5(b); // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.expected b/c/misra/test/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.expected new file mode 100644 index 0000000000..6a56026947 --- /dev/null +++ b/c/misra/test/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.expected @@ -0,0 +1,2 @@ +| test.c:2:1:2:36 | #define M1 _Generic(1, default : 1); | Generic selection contains no non-default association. | +| test.c:14:3:14:26 | _Generic | Generic selection contains no non-default association. | diff --git a/c/misra/test/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.qlref b/c/misra/test/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.qlref new file mode 100644 index 0000000000..b44de9083e --- /dev/null +++ b/c/misra/test/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.qlref @@ -0,0 +1 @@ +rules/RULE-23-3/GenericWithoutNonDefaultAssociation.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-3/test.c b/c/misra/test/rules/RULE-23-3/test.c new file mode 100644 index 0000000000..616c14bc80 --- /dev/null +++ b/c/misra/test/rules/RULE-23-3/test.c @@ -0,0 +1,23 @@ +// NON-COMPLIANT +#define M1 _Generic(1, default : 1); +// COMPLIANT +#define M2 _Generic(1, int : 1); +// COMPLIANT +#define M3 _Generic(1, int : 1, default : 1); +// COMPLIANT +#define M4 _Generic(1, int : 1, long : 1); + +void f() { + // Invalid generics: + // _Generic(1); + // _Generic(1, void: 1); + _Generic(1, default : 1); // NON-COMPLIANT + _Generic(1, int : 1); // COMPLIANT + _Generic(1, int : 1, default : 1); // COMPLIANT + _Generic(1, int : 1, long : 1); // COMPLIANT + + M1; + M2; + M3; + M4; +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-4/GenericAssociationWithUnselectableType.expected b/c/misra/test/rules/RULE-23-4/GenericAssociationWithUnselectableType.expected new file mode 100644 index 0000000000..132bb82979 --- /dev/null +++ b/c/misra/test/rules/RULE-23-4/GenericAssociationWithUnselectableType.expected @@ -0,0 +1,13 @@ +| test.c:11:24:11:24 | 1 | Generic selection uses unselectable type 'const int', due to qualifiers removed'. | test.c:11:24:11:24 | 1 | side effect | +| test.c:12:27:12:27 | 1 | Generic selection uses unselectable type 'volatile int', due to qualifiers removed'. | test.c:12:27:12:27 | 1 | side effect | +| test.c:13:26:13:26 | 1 | Generic selection uses unselectable type '_Atomic(int)', due to qualifiers removed'. | test.c:13:26:13:26 | 1 | side effect | +| test.c:16:33:16:33 | 1 | Generic selection uses unselectable type 'const volatile int', due to qualifiers removed'. | test.c:16:33:16:33 | 1 | side effect | +| test.c:18:24:18:24 | 1 | Generic selection uses unselectable type '(unnamed class/struct/union)', due to containing an anonymous struct or union type'. | test.c:18:24:18:24 | 1 | side effect | +| test.c:19:26:19:26 | 1 | Generic selection uses unselectable type 'struct *', due to containing an anonymous struct or union type'. | test.c:19:26:19:26 | 1 | side effect | +| test.c:24:23:24:23 | 1 | Generic selection uses unselectable type '(unnamed class/struct/union)', due to containing an anonymous struct or union type'. | test.c:24:23:24:23 | 1 | side effect | +| test.c:25:25:25:25 | 1 | Generic selection uses unselectable type 'union *', due to containing an anonymous struct or union type'. | test.c:25:25:25:25 | 1 | side effect | +| test.c:31:21:31:21 | 1 | Generic selection uses unselectable type 'int[3]', due to array-to-pointer decay'. | test.c:31:21:31:21 | 1 | side effect | +| test.c:40:1:40:55 | #define M1(X) _Generic((X), const int : 1, default : 0) | Generic in macro M1 has unselectable type 'const int', due to qualifiers removed. | test.c:40:1:40:55 | #define M1(X) _Generic((X), const int : 1, default : 0) | (ignored) | +| test.c:42:1:42:48 | #define M2(X) _Generic(1, X[3] : 1, default : 0) | Generic in macro M2 has an invocation-dependent unselectable type, for example $@. | test.c:49:3:49:10 | 1 | 'char[3]', due to array-to-pointer decay | +| test.c:52:3:52:15 | M3(X) | Generic resulting from invocation of macro $@ contains an unselectable type 'const int', due to qualifiers removed. | test.c:44:1:44:45 | #define M3(X) _Generic(1, X : 1, default : 0) | M3 | +| test.c:64:24:64:24 | 1 | Generic selection uses unselectable type 'const_int', due to qualifiers removed'. | test.c:64:24:64:24 | 1 | side effect | diff --git a/c/misra/test/rules/RULE-23-4/GenericAssociationWithUnselectableType.qlref b/c/misra/test/rules/RULE-23-4/GenericAssociationWithUnselectableType.qlref new file mode 100644 index 0000000000..1214be7ce2 --- /dev/null +++ b/c/misra/test/rules/RULE-23-4/GenericAssociationWithUnselectableType.qlref @@ -0,0 +1 @@ +rules/RULE-23-4/GenericAssociationWithUnselectableType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-4/test.c b/c/misra/test/rules/RULE-23-4/test.c new file mode 100644 index 0000000000..cfef26318c --- /dev/null +++ b/c/misra/test/rules/RULE-23-4/test.c @@ -0,0 +1,73 @@ +typedef struct { +} empty_struct_t; +struct empty_struct {}; +typedef union { +} empty_union_t; +union empty_union {}; + +void f() { + _Generic(1, + int : 1, // COMPLIANT + const int : 1, // NON-COMPLIANT + volatile int : 1, // NON-COMPLIANT + _Atomic int : 1, // NON-COMPLIANT + int * : 1, // COMPLIANT + int const * : 1, // COMPLIANT + const volatile int : 1, // NON-COMPLIANT + int volatile const * : 1, // COMPLIANT + struct {} : 1, // NON-COMPLIANT + struct {} * : 1, // NON-COMPLIANT + empty_struct_t : 1, // COMPLIANT + struct empty_struct : 1, // COMPLIANT + empty_struct_t * : 1, // COMPLIANT + struct empty_struct * : 1, // COMPLIANT + union {} : 1, // NON-COMPLIANT + union {} * : 1, // NON-COMPLIANT + empty_union_t : 1, // COMPLIANT + union empty_union : 1, // COMPLIANT + empty_union_t * : 1, // COMPLIANT + union empty_union * : 1, // COMPLIANT + // int[]: 1, // compile error + int[3] : 1, // NON-COMPLIANT + int(*)[3] : 1, // COMPLIANT: pointer to array OK + // int (int*): 1, // compile error + int (*)(int *) : 1, // COMPLIANT: function pointers OK + default : 1 // COMPLIANT + ); +} + +// NON-COMPLIANT +#define M1(X) _Generic((X), const int : 1, default : 0) +// NON-COMPLIANT +#define M2(X) _Generic(1, X[3] : 1, default : 0) +// COMPLIANT +#define M3(X) _Generic(1, X : 1, default : 0) + +void f2() { + M1(1); + M2(int); + M2(char); + + M3(int); // COMPLIANT + M3(const int); // NON-COMPLIANT +} + +typedef int int_t; +typedef int *int_ptr; +const typedef int const_int; +const typedef int *const_int_ptr; +typedef long const *long_const_ptr; + +void f3() { + _Generic(1, + int_t : 1, // COMPLIANT + const_int : 1, // NON-COMPLIANT + const_int_ptr : 1, // COMPLIANT + long_const_ptr : 1, // COMPLIANT + const int_ptr : 1, // COMPLIANT + default : 1 // COMPLIANT + ); +} + +// Type written here so it gets added to the database, see LvalueConversion.qll. +char *g; \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.expected b/c/misra/test/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.expected new file mode 100644 index 0000000000..3ed6b3f26b --- /dev/null +++ b/c/misra/test/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.expected @@ -0,0 +1,84 @@ +| test.c:41:3:41:46 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int *. | test.c:41:3:41:46 | _Generic | | +| test.c:42:3:42:49 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to volatile int *. | test.c:42:3:42:49 | _Generic | | +| test.c:43:3:43:55 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile int *. | test.c:43:3:43:55 | _Generic | | +| test.c:44:3:44:41 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to void *. | test.c:44:3:44:41 | _Generic | | +| test.c:45:3:45:47 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const void *. | test.c:45:3:45:47 | _Generic | | +| test.c:46:3:46:56 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile void *. | test.c:46:3:46:56 | _Generic | | +| test.c:48:3:48:40 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int *. | test.c:48:3:48:40 | _Generic | | +| test.c:50:3:50:41 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to void *. | test.c:50:3:50:41 | _Generic | | +| test.c:51:3:51:47 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const void *. | test.c:51:3:51:47 | _Generic | | +| test.c:52:3:52:56 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile void *. | test.c:52:3:52:56 | _Generic | | +| test.c:57:3:57:55 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile int *. | test.c:57:3:57:55 | _Generic | | +| test.c:59:3:59:40 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to int *. | test.c:59:3:59:40 | _Generic | | +| test.c:61:3:61:55 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to const volatile int *. | test.c:61:3:61:55 | _Generic | | +| test.c:62:3:62:41 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to void *. | test.c:62:3:62:41 | _Generic | | +| test.c:63:3:63:56 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to const volatile void *. | test.c:63:3:63:56 | _Generic | | +| test.c:69:3:69:40 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to int *. | test.c:69:3:69:40 | _Generic | | +| test.c:70:3:70:46 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const int *. | test.c:70:3:70:46 | _Generic | | +| test.c:71:3:71:49 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to volatile int *. | test.c:71:3:71:49 | _Generic | | +| test.c:73:3:73:41 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to void *. | test.c:73:3:73:41 | _Generic | | +| test.c:74:3:74:47 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const void *. | test.c:74:3:74:47 | _Generic | | +| test.c:75:3:75:56 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const volatile void *. | test.c:75:3:75:56 | _Generic | | +| test.c:77:3:77:40 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to int *. | test.c:77:3:77:40 | _Generic | | +| test.c:78:3:78:46 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to const int *. | test.c:78:3:78:46 | _Generic | | +| test.c:79:3:79:49 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to volatile int *. | test.c:79:3:79:49 | _Generic | | +| test.c:80:3:80:55 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to const volatile int *. | test.c:80:3:80:55 | _Generic | | +| test.c:82:3:82:47 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to const void *. | test.c:82:3:82:47 | _Generic | | +| test.c:83:3:83:56 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to const volatile void *. | test.c:83:3:83:56 | _Generic | | +| test.c:85:3:85:40 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to int *. | test.c:85:3:85:40 | _Generic | | +| test.c:86:3:86:46 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to const int *. | test.c:86:3:86:46 | _Generic | | +| test.c:87:3:87:55 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to const volatile int *. | test.c:87:3:87:55 | _Generic | | +| test.c:88:3:88:41 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to void *. | test.c:88:3:88:41 | _Generic | | +| test.c:90:3:90:56 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to const volatile void *. | test.c:90:3:90:56 | _Generic | | +| test.c:94:3:94:40 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to int *. | test.c:94:3:94:40 | _Generic | | +| test.c:95:3:95:46 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to const int *. | test.c:95:3:95:46 | _Generic | | +| test.c:96:3:96:49 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to volatile int *. | test.c:96:3:96:49 | _Generic | | +| test.c:97:3:97:55 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to const volatile int *. | test.c:97:3:97:55 | _Generic | | +| test.c:98:3:98:41 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to void *. | test.c:98:3:98:41 | _Generic | | +| test.c:99:3:99:47 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to const void *. | test.c:99:3:99:47 | _Generic | | +| test.c:119:3:119:47 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int *. | test.c:119:3:119:47 | _Generic | | +| test.c:120:3:120:50 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to volatile int *. | test.c:120:3:120:50 | _Generic | | +| test.c:121:3:121:56 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile int *. | test.c:121:3:121:56 | _Generic | | +| test.c:122:3:122:42 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to void *. | test.c:122:3:122:42 | _Generic | | +| test.c:123:3:123:48 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const void *. | test.c:123:3:123:48 | _Generic | | +| test.c:124:3:124:57 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile void *. | test.c:124:3:124:57 | _Generic | | +| test.c:126:3:126:41 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int *. | test.c:126:3:126:41 | _Generic | | +| test.c:128:3:128:42 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to void *. | test.c:128:3:128:42 | _Generic | | +| test.c:129:3:129:48 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const void *. | test.c:129:3:129:48 | _Generic | | +| test.c:130:3:130:57 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile void *. | test.c:130:3:130:57 | _Generic | | +| test.c:135:3:135:56 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile int *. | test.c:135:3:135:56 | _Generic | | +| test.c:137:3:137:41 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to int *. | test.c:137:3:137:41 | _Generic | | +| test.c:139:3:139:56 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to const volatile int *. | test.c:139:3:139:56 | _Generic | | +| test.c:140:3:140:42 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to void *. | test.c:140:3:140:42 | _Generic | | +| test.c:141:3:141:57 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to const volatile void *. | test.c:141:3:141:57 | _Generic | | +| test.c:147:3:147:41 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to int *. | test.c:147:3:147:41 | _Generic | | +| test.c:148:3:148:47 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const int *. | test.c:148:3:148:47 | _Generic | | +| test.c:149:3:149:50 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to volatile int *. | test.c:149:3:149:50 | _Generic | | +| test.c:151:3:151:42 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to void *. | test.c:151:3:151:42 | _Generic | | +| test.c:152:3:152:48 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const void *. | test.c:152:3:152:48 | _Generic | | +| test.c:153:3:153:57 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const volatile void *. | test.c:153:3:153:57 | _Generic | | +| test.c:156:3:156:47 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int *. | test.c:156:3:156:47 | _Generic | | +| test.c:157:3:157:50 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to volatile int *. | test.c:157:3:157:50 | _Generic | | +| test.c:158:3:158:56 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile int *. | test.c:158:3:158:56 | _Generic | | +| test.c:159:3:159:42 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to void *. | test.c:159:3:159:42 | _Generic | | +| test.c:160:3:160:48 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const void *. | test.c:160:3:160:48 | _Generic | | +| test.c:161:3:161:57 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile void *. | test.c:161:3:161:57 | _Generic | | +| test.c:163:3:163:41 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int *. | test.c:163:3:163:41 | _Generic | | +| test.c:165:3:165:42 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to void *. | test.c:165:3:165:42 | _Generic | | +| test.c:166:3:166:48 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const void *. | test.c:166:3:166:48 | _Generic | | +| test.c:167:3:167:57 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile void *. | test.c:167:3:167:57 | _Generic | | +| test.c:172:3:172:56 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile int *. | test.c:172:3:172:56 | _Generic | | +| test.c:180:3:180:50 | _Generic | Generic matched default selection, as controlling argument type int(*)[3] does not undergo pointer conversion to int(*const)[3]. | test.c:180:3:180:50 | _Generic | | +| test.c:188:3:192:16 | _Generic | Generic matched default selection, as controlling argument type int(*)[3] does not undergo pointer conversion to int(*const)[3]. | test.c:188:3:192:16 | _Generic | | +| test.c:201:3:201:49 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to int *. | test.c:201:3:201:49 | _Generic | | +| test.c:202:3:202:49 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to void *. | test.c:202:3:202:49 | _Generic | | +| test.c:216:3:216:46 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int *. | test.c:216:3:216:46 | _Generic | | +| test.c:217:3:217:48 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int_t *. | test.c:217:3:217:48 | _Generic | | +| test.c:218:3:218:44 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to c_int_t *. | test.c:218:3:218:44 | _Generic | | +| test.c:222:3:222:47 | _Generic | Generic matched default selection, as controlling argument type int_t * does not undergo pointer conversion to const int *. | test.c:222:3:222:47 | _Generic | | +| test.c:223:3:223:49 | _Generic | Generic matched default selection, as controlling argument type int_t * does not undergo pointer conversion to const int_t *. | test.c:223:3:223:49 | _Generic | | +| test.c:224:3:224:45 | _Generic | Generic matched default selection, as controlling argument type int_t * does not undergo pointer conversion to c_int_t *. | test.c:224:3:224:45 | _Generic | | +| test.c:226:3:226:40 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int *. | test.c:226:3:226:40 | _Generic | | +| test.c:227:3:227:42 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int_t *. | test.c:227:3:227:42 | _Generic | | +| test.c:232:3:232:41 | _Generic | Generic matched default selection, as controlling argument type c_int_t * does not undergo pointer conversion to int *. | test.c:232:3:232:41 | _Generic | | +| test.c:233:3:233:43 | _Generic | Generic matched default selection, as controlling argument type c_int_t * does not undergo pointer conversion to int_t *. | test.c:233:3:233:43 | _Generic | | diff --git a/c/misra/test/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.qlref b/c/misra/test/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.qlref new file mode 100644 index 0000000000..c6b02b6273 --- /dev/null +++ b/c/misra/test/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.qlref @@ -0,0 +1 @@ +rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-5/test.c b/c/misra/test/rules/RULE-23-5/test.c new file mode 100644 index 0000000000..5d48cc58bd --- /dev/null +++ b/c/misra/test/rules/RULE-23-5/test.c @@ -0,0 +1,237 @@ +void f1(); + +void f2() { + int l1; + int *l2; + const int *l3; + volatile int *l4; + volatile const int *l5; + void *l6; + const void *l7; + volatile void *l8; + const volatile void *l9; + + // No violation for missing pointer/integral conversions: + _Generic(l1, // COMPLIANT + int *: f1, + const int *: f1, + volatile int *: f1, + void *: f1, + const void *: f1, + default: f1); // COMPLIANT + _Generic(l2, int : f1, default : f1); // COMPLIANT + _Generic(l3, int : f1, default : f1); // COMPLIANT + _Generic(l4, int : f1, default : f1); // COMPLIANT + _Generic(l5, int : f1, default : f1); // COMPLIANT + + // Compliant, default case is not matched + _Generic(l1, int : f1); // COMPLIANT + _Generic(l2, int * : f1); // COMPLIANT + _Generic(l3, const int * : f1); // COMPLIANT + _Generic(l4, volatile int * : f1); // COMPLIANT + _Generic(l5, volatile const int * : f1); // COMPLIANT + _Generic(l6, void * : f1); // COMPLIANT + _Generic(l7, const void * : f1); // COMPLIANT + _Generic(l8, volatile void * : f1); // COMPLIANT + _Generic(l9, const volatile void * : f1); // COMPLIANT + + // Violation, match default case due to lack of pointer to pointer + // conversions: + _Generic(l2, int * : f1, default : f1); // COMPLIANT + _Generic(l2, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l2, volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l2, const volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l2, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l2, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l2, const volatile void * : f1, default : f1); // NON-COMPLIANT + + _Generic(l3, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l3, const int * : f1, default : f1); // COMPLIANT + _Generic(l3, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l3, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l3, const volatile void * : f1, default : f1); // NON-COMPLIANT + // Obviously not volatile: + _Generic(l3, volatile int * : f1, default : f1); // COMPLIANT + // Debatable, but volatile const int* is assignable to const int* so its + // considered risky + _Generic(l3, const volatile int * : f1, default : f1); // NON-COMPLIANT + + _Generic(l4, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l4, volatile int * : f1, default : f1); // COMPLIANT + _Generic(l4, const volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l4, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l4, const volatile void * : f1, default : f1); // NON-COMPLIANT + // Debatable, but volatile int* isn't assignable to const int* or vice versa. + _Generic(l4, const int * : f1, default : f1); // COMPLIANT + // Debatable, but volatile int* isn't assignable to const void* or vice versa. + _Generic(l4, const void * : f1, default : f1); // COMPLIANT + + _Generic(l5, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l5, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l5, volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l5, const volatile int * : f1, default : f1); // COMPLIANT + _Generic(l5, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l5, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l5, const volatile void * : f1, default : f1); // NON-COMPLIANT + + _Generic(l6, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l6, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l6, volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l6, const volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l6, void * : f1, default : f1); // COMPLIANT + _Generic(l6, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l6, const volatile void * : f1, default : f1); // NON-COMPLIANT + + _Generic(l7, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l7, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l7, const volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l7, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l7, const void * : f1, default : f1); // COMPLIANT + _Generic(l7, const volatile void * : f1, default : f1); // NON-COMPLIANT + // Debatable, but const void* isn't assignable to volatile int* or vice versa. + _Generic(l7, volatile int * : f1, default : f1); // COMPLIANT + + _Generic(l9, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l9, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l9, volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l9, const volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l9, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l9, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l9, const volatile void * : f1, default : f1); // COMPLIANT + + /** + * Edge case 1: The controlling expression undergoes lvalue conversion, so + * arrays become pointers and qualifiers on pointers are stripped. + */ + int l10[3]; + const int l11[3]; + volatile int l12[3]; + const volatile int l13[3]; + int *const l14; + const int *const l15; + + _Generic(l10, int * : f1, default : f1); // COMPLIANT + _Generic(l11, const int * : f1, default : f1); // COMPLIANT + _Generic(l12, volatile int * : f1, default : f1); // COMPLIANT + _Generic(l13, const volatile int * : f1, default : f1); // COMPLIANT + + _Generic(l10, int * : f1, default : f1); // COMPLIANT + _Generic(l10, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l10, volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l10, const volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l10, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l10, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l10, const volatile void * : f1, default : f1); // NON-COMPLIANT + + _Generic(l11, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l11, const int * : f1, default : f1); // COMPLIANT + _Generic(l11, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l11, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l11, const volatile void * : f1, default : f1); // NON-COMPLIANT + // Obviously not volatile: + _Generic(l11, volatile int * : f1, default : f1); // COMPLIANT + // Debatable, but volatile const int* is assignable to const int* so its + // considered risky + _Generic(l11, const volatile int * : f1, default : f1); // NON-COMPLIANT + + _Generic(l12, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l12, volatile int * : f1, default : f1); // COMPLIANT + _Generic(l12, const volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l12, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l12, const volatile void * : f1, default : f1); // NON-COMPLIANT + // Debatab12e, but volatile int* isn't assignable to const int* or vice versa. + _Generic(l12, const int * : f1, default : f1); // COMPLIANT + // Debatable, but volatile int* isn't assignable to const void* or vice versa. + _Generic(l12, const void * : f1, default : f1); // COMPLIANT + + _Generic(l13, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l13, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l13, volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l13, const volatile int * : f1, default : f1); // COMPLIANT + _Generic(l13, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l13, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l13, const volatile void * : f1, default : f1); // NON-COMPLIANT + + _Generic(l14, int * : f1, default : f1); // COMPLIANT + _Generic(l14, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l14, volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l14, const volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l14, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l14, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l14, const volatile void * : f1, default : f1); // NON-COMPLIANT + + _Generic(l15, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l15, const int * : f1, default : f1); // COMPLIANT + _Generic(l15, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l15, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l15, const volatile void * : f1, default : f1); // NON-COMPLIANT + // Obviously not volatile: + _Generic(l15, volatile int * : f1, default : f1); // COMPLIANT + // Debatable, but volatile const int* is assignable to const int* so its + // considered risky + _Generic(l15, const volatile int * : f1, default : f1); // NON-COMPLIANT + + /** + * Edge case 2: Types don't have to be identical to be compatible. + */ + int(*l16)[3]; + + // This is a risky conversion that should be reported: + _Generic(l16, int(*const)[3] : f1, default : f1); // NON-COMPLIANT + // However, in this one, there is a match on the second selector, because it + // it is an array type with a compatible element type, and sizes only have to + // match if both arrays have a constant size. Therefore, the default selector + // is not chosen and this is not a violation. + _Generic(l16, int(*const)[3] : f1, int(*)[] : f1, default : f1); // COMPLIANT + // In this case, the second selector is not a compatible type because the + // array has a constant size that doesn't match, and this should be reported. + _Generic(l16, int(*const)[3] + : f1, int(*)[4] + : f1, + default + : f1); // NON-COMPLIANT + + /** + * Edge case 3: Conversion on _Generic, make sure we use the fully converted + * type when considering compliance. + */ + int *l17; + void *l18; + _Generic((void *)l17, void * : f1, default : f1); // COMPLIANT + _Generic((void *)l17, int * : f1, default : f1); // NON-COMPLIANT + _Generic((int *)l18, void * : f1, default : f1); // NON-COMPLIANT + _Generic((int *)l18, int * : f1, default : f1); // COMPLIANT + + /** + * Edge case 4: Typedefs must be resolved properly. + */ + typedef int int_t; + const typedef int c_int_t; + int_t *l19; + c_int_t *l20; + volatile c_int_t *l21; + + _Generic(l2, int * : f1, default : f1); // COMPLIANT + _Generic(l2, int_t * : f1, default : f1); // COMPLIANT + _Generic(l2, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l2, const int_t * : f1, default : f1); // NON-COMPLIANT + _Generic(l2, c_int_t * : f1, default : f1); // NON-COMPLIANT + + _Generic(l19, int * : f1, default : f1); // COMPLIANT + _Generic(l19, int_t * : f1, default : f1); // COMPLIANT + _Generic(l19, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l19, const int_t * : f1, default : f1); // NON-COMPLIANT + _Generic(l19, c_int_t * : f1, default : f1); // NON-COMPLIANT + + _Generic(l3, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l3, int_t * : f1, default : f1); // NON-COMPLIANT + _Generic(l3, const int * : f1, default : f1); // COMPLIANT + _Generic(l3, const int_t * : f1, default : f1); // COMPLIANT + _Generic(l3, c_int_t * : f1, default : f1); // COMPLIANT + + _Generic(l20, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l20, int_t * : f1, default : f1); // NON-COMPLIANT + _Generic(l20, const int * : f1, default : f1); // COMPLIANT + _Generic(l20, const int_t * : f1, default : f1); // COMPLIANT + _Generic(l20, c_int_t * : f1, default : f1); // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.expected b/c/misra/test/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.expected new file mode 100644 index 0000000000..4f02d039ce --- /dev/null +++ b/c/misra/test/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.expected @@ -0,0 +1,4 @@ +| test.c:11:3:11:8 | _Generic | Controlling expression in generic macro $@ has standard type (unnamed enum), which doesn't match its essential type (unnamed enum). | test.c:6:1:6:75 | #define M1(X) _Generic((X), int : 1, unsigned int : 1, short : 2, long : 3) | M1 | +| test.c:15:3:15:13 | _Generic | Controlling expression in generic macro $@ has standard type int, which doesn't match its essential type short. | test.c:6:1:6:75 | #define M1(X) _Generic((X), int : 1, unsigned int : 1, short : 2, long : 3) | M1 | +| test.c:18:3:18:24 | _Generic | Controlling expression in generic has standard type int, which doesn't match its essential type char. | test.c:18:3:18:24 | _Generic | | +| test.c:19:3:19:55 | _Generic | Controlling expression in generic has standard type int, which doesn't match its essential type short. | test.c:19:3:19:55 | _Generic | | diff --git a/c/misra/test/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.qlref b/c/misra/test/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.qlref new file mode 100644 index 0000000000..b91bbefec6 --- /dev/null +++ b/c/misra/test/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.qlref @@ -0,0 +1 @@ +rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-6/test.c b/c/misra/test/rules/RULE-23-6/test.c new file mode 100644 index 0000000000..2b18f4cd2c --- /dev/null +++ b/c/misra/test/rules/RULE-23-6/test.c @@ -0,0 +1,33 @@ +short l1; +int l2; +long l3; +enum { E1 } l4; + +#define M1(X) _Generic((X), int : 1, unsigned int : 1, short : 2, long : 3) +void f1() { + M1(l1); // COMPLIANT + M1(l2); // COMPLIANT + M1(l3); // COMPLIANT + M1(l4); // NON-COMPLIANT + + M1(1); // COMPLIANT + M1(1u); // COMPLIANT + M1(l1 + l1); // NON-COMPLIANT + M1((int)(l1 + l1)); // COMPLIANT + M1('c'); // NON-COMPLIANT[false negative] + _Generic('c', int : 1); // NON-COMPLIANT + _Generic(_Generic(0, default : l1 + l1), default : 1); // NON-COMPLIANT + _Generic(((short)_Generic(0, default : (l1 + l1))), default : 1); // COMPLIANT +} + +void f2() { + // Edge case: lvalue conversion of a const struct yields an implicit + // conversion to a non-const struct which is ignored by EssentialTypes.qll, + // meaning the essential type does not match the static type. However, we + // shouldn't report an issue here as the static/essential types are not one + // of the essential type categories. + struct S1 { + int m1; + }; + _Generic((const struct S1){.m1 = 0}, default : 1); +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.expected b/c/misra/test/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.expected new file mode 100644 index 0000000000..47a8acce92 --- /dev/null +++ b/c/misra/test/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.expected @@ -0,0 +1,12 @@ +| test.c:9:1:9:53 | #define M3(X) _Generic((X), int : f1(X), default : 0) | Generic macro M3 may have unexpected behavior from side effects in parameter X, as it is not expanded in generic selection 2. | +| test.c:10:1:10:63 | #define M4(X) (X) + _Generic((X), int : f1(X), default : f1(X)) | Generic macro M4 may have unexpected behavior from side effects in parameter X, as it is expanded outside the generic selection and inside the generic selection. | +| test.c:11:1:11:63 | #define M5(X) _Generic((X), int : f1(X), default : f1(X)) + (X) | Generic macro M5 may have unexpected behavior from side effects in parameter X, as it is expanded outside the generic selection and inside the generic selection. | +| test.c:12:1:12:65 | #define M6(X) _Generic((X), int : f1((X) + (X)), default : f1(X)) | Generic macro M6 may have unexpected behavior from side effects in parameter X, as it is expanded in generic selection 1 more than once. | +| test.c:21:1:21:37 | #define M9(X) _Generic((X), int : f1) | Generic macro M9 may have unexpected behavior from side effects in parameter X, as it is not expanded in generic selection 1. | +| test.c:23:1:23:41 | #define M10(X) _Generic((X), int : f1(1)) | Generic macro M10 may have unexpected behavior from side effects in parameter X, as it is not expanded in generic selection 1. | +| test.c:32:1:32:60 | #define M12(X) _Generic((X) + (X), int : f1(X), default : 1) | Generic macro M12 may have unexpected behavior from side effects in parameter X, as it is not expanded in generic selection 2. | +| test.c:33:1:33:70 | #define M13(X) _Generic((X) + (X), int : f1(X), default : f1(X)) + (X) | Generic macro M13 may have unexpected behavior from side effects in parameter X, as it is expanded outside the generic selection and inside the generic selection. | +| test.c:43:1:43:79 | #define M17(X,Y) _Generic((X) + (Y), int : f2((X), (Y)), default : f2((X), 1)) | Generic macro M17 may have unexpected behavior from side effects in parameter Y, as it is not expanded in generic selection 2. | +| test.c:68:1:68:80 | #define M26(X) _Generic((X), int : IGNORE_2ND(X, X), default : IGNORE_2ND(X, X)) | Generic macro M26 may have unexpected behavior from side effects in parameter X, as it is expanded in generic selection 1 more than once. | +| test.c:68:1:68:80 | #define M26(X) _Generic((X), int : IGNORE_2ND(X, X), default : IGNORE_2ND(X, X)) | Generic macro M26 may have unexpected behavior from side effects in parameter X, as it is expanded in generic selection 2 more than once. | +| test.c:69:1:69:77 | #define M27(X) _Generic((X), int : f1(IGNORE(X)), default : f1(IGNORE(X)))(X) | Generic macro M27 may have unexpected behavior from side effects in parameter X, as it is expanded outside the generic selection and inside the generic selection. | diff --git a/c/misra/test/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.qlref b/c/misra/test/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.qlref new file mode 100644 index 0000000000..3156bdce91 --- /dev/null +++ b/c/misra/test/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.qlref @@ -0,0 +1 @@ +rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-7/test.c b/c/misra/test/rules/RULE-23-7/test.c new file mode 100644 index 0000000000..e2f5e98ee5 --- /dev/null +++ b/c/misra/test/rules/RULE-23-7/test.c @@ -0,0 +1,72 @@ +int f1(int p1); +int f2(int p1, int p2); + +// COMPLIANT -- standard correct cases: +#define M1(X) _Generic((X), int : f1, default : f1)(X) +#define M2(X) _Generic((X), int : f1(X), default : f1(X)) + +// NON-COMPLIANT -- standard incorrect cases: +#define M3(X) _Generic((X), int : f1(X), default : 0) +#define M4(X) (X) + _Generic((X), int : f1(X), default : f1(X)) +#define M5(X) _Generic((X), int : f1(X), default : f1(X)) + (X) +#define M6(X) _Generic((X), int : f1((X) + (X)), default : f1(X)) + +// Compliant by exception +// COMPLIANT +#define M7(X) _Generic((X), int : 1, default : 0) +// NON-COMPLIANT[FALSE NEGATIVE] -- Without an expansion, we can't tell if this +// macro has only constant expressions or not. +#define M8(X) _Generic((X), int : f1(1)) +// NON-COMPLIANT -- If the macro is expanded we can detect constant expressions +#define M9(X) _Generic((X), int : f1) +// NON-COMPLIANT -- If the macro is expanded we can detect constant expressions +#define M10(X) _Generic((X), int : f1(1)) +void f3() { + M9(1); + M10(1); +} + +// COMPLIANT -- multiple uses in the controlling expression is OK: +#define M11(X) _Generic((X) + (X), int : f1(X), default : f1(X)) +// NON-COMPLIANT -- the rule should still be enforced otherwise: +#define M12(X) _Generic((X) + (X), int : f1(X), default : 1) +#define M13(X) _Generic((X) + (X), int : f1(X), default : f1(X)) + (X) + +// COMPLIANT -- the argument is not used in the controlling expression: +#define M14(X) _Generic(1, int : f1((X) + (X)), default : f1(X)) +#define M15(X) _Generic(1, int : f1(X), default : f1(X)) + (X) + +// Test cases with more than one argument: +// COMPLIANT -- Y is not used in the controlling expression: +#define M16(X, Y) _Generic((X), int : f2((X), (Y)), default : f2((X), 1)) +// NON-COMPLIANT -- Y is used in the controlling expression +#define M17(X, Y) _Generic((X) + (Y), int : f2((X), (Y)), default : f2((X), 1)) +// COMPLIANT -- Y is used in the controlling expression correctly +#define M18(X, Y) \ + _Generic((X) + (Y), int : f2((X), (Y)), default : f2((X), (Y))) + +// Test unevaluated contexts: +// COMPLIANT -- sizeof is not evaluated: +#define M19(X) _Generic((X), int[sizeof(X)] : f1, default : f1)(X) +#define M20(X) _Generic((X), int : f1(sizeof(X)), default : f1)(X) +#define M21(X) _Generic((X), int : f1(X), default : f1(X)) + sizeof(X) +// NON-COMPLIANT[FALSE NEGATIVE] -- sizeof plus evaluated context +#define M22(X) _Generic((X), int : f1(sizeof(X) + X), default : f1(X))(X) +// NON-COMPLIANT[FALSE NEGATIVE] -- array type sizes may be evaluated +#define M23(X) _Generic((X), int[X] : f1, default : f1)(X) +// COMPLIANT -- alignof, typeof are not evaluated: +#define M24(X) _Generic((X), int[X] : f1, default : f1)(X) + +// Nested macros: +#define ONCE(X) (X) +#define TWICE(X) (X) + (X) +#define IGNORE(X) (1) +#define IGNORE_2ND(X, Y) (X) +// COMPLIANT +#define M25(X) _Generic((X), int: ONCE(f1(X)), default: ONCE(f1(X)) +// COMPLIANT[FALSE POSITIVE] +#define M26(X) _Generic((X), int : IGNORE_2ND(X, X), default : IGNORE_2ND(X, X)) +#define M27(X) _Generic((X), int : f1(IGNORE(X)), default : f1(IGNORE(X)))(X) +// NON-COMPLIANT[FASE NEGATIVE] +#define M28(X) _Generic((X), int : f1(IGNORE(X)), default : f1(IGNORE(X))) +#define M29(X) _Generic((X), int : TWICE(f1(X)), default : TWICE(f1(X))) \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.expected b/c/misra/test/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.expected new file mode 100644 index 0000000000..fb407e2ff1 --- /dev/null +++ b/c/misra/test/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.expected @@ -0,0 +1,4 @@ +| test.c:11:1:11:67 | #define M4(X) _Generic((X), int : 1, default : 0, unsigned int : 2) | Generic macro M4 has default as 2nd association, which is not first or last. | test.c:11:1:11:67 | #define M4(X) _Generic((X), int : 1, default : 0, unsigned int : 2) | (ignored) | +| test.c:17:1:17:62 | #define M5(__VA_ARGS__...) _Generic(0, __VA_ARGS__, default : 0, int : 1) | Generic macro M5 has a default association which is not first or last, for example $@. | test.c:30:3:30:22 | _Generic | 2nd | +| test.c:37:3:37:27 | M6(__VA_ARGS__...) | Generic macro $@, in this expansion, has default as 2nd association, which is not first or last. | test.c:19:1:19:49 | #define M6(__VA_ARGS__...) _Generic(0, __VA_ARGS__, int : 1) | M6 | +| test.c:48:3:48:53 | _Generic | Generic has default as 2nd association, which is not first or last. | test.c:48:3:48:53 | _Generic | | diff --git a/c/misra/test/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.qlref b/c/misra/test/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.qlref new file mode 100644 index 0000000000..06fe786e7d --- /dev/null +++ b/c/misra/test/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.qlref @@ -0,0 +1 @@ +rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-8/test.c b/c/misra/test/rules/RULE-23-8/test.c new file mode 100644 index 0000000000..340ddb16db --- /dev/null +++ b/c/misra/test/rules/RULE-23-8/test.c @@ -0,0 +1,49 @@ +/** + * Cases where the macro itself is always compliant or non compliant: + */ +// COMPLIANT +#define M1(X) _Generic((X), int : 1, unsigned int : 2) +// COMPLIANT +#define M2(X) _Generic((X), int : 1, unsigned int : 2, default : 0) +// COMPLIANT +#define M3(X) _Generic((X), default : 0, int : 1, unsigned int : 2) +// NON-COMPLIANT +#define M4(X) _Generic((X), int : 1, default : 0, unsigned int : 2) + +/** + * Macros that are compliant or not based on use: + */ +// NON-COMPLIANT: because every use is non compliant +#define M5(...) _Generic(0, __VA_ARGS__, default : 0, int : 1) +// COMPLIANT: because some uses are compliant +#define M6(...) _Generic(0, __VA_ARGS__, int : 1) + +void f1() { + M1(0); // COMPLIANT + M2(0); // COMPLIANT + M3(0); // COMPLIANT + M4(0); // COMPLIANT: the macro invocation is compliant, the macro definition + // is not. + + // COMPLIANT: all invocations of M5 are non compliant so the macro is reported + // instead. + M5(unsigned int : 1); + M5(unsigned int : 1, long : 2); + + // Some invocations of M6() will be compliant, so we'll report the issue at + // each invocation. + M6(default : 0); // COMPLIANT + M6(default : 0, long : 1); // COMPLIANT + M6(long : 1, default : 0); // NON-COMPLIANT +} + +/** + * For completeness, non macro cases, though these are not likely and violate + * RULE-23-1. + */ +void f2() { + _Generic(0, int : 1, unsigned int : 2); // COMPLIANT + _Generic(0, int : 1, unsigned int : 2, default : 0); // COMPLIANT + _Generic(0, default : 0, int : 1, unsigned int : 2); // COMPLIANT + _Generic(0, int : 1, default : 0, unsigned int : 2); // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.expected b/c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.expected index 5e876cecc3..3c4cab00b1 100644 --- a/c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.expected +++ b/c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.expected @@ -1,3 +1,6 @@ | test.c:9:1:9:8 | /* /* */ | Comment contains an illegal sequence '/*' | | test.c:12:1:12:8 | /* // */ | Comment contains an illegal sequence '//' | | test.c:21:1:21:7 | // /* | Comment contains an illegal sequence '/*' | +| test.c:30:1:30:27 | /* https://github.com // */ | Comment contains an illegal sequence '//' | +| test.c:33:1:33:60 | /* a://b, a://b., ://a.b, a://b., a://.b, ://, a://, ://b */ | Comment contains an illegal sequence '//' | +| test.c:42:1:42:8 | ///* foo | Comment contains an illegal sequence '/*' | diff --git a/c/misra/test/rules/RULE-3-1/test.c b/c/misra/test/rules/RULE-3-1/test.c index c1a135f972..fd7a6574dd 100644 --- a/c/misra/test/rules/RULE-3-1/test.c +++ b/c/misra/test/rules/RULE-3-1/test.c @@ -20,4 +20,25 @@ // NON_COMPLIANT // /* +// COMPLIANT +/* https://github.com */ + +// COMPLIANT +/* https://name-with-hyphen-and-num-12345.com */ + +// NON_COMPLIANT +/* https://github.com // */ + +// NON_COMPLIANT +/* a://b, a://b., ://a.b, a://b., a://.b, ://, a://, ://b */ + +// COMPLIANT +// https://github.com + +// COMPLIANT +//* foo + +// NON_COMPLIANT +///* foo + void f(){} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.expected b/c/misra/test/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.expected deleted file mode 100644 index 39d5aa5d85..0000000000 --- a/c/misra/test/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.expected +++ /dev/null @@ -1,21 +0,0 @@ -| test.c:9:18:9:24 | \u001aG | Invalid hexadecimal escape in string literal at '\\x1AG"'. | -| test.c:12:18:12:23 | \u00029 | Invalid octal escape in string literal at '\\029"'. | -| test.c:15:18:15:24 | \n7 | Invalid octal escape in string literal at '\\0127"'. | -| test.c:16:18:16:24 | \r7 | Invalid octal escape in string literal at '\\0157"'. | -| test.c:18:19:18:29 | \n\n9 | Invalid octal escape in string literal at '\\0129"'. | -| test.c:19:19:19:28 | \n\u00019 | Invalid octal escape in string literal at '\\019"'. | -| test.c:22:19:22:31 | \nAAA\u000f | Invalid octal escape in string literal at '\\012AAA\\017"'. | -| test.c:25:19:25:39 | Some Data \n\u000fA | Invalid octal escape in string literal at '\\017A"'. | -| test.c:26:19:27:21 | Some Data \n\u000fA5 | Invalid octal escape in string literal at '\\017A"\n "5"'. | -| test.c:28:19:30:25 | Some Data \n\u000fA\n1 | Invalid octal escape in string literal at '\\0121"'. | -| test.c:34:19:35:26 | \u0011G\u00012 | Invalid octal escape in string literal at '\\0012"'. | -| test.c:36:19:37:25 | \u0011GG\u0001 | Invalid hexadecimal escape in string literal at '\\x11G"\n "G\\001"'. | -| test.c:38:19:39:26 | \u0011GG\u00013 | Invalid hexadecimal escape in string literal at '\\x11G"\n "G\\0013"'. | -| test.c:38:19:39:26 | \u0011GG\u00013 | Invalid octal escape in string literal at '\\0013"'. | -| test.c:45:18:45:42 | Some Data \n\u000fA5 | Invalid octal escape in string literal at '\\017A" "5"'. | -| test.c:46:18:46:49 | Some Data \n\u000fA\n1 | Invalid octal escape in string literal at '\\0121"'. | -| test.c:48:18:48:32 | \u0011G\u00012 | Invalid octal escape in string literal at '\\0012"'. | -| test.c:49:18:49:32 | \u0011GG\u0001 | Invalid hexadecimal escape in string literal at '\\x11G" "G\\001"'. | -| test.c:50:18:50:33 | \u0011GG\u00013 | Invalid hexadecimal escape in string literal at '\\x11G" "G\\0013"'. | -| test.c:50:18:50:33 | \u0011GG\u00013 | Invalid octal escape in string literal at '\\0013"'. | -| test.c:53:11:53:16 | 10 | Invalid hexadecimal escape in string literal at '\\x0a''. | diff --git a/c/misra/test/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.qlref b/c/misra/test/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.qlref deleted file mode 100644 index fbdd187532..0000000000 --- a/c/misra/test/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.testref b/c/misra/test/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.testref new file mode 100644 index 0000000000..f8b5396a9c --- /dev/null +++ b/c/misra/test/rules/RULE-4-1/OctalAndHexadecimalEscapeSequencesNotTerminated.testref @@ -0,0 +1 @@ +c/common/test/rules/nonterminatedescapesequences/NonTerminatedEscapeSequences.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-4-1/test.c b/c/misra/test/rules/RULE-4-1/test.c deleted file mode 100644 index 4a0dcaa6ac..0000000000 --- a/c/misra/test/rules/RULE-4-1/test.c +++ /dev/null @@ -1,53 +0,0 @@ -const char *a1 = "\x11" - "G"; // COMPLIANT - -const char *a2 = "\x1" - "G"; // COMPLIANT - -const char *a3 = "\x1A"; // COMPLIANT - -const char *a4 = "\x1AG"; // NON_COMPLIANT - -const char *a5 = "\021"; // COMPLIANT -const char *a6 = "\029"; // NON_COMPLIANT -const char *a7 = "\0" - "0"; // COMPLIANT -const char *a8 = "\0127"; // NON_COMPLIANT -const char *a9 = "\0157"; // NON_COMPLIANT - -const char *a10 = "\012\0129"; // NON_COMPLIANT (1x) -const char *a11 = "\012\019"; // NON_COMPLIANT -const char *a12 = "\012\017"; // COMPLIANT - -const char *a13 = "\012AAA\017"; // NON_COMPLIANT (1x) - -const char *a14 = "Some Data \012\017"; // COMPLIANT -const char *a15 = "Some Data \012\017A"; // NON_COMPLIANT (1x) -const char *a16 = "Some Data \012\017A" - "5"; // NON_COMPLIANT (1x) -const char *a17 = "Some Data \012\017" - "A" - "\0121"; // NON_COMPLIANT (1x) - -const char *a18 = "\x11" - "G\001"; // COMPLIANT -const char *a19 = "\x11" - "G\0012"; // NON_COMPLIANT (1x) -const char *a20 = "\x11G" - "G\001"; // NON_COMPLIANT (1x) -const char *a21 = "\x11G" - "G\0013"; // NON_COMPLIANT (2x) - -// clang-format off -const char *b1 = "\x11" "G"; // COMPLIANT -const char *b2 = "\x1" "G"; // COMPLIANT -const char *b3 = "\0" "0"; // COMPLIANT -const char *b4 = "Some Data \012\017A" "5"; // NON_COMPLIANT (1x) -const char *b5 = "Some Data \012\017" "A" "\0121"; // NON_COMPLIANT (1x) -const char *b6 = "\x11" "G\001"; // COMPLIANT -const char *b7 = "\x11" "G\0012"; // NON_COMPLIANT (1x) -const char *b8 = "\x11G" "G\001"; // NON_COMPLIANT (1x) -const char *b9 = "\x11G" "G\0013"; // NON_COMPLIANT (2x) - -char c1 = '\023'; // COMPLIANT -char c2 = '\x0a'; // COMPLIANT diff --git a/c/misra/test/rules/RULE-5-4/MacroIdentifiersNotDistinct.expected b/c/misra/test/rules/RULE-5-4/MacroIdentifiersNotDistinct.expected index 12507b2d3f..b079b7e94d 100644 --- a/c/misra/test/rules/RULE-5-4/MacroIdentifiersNotDistinct.expected +++ b/c/misra/test/rules/RULE-5-4/MacroIdentifiersNotDistinct.expected @@ -1,2 +1,4 @@ +| header3.h:7:1:7:24 | #define MULTIPLE_INCLUDE | Definition of macro MULTIPLE_INCLUDE is not distinct from alternative definition of $@ in header4.h. | header4.h:1:1:1:24 | #define MULTIPLE_INCLUDE | MULTIPLE_INCLUDE | +| header3.h:14:1:14:21 | #define NOT_PROTECTED | Definition of macro NOT_PROTECTED is not distinct from alternative definition of $@ in header4.h. | header4.h:12:1:12:23 | #define NOT_PROTECTED 1 | NOT_PROTECTED | | test.c:2:1:2:72 | #define iltiqzxgfqsgigwfuyntzghvzltueatcxqnqofnnvjyszmcsylyohvqaosjbqyyB | Macro identifer iltiqzxgfqsgigwfuyntzghvzltueatcxqnqofnnvjyszmcsylyohvqaosjbqyyB is nondistinct in first 63 characters, compared to $@. | test.c:1:1:1:72 | #define iltiqzxgfqsgigwfuyntzghvzltueatcxqnqofnnvjyszmcsylyohvqaosjbqyyA | iltiqzxgfqsgigwfuyntzghvzltueatcxqnqofnnvjyszmcsylyohvqaosjbqyyA | -| test.c:8:1:8:31 | #define FUNCTION_MACRO(X) X + 1 | Macro identifer FUNCTION_MACRO is nondistinct in first 63 characters, compared to $@. | test.c:7:1:7:57 | #define FUNCTION_MACRO(FUNCTION_MACRO) FUNCTION_MACRO + 1 | FUNCTION_MACRO | +| test.c:8:1:8:31 | #define FUNCTION_MACRO(X) X + 1 | Definition of macro FUNCTION_MACRO is not distinct from alternative definition of $@ in test.c. | test.c:7:1:7:57 | #define FUNCTION_MACRO(FUNCTION_MACRO) FUNCTION_MACRO + 1 | FUNCTION_MACRO | diff --git a/c/misra/test/rules/RULE-5-4/conditional.h b/c/misra/test/rules/RULE-5-4/conditional.h new file mode 100644 index 0000000000..d30701c8e0 --- /dev/null +++ b/c/misra/test/rules/RULE-5-4/conditional.h @@ -0,0 +1,11 @@ +#ifdef FOO +#include "header1.h" +#else +#include "header2.h" +#endif + +#ifdef FOO +#define A_MACRO 1 // COMPLIANT +#else +#define A_MACRO 2 // COMPLIANT +#endif \ No newline at end of file diff --git a/c/misra/test/rules/RULE-5-4/header1.h b/c/misra/test/rules/RULE-5-4/header1.h new file mode 100644 index 0000000000..526f4fa659 --- /dev/null +++ b/c/misra/test/rules/RULE-5-4/header1.h @@ -0,0 +1 @@ +#define REPEATED 11 // COMPLIANT \ No newline at end of file diff --git a/c/misra/test/rules/RULE-5-4/header2.h b/c/misra/test/rules/RULE-5-4/header2.h new file mode 100644 index 0000000000..bd5dde123d --- /dev/null +++ b/c/misra/test/rules/RULE-5-4/header2.h @@ -0,0 +1 @@ +#define REPEATED 1 // COMPLIANT \ No newline at end of file diff --git a/c/misra/test/rules/RULE-5-4/header3.h b/c/misra/test/rules/RULE-5-4/header3.h new file mode 100644 index 0000000000..3aa82f5fd7 --- /dev/null +++ b/c/misra/test/rules/RULE-5-4/header3.h @@ -0,0 +1,16 @@ +#ifndef HEADER3_H +#define HEADER3_H + +// We should ignore the header guards in this file + +// This is defined unconditionally by both header3.h and header4.h +#define MULTIPLE_INCLUDE // NON_COMPLIANT + +// This is redefined in header3.h, but only if it isn't already defined +#define PROTECTED // COMPLIANT + +// This is redefined in header3.h, but is conditional on some other condition, +// so this is redefined +#define NOT_PROTECTED // NON_COMPLIANT + +#endif \ No newline at end of file diff --git a/c/misra/test/rules/RULE-5-4/header4.h b/c/misra/test/rules/RULE-5-4/header4.h new file mode 100644 index 0000000000..8fa6e8b5e8 --- /dev/null +++ b/c/misra/test/rules/RULE-5-4/header4.h @@ -0,0 +1,13 @@ +#define MULTIPLE_INCLUDE // NON_COMPLIANT + +// This case is triggered from root2.c +// because PROTECTED isn't defined in +// that case +#ifndef PROTECTED +#define PROTECTED // COMPLIANT - checked by guard +#endif + +// Always enabled, so conflicts in root1.c case +#ifdef MULTIPLE_INCLUDE +#define NOT_PROTECTED 1 // NON_COMPLIANT +#endif diff --git a/c/misra/test/rules/RULE-5-4/root1.c b/c/misra/test/rules/RULE-5-4/root1.c new file mode 100644 index 0000000000..98a94abed5 --- /dev/null +++ b/c/misra/test/rules/RULE-5-4/root1.c @@ -0,0 +1,6 @@ +#define FOO 1 +#include "conditional.h" + +// Both headers define MULTIPLE_INCLUDE +#include "header3.h" +#include "header4.h" \ No newline at end of file diff --git a/c/misra/test/rules/RULE-5-4/root2.c b/c/misra/test/rules/RULE-5-4/root2.c new file mode 100644 index 0000000000..39926b9b1e --- /dev/null +++ b/c/misra/test/rules/RULE-5-4/root2.c @@ -0,0 +1,3 @@ +#include "conditional.h" + +#include "header4.h" \ No newline at end of file diff --git a/c/misra/test/rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.testref b/c/misra/test/rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.testref new file mode 100644 index 0000000000..9d02a25700 --- /dev/null +++ b/c/misra/test/rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.testref @@ -0,0 +1 @@ +c/common/test/rules/bitfieldshallhaveanappropriatetype/BitFieldShallHaveAnAppropriateType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-6-2/SingleBitNamedBitFieldsOfASignedType.expected b/c/misra/test/rules/RULE-6-2/SingleBitNamedBitFieldsOfASignedType.expected deleted file mode 100644 index df7677961a..0000000000 --- a/c/misra/test/rules/RULE-6-2/SingleBitNamedBitFieldsOfASignedType.expected +++ /dev/null @@ -1,4 +0,0 @@ -| test.c:4:7:4:8 | x1 | Single-bit bit-field named x1 has a signed type int. | -| test.c:7:14:7:15 | x2 | Single-bit bit-field named x2 has a signed type signed int. | -| test.c:9:7:9:8 | x3 | Single-bit bit-field named x3 has a signed type signed char. | -| test.c:11:7:11:8 | x4 | Single-bit bit-field named x4 has a signed type signed short. | diff --git a/c/misra/test/rules/RULE-6-2/SingleBitNamedBitFieldsOfASignedType.qlref b/c/misra/test/rules/RULE-6-2/SingleBitNamedBitFieldsOfASignedType.qlref deleted file mode 100644 index 50c34f70a7..0000000000 --- a/c/misra/test/rules/RULE-6-2/SingleBitNamedBitFieldsOfASignedType.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-6-2/SingleBitNamedBitFieldsOfASignedType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-6-2/SingleBitNamedBitFieldsOfASignedType.testref b/c/misra/test/rules/RULE-6-2/SingleBitNamedBitFieldsOfASignedType.testref new file mode 100644 index 0000000000..edc2f5a16d --- /dev/null +++ b/c/misra/test/rules/RULE-6-2/SingleBitNamedBitFieldsOfASignedType.testref @@ -0,0 +1 @@ +c/common/test/rules/namedbitfieldswithsignedintegertype/NamedBitFieldsWithSignedIntegerType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-6-2/test.c b/c/misra/test/rules/RULE-6-2/test.c deleted file mode 100644 index 8182dfdb5d..0000000000 --- a/c/misra/test/rules/RULE-6-2/test.c +++ /dev/null @@ -1,17 +0,0 @@ -#include - -struct SampleStruct { - int x1 : 1; // NON_COMPLIANT: very likely be signed, but if it's not, the - // query will automatically handle it since we use signed(), not - // isExplicitlySigned(). - signed int x2 : 1; // NON_COMPLIANT: single-bit named field with a signed type - signed char - x3 : 1; // NON_COMPLIANT: single-bit named field with a signed type - signed short - x4 : 1; // NON_COMPLIANT: single-bit named field with a signed type - unsigned int - x5 : 1; // COMPLIANT: single-bit named field but with an unsigned type - signed int x6 : 2; // COMPLIANT: named field with a signed type but declared - // to carry more than 1 bit - signed char : 1; // COMPLIANT: single-bit bit-field but unnamed -} sample_struct; diff --git a/c/misra/test/rules/RULE-6-3/BitFieldDeclaredAsMemberOfAUnion.expected b/c/misra/test/rules/RULE-6-3/BitFieldDeclaredAsMemberOfAUnion.expected new file mode 100644 index 0000000000..7c39484796 --- /dev/null +++ b/c/misra/test/rules/RULE-6-3/BitFieldDeclaredAsMemberOfAUnion.expected @@ -0,0 +1,2 @@ +| test.c:7:7:7:7 | x | Union member x is declared as a bit field which relies on implementation-specific behavior. | +| test.c:20:7:20:7 | (unnamed bitfield) | Union member (unnamed bitfield) is declared as a bit field which relies on implementation-specific behavior. | diff --git a/c/misra/test/rules/RULE-6-3/BitFieldDeclaredAsMemberOfAUnion.qlref b/c/misra/test/rules/RULE-6-3/BitFieldDeclaredAsMemberOfAUnion.qlref new file mode 100644 index 0000000000..21c43d4826 --- /dev/null +++ b/c/misra/test/rules/RULE-6-3/BitFieldDeclaredAsMemberOfAUnion.qlref @@ -0,0 +1 @@ +rules/RULE-6-3/BitFieldDeclaredAsMemberOfAUnion.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-6-3/test.c b/c/misra/test/rules/RULE-6-3/test.c new file mode 100644 index 0000000000..1de648d294 --- /dev/null +++ b/c/misra/test/rules/RULE-6-3/test.c @@ -0,0 +1,21 @@ +union U1 { + int x; // COMPLIANT + char y; // COMPLIANT +}; + +union U2 { + int x : 2; // NON-COMPLIANT + char y; // COMPLIANT +}; + +union U3 { + struct str { + int x : 4; // COMPLIANT + int y : 2; // COMPLIANT + }; +}; + +union U4 { + char x; + int : 0; // NON-COMPLIANT +}; \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-1/OctalConstantsUsed.expected b/c/misra/test/rules/RULE-7-1/OctalConstantsUsed.expected deleted file mode 100644 index deecdf994c..0000000000 --- a/c/misra/test/rules/RULE-7-1/OctalConstantsUsed.expected +++ /dev/null @@ -1,2 +0,0 @@ -| test.c:7:3:7:5 | 10 | Use of banned $@ constant. | test.c:7:3:7:5 | 10 | octal | -| test.c:8:3:8:5 | 44 | Use of banned $@ constant. | test.c:8:3:8:5 | 44 | octal | diff --git a/c/misra/test/rules/RULE-7-1/OctalConstantsUsed.qlref b/c/misra/test/rules/RULE-7-1/OctalConstantsUsed.qlref deleted file mode 100644 index 7d66675dad..0000000000 --- a/c/misra/test/rules/RULE-7-1/OctalConstantsUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-7-1/OctalConstantsUsed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-1/test.c b/c/misra/test/rules/RULE-7-1/test.c deleted file mode 100644 index fb0f2e0d36..0000000000 --- a/c/misra/test/rules/RULE-7-1/test.c +++ /dev/null @@ -1,10 +0,0 @@ -void test_non_zero_octal() { - '\0'; // COMPLIANT - octal zero escape sequence permitted - '\012'; // COMPLIANT - '\054'; // COMPLIANT - '\0149'; // COMPLIANT - 0; // COMPLIANT - octal literal zero permitted - 012; // NON_COMPLIANT - 054; // NON_COMPLIANT - "\0"; // COMPLIANT - octal zero escape sequence permitted -} diff --git a/c/misra/test/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.expected b/c/misra/test/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.expected index 4a131f4eaa..0d5504ba03 100644 --- a/c/misra/test/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.expected +++ b/c/misra/test/rules/RULE-7-2/UOrUSuffixRepresentedInUnsignedType.expected @@ -1,5 +1,12 @@ -| test.c:8:20:8:21 | 0 | Unsigned literal does not explicitly express sign with a 'U' or 'u' suffix. | -| test.c:9:20:9:22 | 0 | Unsigned literal does not explicitly express sign with a 'U' or 'u' suffix. | -| test.c:33:6:33:6 | 1 | Unsigned literal does not explicitly express sign with a 'U' or 'u' suffix. | -| test.c:35:6:35:9 | 1 | Unsigned literal does not explicitly express sign with a 'U' or 'u' suffix. | -| test.c:37:6:37:8 | 1 | Unsigned literal does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:111:3:111:12 | 2147483648 | Unsigned literal 0x80000000 does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:116:3:116:20 | 9223372036854775808 | Unsigned literal 0x8000000000000000 does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:139:3:139:21 | 9223372036854775808 | Unsigned literal 0x8000000000000000l does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:162:3:162:21 | 9223372036854775808 | Unsigned literal 0x8000000000000000L does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:185:3:185:22 | 9223372036854775808 | Unsigned literal 0x8000000000000000ll does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:208:3:208:22 | 9223372036854775808 | Unsigned literal 0x8000000000000000LL does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:227:3:227:14 | 2147483648 | Unsigned literal 020000000000 does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:232:3:232:25 | 9223372036854775808 | Unsigned literal 01000000000000000000000 does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:249:3:249:26 | 9223372036854775808 | Unsigned literal 01000000000000000000000l does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:266:3:266:26 | 9223372036854775808 | Unsigned literal 01000000000000000000000L does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:283:3:283:27 | 9223372036854775808 | Unsigned literal 01000000000000000000000ll does not explicitly express sign with a 'U' or 'u' suffix. | +| test.c:300:3:300:27 | 9223372036854775808 | Unsigned literal 01000000000000000000000LL does not explicitly express sign with a 'U' or 'u' suffix. | diff --git a/c/misra/test/rules/RULE-7-2/test.c b/c/misra/test/rules/RULE-7-2/test.c index da62825755..170e822023 100644 --- a/c/misra/test/rules/RULE-7-2/test.c +++ b/c/misra/test/rules/RULE-7-2/test.c @@ -1,39 +1,319 @@ +// Assumed platform in qltest is linux_x86_64, so +// int, long, long long sizes are assumed to be 32, 64, 64 bits respectively -long a1 = 0L; // COMPLIANT -long a2 = 0LL; // COMPLIANT -long a3 = 0uL; // COMPLIANT -long a4 = 0Lu; // COMPLIANT -long a5 = 0LU; // COMPLIANT - -unsigned long b1 = 0L; // NON_COMPLIANT -unsigned long b2 = 0LL; // NON_COMPLIANT -unsigned long b3 = 0uL; // COMPLIANT -unsigned long b4 = 0Lu; // COMPLIANT -unsigned long b5 = 0LU; // COMPLIANT - -signed long c1 = 0L; // COMPLIANT -signed long c2 = 0LL; // COMPLIANT -signed long c3 = 0uL; // COMPLIANT -signed long c4 = 0Lu; // COMPLIANT -signed long c5 = 0LU; // COMPLIANT - -void f0(int a) {} - -void f1(unsigned int a) {} - -void f2() { - - f0(1); // COMPLIANT - f0(1U); // COMPLIANT - f0(0x01); // COMPLIANT - f0(0x01U); // COMPLIANT - f0(001); // COMPLIANT - f0(001U); // COMPLIANT - - f1(1); // NON_COMPLIANT - f1(1U); // COMPLIANT - f1(0x01); // NON_COMPLIANT - f1(0x01U); // COMPLIANT - f1(001); // NON_COMPLIANT - f1(001U); // COMPLIANT +// The type of an integer constant is determined by "6.4.4.1 Integer constants" +// in the C11 Standard. The principle is that any decimal integer constant will +// be signed, unless it has the `U` or `u` suffix. Any hexadecimal integer will +// depend on whether it is larger than the maximum value of the smallest signed +// integer value that can hold the value. So the signedness depends on the +// magnitude of the constant. + +void test_decimal_constants() { + 0; // COMPLIANT + 2147483648; // COMPLIANT - larger than int, but decimal constants never use + // unsigned without the suffix, so will be `long` + 4294967296; // COMPLIANT - larger than unsigned int, still `long` + 9223372036854775807; // COMPLIANT - max long int + // 9223372036854775808; Not a valid integer constant, out of signed range + 0U; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648U; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296U; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807U; // COMPLIANT - max long int + 9223372036854775808U; // COMPLIANT - explicitly unsigned, so can go large than + // max long int + 0u; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648u; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296u; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807u; // COMPLIANT - max long int + 9223372036854775808u; // COMPLIANT - explicitly unsigned, so can go large than + // max long int + + // l suffix + 0l; // COMPLIANT + 2147483648l; // COMPLIANT - within the range of long int + 4294967296l; // COMPLIANT - within the range of long int + 9223372036854775807l; // COMPLIANT - max long int + // 9223372036854775808l; Not a valid integer constant, out of signed range + 0lU; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648lU; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296lU; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807lU; // COMPLIANT - max long int + 9223372036854775808lU; // COMPLIANT - explicitly unsigned, so can go large + // than max long int + 0lu; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648lu; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296lu; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807lu; // COMPLIANT - max long int + 9223372036854775808lu; // COMPLIANT - explicitly unsigned, so can go large + // than max long int + + // L suffix + 0L; // COMPLIANT + 2147483648L; // COMPLIANT - within the range of long int + 4294967296L; // COMPLIANT - within the range of long int + 9223372036854775807L; // COMPLIANT - max long int + // 9223372036854775808L; Not a valid integer constant, out of signed range + 0LU; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648LU; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296LU; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807LU; // COMPLIANT - max long int + 9223372036854775808LU; // COMPLIANT - explicitly unsigned, so can go large + // than max long int + 0Lu; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648Lu; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296Lu; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807Lu; // COMPLIANT - max long int + 9223372036854775808Lu; // COMPLIANT - explicitly unsigned, so can go large + // than max long int + + // ll suffix + 0ll; // COMPLIANT + 2147483648ll; // COMPLIANT - within the range of long long int + 4294967296ll; // COMPLIANT - within the range of long long int + 9223372036854775807ll; // COMPLIANT - max long long int + // 9223372036854775808ll; Not a valid integer constant, out of signed range + 0llU; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648llU; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296llU; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807llU; // COMPLIANT - max long long int + 9223372036854775808llU; // COMPLIANT - explicitly unsigned, so can go large + // than max long long int + 0llu; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648llu; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296llu; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807llu; // COMPLIANT - max long long int + 9223372036854775808llu; // COMPLIANT - explicitly unsigned, so can go large + // than max long long int + + // LL suffix + 0LL; // COMPLIANT + 2147483648LL; // COMPLIANT - within the range of long long int + 4294967296LL; // COMPLIANT - within the range of long long int + 9223372036854775807LL; // COMPLIANT - max long long int + // 9223372036854775808LL; Not a valid integer constant, out of signed range + 0LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807LLU; // COMPLIANT - max long long int + 9223372036854775808LLU; // COMPLIANT - explicitly unsigned, so can go large + // than max long long int + 0LLu; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648LLu; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296LLu; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807LLu; // COMPLIANT - max long long int + 9223372036854775808LLu; // COMPLIANT - explicitly unsigned, so can go large + // than max long long int } + +void test_hexadecimal_constants() { + 0x0; // COMPLIANT - uses signed int + 0x7FFFFFFF; // COMPLIANT - max value held by signed int + 0x80000000; // NON_COMPLIANT - larger than max signed int, so will be unsigned + // int + 0x100000000; // COMPLIANT - larger than unsigned int, but smaller than long + // int + 0x7FFFFFFFFFFFFFFF; // COMPLIANT - max long int + 0x8000000000000000; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 0x0U; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000U; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000U; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000U; // COMPLIANT - unsigned, but uses the suffix correctly + 0x0u; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000u; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000u; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000u; // COMPLIANT - unsigned, but uses the suffix correctly + + // Use of the `l` suffix + 0x0l; // COMPLIANT - uses signed int + 0x7FFFFFFFl; // COMPLIANT - max value held by signed int + 0x80000000l; // COMPLIANT - larger than max signed int, but smaller than long + // int + 0x100000000l; // COMPLIANT - larger than unsigned int, but smaller than long + // int + 0x7FFFFFFFFFFFFFFFl; // COMPLIANT - max long int + 0x8000000000000000l; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 0x0lU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFlU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000lU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000lU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFlU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000lU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x0lu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFlu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000lu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000lu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFlu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000lu; // COMPLIANT - unsigned, but uses the suffix correctly + + // Use of the `L` suffix + 0x0L; // COMPLIANT - uses signed int + 0x7FFFFFFFL; // COMPLIANT - max value held by signed int + 0x80000000L; // COMPLIANT - larger than max signed int, but smaller than long + // int + 0x100000000L; // COMPLIANT - larger than unsigned int, but smaller than long + // int + 0x7FFFFFFFFFFFFFFFL; // COMPLIANT - max long int + 0x8000000000000000L; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 0x0LU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000LU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000LU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000LU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x0Lu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000Lu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000Lu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000Lu; // COMPLIANT - unsigned, but uses the suffix correctly + + // Use of the `ll` suffix + 0x0ll; // COMPLIANT - uses signed int + 0x7FFFFFFFll; // COMPLIANT - max value held by signed int + 0x80000000ll; // COMPLIANT - larger than max signed int, but smaller than long + // long int + 0x100000000ll; // COMPLIANT - larger than unsigned int, but smaller than long + // long int + 0x7FFFFFFFFFFFFFFFll; // COMPLIANT - max long long int + 0x8000000000000000ll; // NON_COMPLIANT - larger than long long int, so will be + // unsigned long long int + 0x0llU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFllU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000llU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000llU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFllU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000llU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x0llu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFllu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000llu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000llu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFllu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000llu; // COMPLIANT - unsigned, but uses the suffix correctly + + // Use of the `LL` suffix + 0x0LL; // COMPLIANT - uses signed int + 0x7FFFFFFFLL; // COMPLIANT - max value held by signed int + 0x80000000LL; // COMPLIANT - larger than max signed int, but smaller than long + // long int + 0x100000000LL; // COMPLIANT - larger than unsigned int, but smaller than long + // long int + 0x7FFFFFFFFFFFFFFFLL; // COMPLIANT - max long long int + 0x8000000000000000LL; // NON_COMPLIANT - larger than long long int, so will be + // unsigned long long int + 0x0LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFLLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFLLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x0LLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFLLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000LLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000LLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFLLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000LLu; // COMPLIANT - unsigned, but uses the suffix correctly +} + +void test_octal_constants() { + 00; // COMPLIANT - uses signed int + 017777777777; // COMPLIANT - max value held by signed int + 020000000000; // NON_COMPLIANT - larger than max signed int, so will be + // unsigned int + 040000000000; // COMPLIANT - larger than unsigned int, but smaller than long + // int + 0777777777777777777777; // COMPLIANT - max long int + 01000000000000000000000; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00U; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777U; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000U; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000U; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777U; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000U; // COMPLIANT - unsigned, but uses the suffix + // correctly + + // Use of the `l` suffix + 00l; // COMPLIANT - uses signed long + 017777777777l; // COMPLIANT - uses signed long + 020000000000l; // COMPLIANT - uses signed long + 040000000000l; // COMPLIANT - uses signed long + 0777777777777777777777l; // COMPLIANT - max long int + 01000000000000000000000l; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00Ul; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777Ul; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000Ul; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000Ul; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777Ul; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000Ul; // COMPLIANT - unsigned, but uses the suffix + // correctly + + // Use of the `L` suffix + 00L; // COMPLIANT - uses signed long + 017777777777L; // COMPLIANT - uses signed long + 020000000000L; // COMPLIANT - uses signed long + 040000000000L; // COMPLIANT - uses signed long + 0777777777777777777777L; // COMPLIANT - COMPLIANT - uses signed long + 01000000000000000000000L; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00UL; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777UL; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000UL; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000UL; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777UL; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000UL; // COMPLIANT - unsigned, but uses the suffix + // correctly + + // Use of the `ll` suffix + 00ll; // COMPLIANT - uses signed long long + 017777777777ll; // COMPLIANT - uses signed long long + 020000000000ll; // COMPLIANT - uses signed long long + 040000000000ll; // COMPLIANT - uses signed long long + 0777777777777777777777ll; // COMPLIANT - max long int + 01000000000000000000000ll; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00Ull; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777Ull; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000Ull; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000Ull; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777Ull; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000Ull; // COMPLIANT - unsigned, but uses the suffix + // correctly + + // Use of the `LL` suffix + 00LL; // COMPLIANT - uses signed long long + 017777777777LL; // COMPLIANT - uses signed long long + 020000000000LL; // COMPLIANT - uses signed long long + 040000000000LL; // COMPLIANT - uses signed long long + 0777777777777777777777LL; // COMPLIANT - max long int + 01000000000000000000000LL; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00ULL; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777ULL; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000ULL; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000ULL; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777ULL; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000ULL; // COMPLIANT - unsigned, but uses the suffix + // correctly +} + +#define COMPLIANT_VAL 0x80000000U +#define NON_COMPLIANT_VAL 0x80000000 + +void test_macro() { + COMPLIANT_VAL; // COMPLIANT + NON_COMPLIANT_VAL; // NON_COMPLIANT[FALSE_NEGATIVE] - cannot determine suffix + // in macro expansions +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.expected b/c/misra/test/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.expected deleted file mode 100644 index 279fd7e621..0000000000 --- a/c/misra/test/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.expected +++ /dev/null @@ -1,16 +0,0 @@ -| test.c:3:10:3:11 | 0 | Lowercase 'l' used as a literal suffix. | -| test.c:4:10:4:12 | 0 | Lowercase 'l' used as a literal suffix. | -| test.c:7:10:7:12 | 0 | Lowercase 'l' used as a literal suffix. | -| test.c:8:10:8:12 | 0 | Lowercase 'l' used as a literal suffix. | -| test.c:13:11:13:12 | 0 | Lowercase 'l' used as a literal suffix. | -| test.c:14:11:14:13 | 0 | Lowercase 'l' used as a literal suffix. | -| test.c:17:11:17:13 | 0 | Lowercase 'l' used as a literal suffix. | -| test.c:18:11:18:13 | 0 | Lowercase 'l' used as a literal suffix. | -| test.c:23:10:23:14 | 1 | Lowercase 'l' used as a literal suffix. | -| test.c:24:10:24:15 | 1 | Lowercase 'l' used as a literal suffix. | -| test.c:27:10:27:15 | 1 | Lowercase 'l' used as a literal suffix. | -| test.c:28:10:28:15 | 1 | Lowercase 'l' used as a literal suffix. | -| test.c:33:11:33:14 | 1 | Lowercase 'l' used as a literal suffix. | -| test.c:34:11:34:15 | 1 | Lowercase 'l' used as a literal suffix. | -| test.c:37:11:37:15 | 1 | Lowercase 'l' used as a literal suffix. | -| test.c:38:11:38:15 | 1 | Lowercase 'l' used as a literal suffix. | diff --git a/c/misra/test/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.qlref b/c/misra/test/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.qlref deleted file mode 100644 index 464efc3b2f..0000000000 --- a/c/misra/test/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.testref b/c/misra/test/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.testref new file mode 100644 index 0000000000..1fc7164d80 --- /dev/null +++ b/c/misra/test/rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.testref @@ -0,0 +1 @@ +c/common/test/rules/lowercaselstartsinliteralsuffix/LowercaseLStartsInLiteralSuffix.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-3/cpp/LowercaseCharacterLUsedInLiteralSuffix.qlref b/c/misra/test/rules/RULE-7-3/cpp/LowercaseCharacterLUsedInLiteralSuffix.qlref deleted file mode 100644 index 464efc3b2f..0000000000 --- a/c/misra/test/rules/RULE-7-3/cpp/LowercaseCharacterLUsedInLiteralSuffix.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-7-3/LowercaseCharacterLUsedInLiteralSuffix.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-3/cpp/options b/c/misra/test/rules/RULE-7-3/cpp/options deleted file mode 100644 index 8dbed822c6..0000000000 --- a/c/misra/test/rules/RULE-7-3/cpp/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options:--clang -std=c++14 --edg --diag_error=implicit_func_decl -nostdinc -I../../../../../cpp/common/test/includes/standard-library \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-3/cpp/test.cpp b/c/misra/test/rules/RULE-7-3/cpp/test.cpp deleted file mode 100644 index ba3ca4f14e..0000000000 --- a/c/misra/test/rules/RULE-7-3/cpp/test.cpp +++ /dev/null @@ -1 +0,0 @@ -int x = false; // COMPLIANT - reported as FP in #319 \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-3/test.c b/c/misra/test/rules/RULE-7-3/test.c deleted file mode 100644 index 5e1c448926..0000000000 --- a/c/misra/test/rules/RULE-7-3/test.c +++ /dev/null @@ -1,44 +0,0 @@ - -int a1 = 0L; // COMPLIANT -int a2 = 0l; // NON_COMPLIANT -int a3 = 0ll; // NON_COMPLIANT -int a4 = 0LL; // COMPLIANT -int a5 = 0uL; // COMPLIANT -int a6 = 0ul; // NON_COMPLIANT -int a7 = 0lu; // NON_COMPLIANT -int a8 = 0Lu; // COMPLIANT -int a9 = 0LU; // COMPLIANT - -long b1 = 0L; // COMPLIANT -long b2 = 0l; // NON_COMPLIANT -long b3 = 0ll; // NON_COMPLIANT -long b4 = 0LL; // COMPLIANT -long b5 = 0uL; // COMPLIANT -long b6 = 0ul; // NON_COMPLIANT -long b7 = 0lu; // NON_COMPLIANT -long b8 = 0Lu; // COMPLIANT -long b9 = 0LU; // COMPLIANT - -int c1 = 0x01L; // COMPLIANT -int c2 = 0x01l; // NON_COMPLIANT -int c3 = 0x01ll; // NON_COMPLIANT -int c4 = 0x01LL; // COMPLIANT -int c5 = 0x01uL; // COMPLIANT -int c6 = 0x01ul; // NON_COMPLIANT -int c7 = 0x01lu; // NON_COMPLIANT -int c8 = 0x01Lu; // COMPLIANT -int c9 = 0x01LU; // COMPLIANT - -long d1 = 001L; // COMPLIANT -long d2 = 001l; // NON_COMPLIANT -long d3 = 001ll; // NON_COMPLIANT -long d4 = 001LL; // COMPLIANT -long d5 = 001uL; // COMPLIANT -long d6 = 001ul; // NON_COMPLIANT -long d7 = 001lu; // NON_COMPLIANT -long d8 = 001Lu; // COMPLIANT -long d9 = 001LU; // COMPLIANT - -char *e1 = ""; -char *e2 = "ul"; -char *e3 = "UL"; \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-4/StringLiteralAssignedToNonConstChar.expected b/c/misra/test/rules/RULE-7-4/StringLiteralAssignedToNonConstChar.expected index 46b8e5a47b..208e98f632 100644 --- a/c/misra/test/rules/RULE-7-4/StringLiteralAssignedToNonConstChar.expected +++ b/c/misra/test/rules/RULE-7-4/StringLiteralAssignedToNonConstChar.expected @@ -6,3 +6,4 @@ | test.c:58:5:58:22 | return ... | wchar_t * function w_sample3 is returning a string literal. | | test.c:69:3:69:9 | call to sample4 | char * parameter of sample4 is passed a string literal. | | test.c:78:3:78:11 | call to w_sample4 | wchar_t * parameter of w_sample4 is passed a string literal. | +| test.c:91:3:91:11 | call to w_sample7 | char * parameter of w_sample7 is passed a string literal. | diff --git a/c/misra/test/rules/RULE-7-4/test.c b/c/misra/test/rules/RULE-7-4/test.c index c178915200..ab7ea21ce9 100644 --- a/c/misra/test/rules/RULE-7-4/test.c +++ b/c/misra/test/rules/RULE-7-4/test.c @@ -79,4 +79,16 @@ void w_call45() { w_sample5(L"string9"); // COMPLIANT: passing string literal to const char* } +void w_sample6(int x, ...) {} + +void w_call6() { + w_sample6(1, "string10"); // COMPLIANT by first (and only) exception +} + +void w_sample7(char *x, ...) {} + +void w_call7() { + w_sample7("string11", 1); // NON_COMPLIANT, does not fit exceptional case +} + int main() { return 0; } diff --git a/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.expected b/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.expected new file mode 100644 index 0000000000..d3724e21a4 --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.expected @@ -0,0 +1,31 @@ +| test.c:17:13:17:16 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:19:13:19:18 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:21:13:21:16 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:37:13:37:15 | 256 | Value provided to integer constant macro UINT8_C is outside of the allowed range 0..255 | +| test.c:38:13:38:16 | 256 | Value provided to integer constant macro UINT8_C is outside of the allowed range 0..255 | +| test.c:39:13:39:17 | 256 | Value provided to integer constant macro UINT8_C is outside of the allowed range 0..255 | +| test.c:42:13:42:14 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:43:13:43:15 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:44:13:44:15 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:45:13:45:17 | - ... | Value provided to integer constant macro UINT8_C cannot be negative | +| test.c:70:12:70:14 | 128 | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | +| test.c:71:12:71:15 | 128 | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | +| test.c:72:12:72:15 | 128 | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | +| test.c:76:12:76:15 | - ... | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | +| test.c:77:12:77:16 | - ... | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | +| test.c:78:12:78:16 | - ... | Value provided to integer constant macro INT8_C is outside of the allowed range -128..127 | +| test.c:91:14:91:18 | 65536 | Value provided to integer constant macro UINT16_C is outside of the allowed range 0..65535 | +| test.c:92:14:92:20 | 65536 | Value provided to integer constant macro UINT16_C is outside of the allowed range 0..65535 | +| test.c:93:14:93:20 | 65536 | Value provided to integer constant macro UINT16_C is outside of the allowed range 0..65535 | +| test.c:106:13:106:17 | 32768 | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | +| test.c:107:13:107:19 | 32768 | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | +| test.c:108:13:108:18 | 32768 | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | +| test.c:112:13:112:18 | - ... | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | +| test.c:113:13:113:20 | - ... | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | +| test.c:114:13:114:19 | - ... | Value provided to integer constant macro INT16_C is outside of the allowed range -32768..32767 | +| test.c:124:14:124:24 | 4294967296 | Value provided to integer constant macro UINT32_C is outside of the allowed range 0..4294967295 | +| test.c:125:14:125:25 | 4294967296 | Value provided to integer constant macro UINT32_C is outside of the allowed range 0..4294967295 | +| test.c:135:13:135:22 | 2147483648 | Value provided to integer constant macro INT32_C is outside of the allowed range -2147483648..2147483647 | +| test.c:136:13:136:22 | 2147483648 | Value provided to integer constant macro INT32_C is outside of the allowed range -2147483648..2147483647 | +| test.c:139:13:139:23 | - ... | Value provided to integer constant macro INT32_C is outside of the allowed range -2147483648..2147483647 | +| test.c:140:13:140:23 | - ... | Value provided to integer constant macro INT32_C is outside of the allowed range -2147483648..2147483647 | diff --git a/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.qlref b/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.qlref new file mode 100644 index 0000000000..ca6959acec --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.qlref @@ -0,0 +1 @@ +rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.expected b/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.expected new file mode 100644 index 0000000000..97a35dd977 --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.expected @@ -0,0 +1,7 @@ +| test.c:25:13:25:14 | 1 | Value suffix 'u' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:26:13:26:14 | 2 | Value suffix 'U' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:27:13:27:14 | 3 | Value suffix 'l' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:28:13:28:14 | 4 | Value suffix 'L' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:29:13:29:15 | 5 | Value suffix 'ul' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:30:13:30:15 | 5 | Value suffix 'll' is not allowed on provided argument to integer constant macro UINT8_C. | +| test.c:31:13:31:16 | 5 | Value suffix 'ull' is not allowed on provided argument to integer constant macro UINT8_C. | diff --git a/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.qlref b/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.qlref new file mode 100644 index 0000000000..afadb6e34b --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.qlref @@ -0,0 +1 @@ +rules/RULE-7-5/IntegerConstantMacroArgumentUsesSuffix.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected b/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected new file mode 100644 index 0000000000..b29228b6df --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.expected @@ -0,0 +1,8 @@ +| test.c:48:13:48:17 | ... + ... | Argument to integer constant macro UINT8_C must be an integer literal. | +| test.c:49:13:49:18 | access to array | Argument to integer constant macro UINT8_C must be an integer literal. | +| test.c:50:13:50:19 | access to array | Argument to integer constant macro UINT8_C must be an integer literal. | +| test.c:51:5:51:22 | 255 | Argument to integer constant macro UINT8_C must be an integer literal. | +| test.c:52:5:52:17 | 1 | Argument to integer constant macro UINT8_C must be an integer literal. | +| test.c:53:5:53:18 | 0 | Argument to integer constant macro UINT8_C must be an integer literal. | +| test.c:54:5:54:17 | 0 | Argument to integer constant macro UINT8_C must be an integer literal. | +| test.c:55:5:55:20 | 0 | Argument to integer constant macro UINT8_C must be an integer literal. | diff --git a/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.qlref b/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.qlref new file mode 100644 index 0000000000..802f415bc9 --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/InvalidIntegerConstantMacroArgument.qlref @@ -0,0 +1 @@ +rules/RULE-7-5/InvalidIntegerConstantMacroArgument.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.expected b/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.expected new file mode 100644 index 0000000000..ee5b75cb91 --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.expected @@ -0,0 +1,7 @@ +| test.c:16:13:16:15 | 1.0 | Integer constant macro UINT8_C used with floating point literal argument, only decimal, octal, or hex integer literal allowed. | +| test.c:17:13:17:16 | - ... | Integer constant macro UINT8_C used with floating point literal argument, only decimal, octal, or hex integer literal allowed. | +| test.c:18:13:18:17 | 7 | Integer constant macro UINT8_C used with binary literal argument, only decimal, octal, or hex integer literal allowed. | +| test.c:19:13:19:18 | - ... | Integer constant macro UINT8_C used with binary literal argument, only decimal, octal, or hex integer literal allowed. | +| test.c:20:13:20:15 | 97 | Integer constant macro UINT8_C used with char literal argument, only decimal, octal, or hex integer literal allowed. | +| test.c:21:13:21:16 | - ... | Integer constant macro UINT8_C used with char literal argument, only decimal, octal, or hex integer literal allowed. | +| test.c:22:13:22:16 | 10 | Integer constant macro UINT8_C used with char literal argument, only decimal, octal, or hex integer literal allowed. | diff --git a/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.qlref b/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.qlref new file mode 100644 index 0000000000..5584fe8d46 --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.qlref @@ -0,0 +1 @@ +rules/RULE-7-5/InvalidLiteralForIntegerConstantMacroArgument.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-5/test.c b/c/misra/test/rules/RULE-7-5/test.c new file mode 100644 index 0000000000..a3fb4b60e4 --- /dev/null +++ b/c/misra/test/rules/RULE-7-5/test.c @@ -0,0 +1,179 @@ +#include "stdbool.h" +#include "stdint.h" + +#define NULL 0 +#define NULLPTR ((void *)NULL) + +uint_least8_t g1[] = { + // Basic valid + UINT8_C(0), // COMPLIANT + UINT8_C(1), // COMPLIANT + UINT8_C(8), // COMPLIANT + UINT8_C(0x23), // COMPLIANT + UINT8_C(034), // COMPLIANT + + // Incorrect literal types + UINT8_C(1.0), // NON-COMPLIANT + UINT8_C(-1.0), // NON-COMPLIANT + UINT8_C(0b111), // NON-COMPLIANT + UINT8_C(-0b111), // NON-COMPLIANT + UINT8_C('a'), // NON-COMPLIANT + UINT8_C(-'$'), // NON-COMPLIANT + UINT8_C('\n'), // NON-COMPLIANT + + // Suffixes disallowed + UINT8_C(1u), // NON-COMPLIANT + UINT8_C(2U), // NON-COMPLIANT + UINT8_C(3l), // NON-COMPLIANT + UINT8_C(4L), // NON-COMPLIANT + UINT8_C(5ul), // NON-COMPLIANT + UINT8_C(5ll), // NON-COMPLIANT + UINT8_C(5ull), // NON-COMPLIANT + + // Range tests + UINT8_C(255), // COMPLIANT + UINT8_C(0xFF), // COMPLIANT + UINT8_C(0377), // COMPLIANT + UINT8_C(256), // NON-COMPLIANT + UINT8_C(0400), // NON-COMPLIANT + UINT8_C(0x100), // NON-COMPLIANT + + // Signage tests + UINT8_C(-1), // NON-COMPLIANT + UINT8_C(-20), // NON-COMPLIANT + UINT8_C(-33), // NON-COMPLIANT + UINT8_C(-0x44), // NON-COMPLIANT + + // Invalid nonliteral expressions + UINT8_C(0 + 0), // NON-COMPLIANT + UINT8_C("a"[0]), // NON-COMPLIANT + UINT8_C(0 ["a"]), // NON-COMPLIANT + UINT8_C(UINT8_MAX), // NON-COMPLIANT + UINT8_C(true), // NON-COMPLIANT + UINT8_C(false), // NON-COMPLIANT + UINT8_C(NULL), // NON-COMPLIANT + UINT8_C(NULLPTR), // NON-COMPLIANT +}; + +int_least8_t g2[] = { + // Basic valid + INT8_C(0), // COMPLIANT + INT8_C(1), // COMPLIANT + INT8_C(8), // COMPLIANT + INT8_C(0x23), // COMPLIANT + INT8_C(034), // COMPLIANT + + // Range tests + INT8_C(127), // COMPLIANT + INT8_C(0x79), // COMPLIANT + INT8_C(0177), // COMPLIANT + INT8_C(128), // NON-COMPLIANT + INT8_C(0200), // NON-COMPLIANT + INT8_C(0x80), // NON-COMPLIANT + INT8_C(-128), // COMPLIANT + INT8_C(-0x80), // COMPLIANT + INT8_C(-0200), // COMPLIANT + INT8_C(-129), // NON-COMPLIANT + INT8_C(-0201), // NON-COMPLIANT + INT8_C(-0x81), // NON-COMPLIANT +}; + +uint_least16_t g3[] = { + // Basic valid + UINT16_C(0), // COMPLIANT + UINT16_C(0x23), // COMPLIANT + UINT16_C(034), // COMPLIANT + + // Range tests + UINT16_C(65535), // COMPLIANT + UINT16_C(0xFFFF), // COMPLIANT + UINT16_C(0177777), // COMPLIANT + UINT16_C(65536), // NON-COMPLIANT + UINT16_C(0200000), // NON-COMPLIANT + UINT16_C(0x10000), // NON-COMPLIANT +}; + +int_least16_t g4[] = { + // Basic valid + INT16_C(0), // COMPLIANT + INT16_C(0x23), // COMPLIANT + INT16_C(034), // COMPLIANT + + // Range tests + INT16_C(32767), // COMPLIANT + INT16_C(0x7FFF), // COMPLIANT + INT16_C(077777), // COMPLIANT + INT16_C(32768), // NON-COMPLIANT + INT16_C(0100000), // NON-COMPLIANT + INT16_C(0x8000), // NON-COMPLIANT + INT16_C(-32768), // COMPLIANT + INT16_C(-0100000), // COMPLIANT + INT16_C(-0x8000), // COMPLIANT + INT16_C(-32769), // NON-COMPLIANT + INT16_C(-0100001), // NON-COMPLIANT + INT16_C(-0x8001), // NON-COMPLIANT +}; + +uint_least32_t g5[] = { + // Basic valid + UINT32_C(0), // COMPLIANT + + // Range tests + UINT32_C(4294967295), // COMPLIANT + UINT32_C(0xFFFFFFFF), // COMPLIANT + UINT32_C(4294967296), // NON-COMPLIANT + UINT32_C(0x100000000), // NON-COMPLIANT +}; + +int_least32_t g6[] = { + // Basic valid + INT32_C(0), // COMPLIANT + + // Range tests + INT32_C(2147483647), // COMPLIANT + INT32_C(0x7FFFFFFF), // COMPLIANT + INT32_C(2147483648), // NON-COMPLIANT + INT32_C(0x80000000), // NON-COMPLIANT + INT32_C(-2147483648), // COMPLIANT + INT32_C(-0x80000000), // COMPLIANT + INT32_C(-2147483649), // NON-COMPLIANT + INT32_C(-0x80000001), // NON-COMPLIANT +}; + +uint_least64_t g7[] = { + // Basic valid + UINT64_C(0), // COMPLIANT + + // Range tests + UINT64_C(18446744073709551615), // COMPLIANT + UINT64_C(0xFFFFFFFFFFFFFFFF), // COMPLIANT + // Compile time error if we try to create integer literals beyond this. +}; + +int_least64_t g8[] = { + // Basic valid + INT64_C(0), // COMPLIANT + + // Range tests + INT64_C(9223372036854775807), // COMPLIANT + // INT64_C(9223372036854775808) is a compile-time error + + INT64_C(-9223372036854775807), // COMPLIANT + // -9223372036854775808 is correctly sized, but not a valid decimal literal + // value. + // -9223372036854775809 is not correctly sized, and not a valid decimal + // literal value. + + INT64_C(0x7FFFFFFFFFFFFFFF), // COMPLIANT + INT64_C(0x8000000000000000), // NON-COMPLIANT[FALSE NEGATIVE] + INT64_C(-0x8000000000000000), // COMPLIANT + INT64_C(-0x8000000000000001), // NON-COMPLIANT[FALSE NEGATIVE] + INT64_C(-0x8001000000000000), // NON-COMPLIANT[FALSE NEGATIVE] +}; + +// Other edge cases: +void f(void) { + uint32_t l1 = 1; + // `UnrecognizedNumericLiteral` case: + int64_t l2 = ((int32_t)UINT64_C(0x1b2) * (l1)); // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.expected b/c/misra/test/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.expected new file mode 100644 index 0000000000..ddf517ed9e --- /dev/null +++ b/c/misra/test/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.expected @@ -0,0 +1,4 @@ +| test.c:3:13:3:24 | INT8_C(c) | Usage of small integer constant macro INT8_C is not allowed. | +| test.c:4:14:4:26 | UINT8_C(c) | Usage of small integer constant macro UINT8_C is not allowed. | +| test.c:5:14:5:28 | INT16_C(c) | Usage of small integer constant macro INT16_C is not allowed. | +| test.c:6:15:6:30 | UINT16_C(c) | Usage of small integer constant macro UINT16_C is not allowed. | diff --git a/c/misra/test/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.qlref b/c/misra/test/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.qlref new file mode 100644 index 0000000000..e41e2912d8 --- /dev/null +++ b/c/misra/test/rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.qlref @@ -0,0 +1 @@ +rules/RULE-7-6/UseOfBannedSmallIntegerConstantMacro.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-6/test.c b/c/misra/test/rules/RULE-7-6/test.c new file mode 100644 index 0000000000..9832cdf251 --- /dev/null +++ b/c/misra/test/rules/RULE-7-6/test.c @@ -0,0 +1,10 @@ +#include "stdint.h" + +int8_t g1 = INT8_C(0x12); // NON-COMPLIANT +uint8_t g2 = UINT8_C(0x12); // NON-COMPLIANT +int16_t g3 = INT16_C(0x1234); // NON-COMPLIANT +uint16_t g4 = UINT16_C(0x1234); // NON-COMPLIANT +int32_t g5 = INT32_C(0x1234); // COMPLIANT +uint32_t g6 = UINT32_C(0x1234); // COMPLIANT +int64_t g7 = INT64_C(0x1234); // COMPLIANT +uint64_t g8 = UINT64_C(0x1234); // COMPLIANT \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-12/ValueImplicitEnumerationConstantNotUnique.expected b/c/misra/test/rules/RULE-8-12/ValueImplicitEnumerationConstantNotUnique.expected deleted file mode 100644 index 55abb72b57..0000000000 --- a/c/misra/test/rules/RULE-8-12/ValueImplicitEnumerationConstantNotUnique.expected +++ /dev/null @@ -1 +0,0 @@ -| test.c:3:19:3:20 | c4 | Nonunique value of enum constant compared to $@ | test.c:3:23:3:24 | c5 | c5 | diff --git a/c/misra/test/rules/RULE-8-12/ValueImplicitEnumerationConstantNotUnique.qlref b/c/misra/test/rules/RULE-8-12/ValueImplicitEnumerationConstantNotUnique.qlref deleted file mode 100644 index e43c765d37..0000000000 --- a/c/misra/test/rules/RULE-8-12/ValueImplicitEnumerationConstantNotUnique.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-8-12/ValueImplicitEnumerationConstantNotUnique.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-12/ValueImplicitEnumerationConstantNotUnique.testref b/c/misra/test/rules/RULE-8-12/ValueImplicitEnumerationConstantNotUnique.testref new file mode 100644 index 0000000000..7db7d79d72 --- /dev/null +++ b/c/misra/test/rules/RULE-8-12/ValueImplicitEnumerationConstantNotUnique.testref @@ -0,0 +1 @@ +c/common/test/rules/nonuniqueenumerationconstant/NonUniqueEnumerationConstant.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-12/test.c b/c/misra/test/rules/RULE-8-12/test.c deleted file mode 100644 index 349bb7867c..0000000000 --- a/c/misra/test/rules/RULE-8-12/test.c +++ /dev/null @@ -1,4 +0,0 @@ -enum e { c = 3 }; // COMPLIANT -enum e1 { c1 = 3, c2 }; // COMPLIANT -enum e3 { c3 = 3, c4, c5 = 4 }; // NON_COMPLIANT -enum e4 { c6 = 3, c7, c8, c9 = 6 }; // COMPLIANT \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.expected b/c/misra/test/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.expected index 39dbf04763..e3e0963087 100644 --- a/c/misra/test/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.expected +++ b/c/misra/test/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.expected @@ -12,3 +12,4 @@ | test.c:66:23:66:24 | p1 | $@ points to a non-const-qualified type. | test.c:66:23:66:24 | p1 | p1 | | test.c:71:17:71:18 | p1 | $@ points to a non-const-qualified type. | test.c:71:17:71:18 | p1 | p1 | | test.c:75:15:75:16 | p1 | $@ points to a non-const-qualified type. | test.c:75:15:75:16 | p1 | p1 | +| test.c:103:30:103:30 | s | $@ points to a non-const-qualified type. | test.c:103:30:103:30 | s | s | diff --git a/c/misra/test/rules/RULE-8-13/test.c b/c/misra/test/rules/RULE-8-13/test.c index 1ac9e5028c..a2333d2a3d 100644 --- a/c/misra/test/rules/RULE-8-13/test.c +++ b/c/misra/test/rules/RULE-8-13/test.c @@ -75,4 +75,38 @@ char *f16(char *p1) { // NON_COMPLIANT int f17(char *p1) { // NON_COMPLIANT p1++; return 0; +} + +#include + +int16_t +test_r(int16_t *value) { // COMPLIANT - ignored because of the use of ASM + int16_t result; + struct S { + int *x; // COMPLIANT - ignored because of the use of ASM + struct S2 { + int *y; // COMPLIANT - ignored because of the use of ASM + } s2; + }; + __asm__("movb %bh (%eax)"); + return result; +} + +struct S { + int x; +}; + +void test_struct(struct S *s) { // COMPLIANT + s->x = 1; +} + +void test_struct_2(struct S *s) { // NON_COMPLIANT - could be const + s = 0; +} + +void test_no_body(int *p); // COMPLIANT - no body, so cannot evaluate whether it + // should be const + +void increment(int *p) { // COMPLIANT + *p++ = 1; } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected new file mode 100644 index 0000000000..3479ef1e35 --- /dev/null +++ b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected @@ -0,0 +1,8 @@ +| test.c:18:8:18:15 | alignas(...) | Variable g6 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:18:8:18:15 | alignas(...) | int | test.c:19:8:19:15 | alignas(...) | 4 | +| test.c:19:8:19:15 | alignas(...) | Variable g6 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:19:8:19:15 | alignas(...) | 4 | test.c:18:8:18:15 | alignas(...) | int | +| test.c:22:8:22:15 | alignas(...) | Variable g7 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:22:8:22:15 | alignas(...) | ... * ... | test.c:23:8:23:15 | alignas(...) | 32 | +| test.c:23:8:23:15 | alignas(...) | Variable g7 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:23:8:23:15 | alignas(...) | 32 | test.c:22:8:22:15 | alignas(...) | ... * ... | +| test.c:28:8:28:15 | alignas(...) | Variable g9 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:28:8:28:15 | alignas(...) | ... * ... | test.c:29:8:29:15 | alignas(...) | ... * ... | +| test.c:29:8:29:15 | alignas(...) | Variable g9 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:29:8:29:15 | alignas(...) | ... * ... | test.c:28:8:28:15 | alignas(...) | ... * ... | +| test.c:34:8:34:15 | alignas(...) | Variable g11 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:34:8:34:15 | alignas(...) | signed int | test.c:35:8:35:15 | alignas(...) | unsigned int | +| test.c:35:8:35:15 | alignas(...) | Variable g11 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:35:8:35:15 | alignas(...) | unsigned int | test.c:34:8:34:15 | alignas(...) | signed int | diff --git a/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected.gcc b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected.gcc new file mode 100644 index 0000000000..6f3d414214 --- /dev/null +++ b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected.gcc @@ -0,0 +1,10 @@ +| test.c:11:8:11:15 | alignas(...) | Variable g4 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:11:8:11:15 | alignas(...) | 16 | test.c:12:8:12:15 | alignas(...) | 32 | +| test.c:12:8:12:15 | alignas(...) | Variable g4 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:12:8:12:15 | alignas(...) | 32 | test.c:11:8:11:15 | alignas(...) | 16 | +| test.c:18:8:18:15 | alignas(...) | Variable g6 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:18:8:18:15 | alignas(...) | int | test.c:19:8:19:15 | alignas(...) | 4 | +| test.c:19:8:19:15 | alignas(...) | Variable g6 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:19:8:19:15 | alignas(...) | 4 | test.c:18:8:18:15 | alignas(...) | int | +| test.c:22:8:22:15 | alignas(...) | Variable g7 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:22:8:22:15 | alignas(...) | ... * ... | test.c:23:8:23:15 | alignas(...) | 32 | +| test.c:23:8:23:15 | alignas(...) | Variable g7 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:23:8:23:15 | alignas(...) | 32 | test.c:22:8:22:15 | alignas(...) | ... * ... | +| test.c:28:8:28:15 | alignas(...) | Variable g9 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:28:8:28:15 | alignas(...) | ... * ... | test.c:29:8:29:15 | alignas(...) | ... * ... | +| test.c:29:8:29:15 | alignas(...) | Variable g9 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:29:8:29:15 | alignas(...) | ... * ... | test.c:28:8:28:15 | alignas(...) | ... * ... | +| test.c:34:8:34:15 | alignas(...) | Variable g11 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:34:8:34:15 | alignas(...) | signed int | test.c:35:8:35:15 | alignas(...) | unsigned int | +| test.c:35:8:35:15 | alignas(...) | Variable g11 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:35:8:35:15 | alignas(...) | unsigned int | test.c:34:8:34:15 | alignas(...) | signed int | diff --git a/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.qlref b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.qlref new file mode 100644 index 0000000000..08648fd168 --- /dev/null +++ b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.qlref @@ -0,0 +1 @@ +rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.expected b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.expected new file mode 100644 index 0000000000..69d2c8bb2d --- /dev/null +++ b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.expected @@ -0,0 +1,2 @@ +| test.c:5:12:5:13 | declaration of g2 | Variable g2 declared without explicit alignment to match $@ with alignment $@. | test.c:4:25:4:26 | declaration of g2 | other definition | test.c:4:8:4:15 | alignas(...) | alignas(...) | +| test.c:7:12:7:13 | declaration of g3 | Variable g3 declared without explicit alignment to match $@ with alignment $@. | test.c:8:25:8:26 | declaration of g3 | other definition | test.c:8:8:8:15 | alignas(...) | alignas(...) | diff --git a/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.qlref b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.qlref new file mode 100644 index 0000000000..f5f13e2125 --- /dev/null +++ b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.qlref @@ -0,0 +1 @@ +rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-15/test.c b/c/misra/test/rules/RULE-8-15/test.c new file mode 100644 index 0000000000..f97a79d5b6 --- /dev/null +++ b/c/misra/test/rules/RULE-8-15/test.c @@ -0,0 +1,35 @@ +extern _Alignas(16) int g1; // COMPLIANT +extern _Alignas(16) int g1; // COMPLIANT + +extern _Alignas(16) int g2; +extern int g2; // NON_COMPLIANT + +extern int g3; // NON_COMPLIANT +extern _Alignas(16) int g3; + +// Does not compile on clang: +// extern _Alignas(16) int g4; // COMPLIANT +// extern _Alignas(32) int g4; // COMPLIANT + +extern int g5; // COMPLIANT +extern int g5; // COMPLIANT + +// Spec says elements must be lexically identical after macro expansion +extern _Alignas(int) int g6; // NON_COMPLIANT +extern _Alignas(4) int g6; // NON_COMPLIANT + +#define THIRTY_TWO 32 +extern _Alignas(16 * 2) int g7; // NON_COMPLIANT +extern _Alignas(32) int g7; // NON_COMPLIANT + +extern _Alignas(THIRTY_TWO) int g8; // COMPLIANT +extern _Alignas(32) int g8; // COMPLIANT + +extern _Alignas(16 * 2) int g9; // NON_COMPLIANT +extern _Alignas(2 * 16) int g9; // NON_COMPLIANT + +extern _Alignas(int) int g10; // COMPLIANT +extern _Alignas(int) int g10; // COMPLIANT + +extern _Alignas(signed int) int g11; // NON_COMPLIANT +extern _Alignas(unsigned int) int g11; // NON_COMPLIANT \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-15/test.c.gcc b/c/misra/test/rules/RULE-8-15/test.c.gcc new file mode 100644 index 0000000000..d0f53bf89a --- /dev/null +++ b/c/misra/test/rules/RULE-8-15/test.c.gcc @@ -0,0 +1,35 @@ +extern _Alignas(16) int g1; // COMPLIANT +extern _Alignas(16) int g1; // COMPLIANT + +extern _Alignas(16) int g2; +extern int g2; // NON_COMPLIANT + +extern int g3; // NON_COMPLIANT +extern _Alignas(16) int g3; + +// Does not compile on clang: +extern _Alignas(16) int g4; // COMPLIANT +extern _Alignas(32) int g4; // COMPLIANT + +extern int g5; // COMPLIANT +extern int g5; // COMPLIANT + +// Spec says elements must be lexically identical after macro expansion +extern _Alignas(int) int g6; // NON_COMPLIANT +extern _Alignas(4) int g6; // NON_COMPLIANT + +#define THIRTY_TWO 32 +extern _Alignas(16 * 2) int g7; // NON_COMPLIANT +extern _Alignas(32) int g7; // NON_COMPLIANT + +extern _Alignas(THIRTY_TWO) int g8; // COMPLIANT +extern _Alignas(32) int g8; // COMPLIANT + +extern _Alignas(16 * 2) int g9; // NON_COMPLIANT +extern _Alignas(2 * 16) int g9; // NON_COMPLIANT + +extern _Alignas(int) int g10; // COMPLIANT +extern _Alignas(int) int g10; // COMPLIANT + +extern _Alignas(signed int) int g11; // NON_COMPLIANT +extern _Alignas(unsigned int) int g11; // NON_COMPLIANT \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-16/AlignmentWithSizeZero.expected b/c/misra/test/rules/RULE-8-16/AlignmentWithSizeZero.expected new file mode 100644 index 0000000000..4daa3475ed --- /dev/null +++ b/c/misra/test/rules/RULE-8-16/AlignmentWithSizeZero.expected @@ -0,0 +1,4 @@ +| test.c:2:10:2:10 | 0 | Invalid alignof() size set to zero for variable $@. | test.c:2:17:2:18 | g2 | g2 | +| test.c:3:10:3:14 | ... - ... | Invalid alignof() size set to zero for variable $@. | test.c:3:21:3:22 | g3 | g3 | +| test.c:8:12:8:12 | 0 | Invalid alignof() size set to zero for variable $@. | test.c:8:19:8:20 | m2 | m2 | +| test.c:13:12:13:12 | 0 | Invalid alignof() size set to zero for variable $@. | test.c:13:19:13:20 | l2 | l2 | diff --git a/c/misra/test/rules/RULE-8-16/AlignmentWithSizeZero.qlref b/c/misra/test/rules/RULE-8-16/AlignmentWithSizeZero.qlref new file mode 100644 index 0000000000..c8e19d1fe5 --- /dev/null +++ b/c/misra/test/rules/RULE-8-16/AlignmentWithSizeZero.qlref @@ -0,0 +1 @@ +rules/RULE-8-16/AlignmentWithSizeZero.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-16/test.c b/c/misra/test/rules/RULE-8-16/test.c new file mode 100644 index 0000000000..3e96b7b8cc --- /dev/null +++ b/c/misra/test/rules/RULE-8-16/test.c @@ -0,0 +1,14 @@ +_Alignas(8) int g1; // COMPLIANT +_Alignas(0) int g2; // NON-COMPLIANT +_Alignas(8 - 8) int g3; // NON-COMPLIANT +_Alignas(float) int g4; // COMPLIANT + +struct s { + _Alignas(64) int m1; // COMPLIANT + _Alignas(0) int m2; // NON_COMPLIANT +}; + +void f() { + _Alignas(8) int l1; // COMPLIANT + _Alignas(0) int l2; // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.expected b/c/misra/test/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.expected new file mode 100644 index 0000000000..24707ca457 --- /dev/null +++ b/c/misra/test/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.expected @@ -0,0 +1,6 @@ +| test.c:2:30:2:31 | g2 | Variable g2 contains more than one alignment specifier, $@ and $@ | test.c:2:1:2:8 | alignas(...) | alignas(...) | test.c:2:13:2:20 | alignas(...) | alignas(...) | +| test.c:3:29:3:30 | g3 | Variable g3 contains more than one alignment specifier, $@ and $@ | test.c:3:1:3:8 | alignas(...) | alignas(...) | test.c:3:13:3:20 | alignas(...) | alignas(...) | +| test.c:4:35:4:36 | g4 | Variable g4 contains more than one alignment specifier, $@ and $@ | test.c:4:1:4:8 | alignas(...) | alignas(...) | test.c:4:17:4:24 | alignas(...) | alignas(...) | +| test.c:6:53:6:54 | g5 | Variable g5 contains more than one alignment specifier, $@ and $@ | test.c:5:1:5:8 | alignas(...) | alignas(...) | test.c:6:33:6:40 | alignas(...) | alignas(...) | +| test.c:10:35:10:36 | m2 | Variable m2 contains more than one alignment specifier, $@ and $@ | test.c:10:3:10:10 | alignas(...) | alignas(...) | test.c:10:18:10:25 | alignas(...) | alignas(...) | +| test.c:15:35:15:36 | l2 | Variable l2 contains more than one alignment specifier, $@ and $@ | test.c:15:3:15:10 | alignas(...) | alignas(...) | test.c:15:18:15:25 | alignas(...) | alignas(...) | diff --git a/c/misra/test/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.qlref b/c/misra/test/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.qlref new file mode 100644 index 0000000000..7ff11e8a61 --- /dev/null +++ b/c/misra/test/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.qlref @@ -0,0 +1 @@ +rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-17/test.c b/c/misra/test/rules/RULE-8-17/test.c new file mode 100644 index 0000000000..e2f8b2b44f --- /dev/null +++ b/c/misra/test/rules/RULE-8-17/test.c @@ -0,0 +1,16 @@ +_Alignas(8) int g1; // COMPLIANT +_Alignas(8) _Alignas(16) int g2; // NON-COMPLIANT +_Alignas(8) _Alignas(8) int g3; // NON-COMPLIANT +_Alignas(float) _Alignas(int) int g4; // NON-COMPLIANT +_Alignas(float) _Alignas(float) int g5; // NON-COMPLIANT +_Alignas(float) _Alignas(float) _Alignas(float) int g5; // NON-COMPLIANT + +struct s { + _Alignas(64) int m1; // COMPLIANT + _Alignas(long) _Alignas(16) int m2; // NON_COMPLIANT +}; + +void f() { + _Alignas(8) int l1; // COMPLIANT + _Alignas(long) _Alignas(16) int l2; // NON_COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.qlref b/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.qlref deleted file mode 100644 index 0a6121b324..0000000000 --- a/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-8-2/FunctionTypesNotInPrototypeForm.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.testref b/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.testref new file mode 100644 index 0000000000..1a6a69fc24 --- /dev/null +++ b/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.testref @@ -0,0 +1 @@ +c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.expected b/c/misra/test/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.expected index 08e419ef4f..f2b438aaf1 100644 --- a/c/misra/test/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.expected +++ b/c/misra/test/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.expected @@ -1,12 +1,14 @@ -| function1.c:6:6:6:7 | declaration of f3 | The return type of re-declaration of $@ is not compatible with declaration $@ | function1.c:6:6:6:7 | declaration of f3 | f3 | function1.c:8:4:8:5 | declaration of f3 | f3 | -| function1.c:8:4:8:5 | declaration of f3 | The return type of re-declaration of $@ is not compatible with declaration $@ | function1.c:8:4:8:5 | declaration of f3 | f3 | function1.c:6:6:6:7 | declaration of f3 | f3 | -| function1.c:8:4:8:5 | declaration of f3 | The return type of re-declaration of $@ is not compatible with declaration $@ | function1.c:8:4:8:5 | declaration of f3 | f3 | function2.c:4:6:4:7 | declaration of f3 | f3 | -| function1.c:9:6:9:7 | declaration of f4 | The return type of re-declaration of $@ is not compatible with declaration $@ | function1.c:9:6:9:7 | declaration of f4 | f4 | function2.c:5:5:5:6 | declaration of f4 | f4 | -| function1.c:13:5:13:6 | definition of f6 | The return type of re-declaration of $@ is not compatible with declaration $@ | function1.c:13:5:13:6 | definition of f6 | f6 | function2.c:9:6:9:7 | definition of f6 | f6 | -| function1.c:21:3:21:5 | definition of f21 | The parameter types of re-declaration of $@ is not compatible with declaration $@ | function1.c:21:3:21:5 | definition of f21 | f21 | function2.c:17:10:17:12 | declaration of f21 | f21 | -| function1.c:25:6:25:8 | definition of f22 | The parameter names of re-declaration of $@ is not compatible with declaration $@ | function1.c:25:6:25:8 | definition of f22 | f22 | function2.c:19:13:19:15 | declaration of f22 | f22 | -| function2.c:4:6:4:7 | declaration of f3 | The return type of re-declaration of $@ is not compatible with declaration $@ | function2.c:4:6:4:7 | declaration of f3 | f3 | function1.c:8:4:8:5 | declaration of f3 | f3 | -| function2.c:5:5:5:6 | declaration of f4 | The return type of re-declaration of $@ is not compatible with declaration $@ | function2.c:5:5:5:6 | declaration of f4 | f4 | function1.c:9:6:9:7 | declaration of f4 | f4 | -| function2.c:9:6:9:7 | definition of f6 | The return type of re-declaration of $@ is not compatible with declaration $@ | function2.c:9:6:9:7 | definition of f6 | f6 | function1.c:13:5:13:6 | definition of f6 | f6 | -| function2.c:17:10:17:12 | declaration of f21 | The parameter types of re-declaration of $@ is not compatible with declaration $@ | function2.c:17:10:17:12 | declaration of f21 | f21 | function1.c:21:3:21:5 | definition of f21 | f21 | -| function2.c:19:13:19:15 | declaration of f22 | The parameter names of re-declaration of $@ is not compatible with declaration $@ | function2.c:19:13:19:15 | declaration of f22 | f22 | function1.c:25:6:25:8 | definition of f22 | f22 | +| function1.c:6:6:6:7 | declaration of f3 | The return type of re-declaration of $@ does not use the same type names as declaration $@ | function1.c:6:6:6:7 | declaration of f3 | f3 | function1.c:8:4:8:5 | declaration of f3 | f3 | +| function1.c:8:4:8:5 | declaration of f3 | The return type of re-declaration of $@ does not use the same type names as declaration $@ | function1.c:8:4:8:5 | declaration of f3 | f3 | function1.c:6:6:6:7 | declaration of f3 | f3 | +| function1.c:8:4:8:5 | declaration of f3 | The return type of re-declaration of $@ does not use the same type names as declaration $@ | function1.c:8:4:8:5 | declaration of f3 | f3 | function2.c:4:6:4:7 | declaration of f3 | f3 | +| function1.c:9:6:9:7 | declaration of f4 | The return type of re-declaration of $@ does not use the same type names as declaration $@ | function1.c:9:6:9:7 | declaration of f4 | f4 | function2.c:5:5:5:6 | declaration of f4 | f4 | +| function1.c:13:5:13:6 | definition of f6 | The return type of re-declaration of $@ does not use the same type names as declaration $@ | function1.c:13:5:13:6 | definition of f6 | f6 | function2.c:9:6:9:7 | definition of f6 | f6 | +| function1.c:15:5:15:7 | declaration of f20 | The parameter types of re-declaration of $@ do not use the same type names as declaration $@ | function1.c:15:5:15:7 | declaration of f20 | f20 | function2.c:11:5:11:7 | declaration of f20 | f20 | +| function1.c:21:3:21:5 | definition of f21 | The parameter types of re-declaration of $@ do not use the same type names as declaration $@ | function1.c:21:3:21:5 | definition of f21 | f21 | function2.c:17:10:17:12 | declaration of f21 | f21 | +| function1.c:25:6:25:8 | definition of f22 | The parameter names of re-declaration of $@ do not use the same type names as declaration $@ | function1.c:25:6:25:8 | definition of f22 | f22 | function2.c:19:13:19:15 | declaration of f22 | f22 | +| function2.c:4:6:4:7 | declaration of f3 | The return type of re-declaration of $@ does not use the same type names as declaration $@ | function2.c:4:6:4:7 | declaration of f3 | f3 | function1.c:8:4:8:5 | declaration of f3 | f3 | +| function2.c:5:5:5:6 | declaration of f4 | The return type of re-declaration of $@ does not use the same type names as declaration $@ | function2.c:5:5:5:6 | declaration of f4 | f4 | function1.c:9:6:9:7 | declaration of f4 | f4 | +| function2.c:9:6:9:7 | definition of f6 | The return type of re-declaration of $@ does not use the same type names as declaration $@ | function2.c:9:6:9:7 | definition of f6 | f6 | function1.c:13:5:13:6 | definition of f6 | f6 | +| function2.c:11:5:11:7 | declaration of f20 | The parameter types of re-declaration of $@ do not use the same type names as declaration $@ | function2.c:11:5:11:7 | declaration of f20 | f20 | function1.c:15:5:15:7 | declaration of f20 | f20 | +| function2.c:17:10:17:12 | declaration of f21 | The parameter types of re-declaration of $@ do not use the same type names as declaration $@ | function2.c:17:10:17:12 | declaration of f21 | f21 | function1.c:21:3:21:5 | definition of f21 | f21 | +| function2.c:19:13:19:15 | declaration of f22 | The parameter names of re-declaration of $@ do not use the same type names as declaration $@ | function2.c:19:13:19:15 | declaration of f22 | f22 | function1.c:25:6:25:8 | definition of f22 | f22 | diff --git a/c/misra/test/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.expected b/c/misra/test/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.expected index c63681c7be..8b8e7f8a48 100644 --- a/c/misra/test/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.expected +++ b/c/misra/test/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.expected @@ -1,22 +1,22 @@ -| object1.c:5:6:5:7 | definition of a3 | The object $@ of type long is not compatible with re-declaration $@ of type LL | object1.c:5:6:5:7 | definition of a3 | a3 | object2.c:11:11:11:12 | declaration of a3 | a3 | -| object1.c:6:6:6:7 | definition of a4 | The object $@ of type long is not compatible with re-declaration $@ of type int | object1.c:6:6:6:7 | definition of a4 | a4 | object2.c:13:12:13:13 | declaration of a4 | a4 | -| object1.c:7:5:7:6 | definition of a5 | The object $@ of type int is not compatible with re-declaration $@ of type long | object1.c:7:5:7:6 | definition of a5 | a5 | object2.c:15:13:15:14 | declaration of a5 | a5 | -| object1.c:8:6:8:7 | definition of a6 | The object $@ of type long is not compatible with re-declaration $@ of type int | object1.c:8:6:8:7 | definition of a6 | a6 | object2.c:19:1:19:3 | declaration of a6 | a6 | -| object1.c:9:5:9:6 | definition of a7 | The object $@ of type int is not compatible with re-declaration $@ of type LL | object1.c:9:5:9:6 | definition of a7 | a7 | object2.c:21:11:21:12 | declaration of a7 | a7 | -| object1.c:15:5:15:7 | definition of a10 | The object $@ of type int[100] is not compatible with re-declaration $@ of type LI[100] | object1.c:15:5:15:7 | definition of a10 | a10 | object2.c:24:4:24:6 | definition of a10 | a10 | -| object1.c:16:5:16:7 | definition of a11 | The object $@ of type int[100] is not compatible with re-declaration $@ of type int[101] | object1.c:16:5:16:7 | definition of a11 | a11 | object2.c:25:12:25:14 | declaration of a11 | a11 | -| object1.c:19:12:19:14 | definition of a13 | The object $@ of type int *const is not compatible with re-declaration $@ of type int * | object1.c:19:12:19:14 | definition of a13 | a13 | object2.c:28:13:28:15 | declaration of a13 | a13 | -| object1.c:23:10:23:13 | definition of size | The object $@ of type size_t is not compatible with re-declaration $@ of type unsigned char | object1.c:23:10:23:13 | definition of size | size | object2.c:32:17:32:20 | definition of size | size | -| object1.c:24:3:24:4 | definition of s0 | The object $@ of type NamedStruct0 is not compatible with re-declaration $@ of type NamedStruct0 | object1.c:24:3:24:4 | definition of s0 | s0 | object2.c:33:3:33:4 | definition of s0 | s0 | -| object1.c:29:3:29:4 | definition of s1 | The object $@ of type NamedStruct1 is not compatible with re-declaration $@ of type NamedStruct1 | object1.c:29:3:29:4 | definition of s1 | s1 | object2.c:38:3:38:4 | definition of s1 | s1 | -| object2.c:11:11:11:12 | declaration of a3 | The object $@ of type LL is not compatible with re-declaration $@ of type long | object2.c:11:11:11:12 | declaration of a3 | a3 | object1.c:5:6:5:7 | definition of a3 | a3 | -| object2.c:13:12:13:13 | declaration of a4 | The object $@ of type int is not compatible with re-declaration $@ of type long | object2.c:13:12:13:13 | declaration of a4 | a4 | object1.c:6:6:6:7 | definition of a4 | a4 | -| object2.c:15:13:15:14 | declaration of a5 | The object $@ of type long is not compatible with re-declaration $@ of type int | object2.c:15:13:15:14 | declaration of a5 | a5 | object1.c:7:5:7:6 | definition of a5 | a5 | -| object2.c:19:1:19:3 | declaration of a6 | The object $@ of type int is not compatible with re-declaration $@ of type long | object2.c:19:1:19:3 | declaration of a6 | a6 | object1.c:8:6:8:7 | definition of a6 | a6 | -| object2.c:21:11:21:12 | declaration of a7 | The object $@ of type LL is not compatible with re-declaration $@ of type int | object2.c:21:11:21:12 | declaration of a7 | a7 | object1.c:9:5:9:6 | definition of a7 | a7 | -| object2.c:24:4:24:6 | definition of a10 | The object $@ of type LI[100] is not compatible with re-declaration $@ of type int[100] | object2.c:24:4:24:6 | definition of a10 | a10 | object1.c:15:5:15:7 | definition of a10 | a10 | -| object2.c:25:12:25:14 | declaration of a11 | The object $@ of type int[101] is not compatible with re-declaration $@ of type int[100] | object2.c:25:12:25:14 | declaration of a11 | a11 | object1.c:16:5:16:7 | definition of a11 | a11 | -| object2.c:28:13:28:15 | declaration of a13 | The object $@ of type int * is not compatible with re-declaration $@ of type int *const | object2.c:28:13:28:15 | declaration of a13 | a13 | object1.c:19:12:19:14 | definition of a13 | a13 | -| object2.c:32:17:32:20 | definition of size | The object $@ of type unsigned char is not compatible with re-declaration $@ of type size_t | object2.c:32:17:32:20 | definition of size | size | object1.c:23:10:23:13 | definition of size | size | -| object2.c:33:3:33:4 | definition of s0 | The object $@ of type NamedStruct0 is not compatible with re-declaration $@ of type NamedStruct0 | object2.c:33:3:33:4 | definition of s0 | s0 | object1.c:24:3:24:4 | definition of s0 | s0 | -| object2.c:38:3:38:4 | definition of s1 | The object $@ of type NamedStruct1 is not compatible with re-declaration $@ of type NamedStruct1 | object2.c:38:3:38:4 | definition of s1 | s1 | object1.c:29:3:29:4 | definition of s1 | s1 | +| object1.c:5:6:5:7 | definition of a3 | The object $@ of type long does not use the same type names as re-declaration $@ of type LL | object1.c:5:6:5:7 | definition of a3 | a3 | object2.c:11:11:11:12 | declaration of a3 | a3 | +| object1.c:6:6:6:7 | definition of a4 | The object $@ of type long does not use the same type names as re-declaration $@ of type int | object1.c:6:6:6:7 | definition of a4 | a4 | object2.c:13:12:13:13 | declaration of a4 | a4 | +| object1.c:7:5:7:6 | definition of a5 | The object $@ of type int does not use the same type names as re-declaration $@ of type long | object1.c:7:5:7:6 | definition of a5 | a5 | object2.c:15:13:15:14 | declaration of a5 | a5 | +| object1.c:8:6:8:7 | definition of a6 | The object $@ of type long does not use the same type names as re-declaration $@ of type int | object1.c:8:6:8:7 | definition of a6 | a6 | object2.c:19:1:19:3 | declaration of a6 | a6 | +| object1.c:9:5:9:6 | definition of a7 | The object $@ of type int does not use the same type names as re-declaration $@ of type LL | object1.c:9:5:9:6 | definition of a7 | a7 | object2.c:21:11:21:12 | declaration of a7 | a7 | +| object1.c:15:5:15:7 | definition of a10 | The object $@ of type int[100] does not use the same type names as re-declaration $@ of type LI[100] | object1.c:15:5:15:7 | definition of a10 | a10 | object2.c:24:4:24:6 | definition of a10 | a10 | +| object1.c:16:5:16:7 | definition of a11 | The object $@ of type int[100] does not use the same type names as re-declaration $@ of type int[101] | object1.c:16:5:16:7 | definition of a11 | a11 | object2.c:25:12:25:14 | declaration of a11 | a11 | +| object1.c:19:12:19:14 | definition of a13 | The object $@ of type int *const does not use the same type names as re-declaration $@ of type int * | object1.c:19:12:19:14 | definition of a13 | a13 | object2.c:28:13:28:15 | declaration of a13 | a13 | +| object1.c:23:10:23:13 | definition of size | The object $@ of type size_t does not use the same type names as re-declaration $@ of type unsigned char | object1.c:23:10:23:13 | definition of size | size | object2.c:32:17:32:20 | definition of size | size | +| object1.c:24:3:24:4 | definition of s0 | The object $@ of type NamedStruct0 does not use the same type names as re-declaration $@ of type NamedStruct0 | object1.c:24:3:24:4 | definition of s0 | s0 | object2.c:33:3:33:4 | definition of s0 | s0 | +| object1.c:29:3:29:4 | definition of s1 | The object $@ of type NamedStruct1 does not use the same type names as re-declaration $@ of type NamedStruct1 | object1.c:29:3:29:4 | definition of s1 | s1 | object2.c:38:3:38:4 | definition of s1 | s1 | +| object2.c:11:11:11:12 | declaration of a3 | The object $@ of type LL does not use the same type names as re-declaration $@ of type long | object2.c:11:11:11:12 | declaration of a3 | a3 | object1.c:5:6:5:7 | definition of a3 | a3 | +| object2.c:13:12:13:13 | declaration of a4 | The object $@ of type int does not use the same type names as re-declaration $@ of type long | object2.c:13:12:13:13 | declaration of a4 | a4 | object1.c:6:6:6:7 | definition of a4 | a4 | +| object2.c:15:13:15:14 | declaration of a5 | The object $@ of type long does not use the same type names as re-declaration $@ of type int | object2.c:15:13:15:14 | declaration of a5 | a5 | object1.c:7:5:7:6 | definition of a5 | a5 | +| object2.c:19:1:19:3 | declaration of a6 | The object $@ of type int does not use the same type names as re-declaration $@ of type long | object2.c:19:1:19:3 | declaration of a6 | a6 | object1.c:8:6:8:7 | definition of a6 | a6 | +| object2.c:21:11:21:12 | declaration of a7 | The object $@ of type LL does not use the same type names as re-declaration $@ of type int | object2.c:21:11:21:12 | declaration of a7 | a7 | object1.c:9:5:9:6 | definition of a7 | a7 | +| object2.c:24:4:24:6 | definition of a10 | The object $@ of type LI[100] does not use the same type names as re-declaration $@ of type int[100] | object2.c:24:4:24:6 | definition of a10 | a10 | object1.c:15:5:15:7 | definition of a10 | a10 | +| object2.c:25:12:25:14 | declaration of a11 | The object $@ of type int[101] does not use the same type names as re-declaration $@ of type int[100] | object2.c:25:12:25:14 | declaration of a11 | a11 | object1.c:16:5:16:7 | definition of a11 | a11 | +| object2.c:28:13:28:15 | declaration of a13 | The object $@ of type int * does not use the same type names as re-declaration $@ of type int *const | object2.c:28:13:28:15 | declaration of a13 | a13 | object1.c:19:12:19:14 | definition of a13 | a13 | +| object2.c:32:17:32:20 | definition of size | The object $@ of type unsigned char does not use the same type names as re-declaration $@ of type size_t | object2.c:32:17:32:20 | definition of size | size | object1.c:23:10:23:13 | definition of size | size | +| object2.c:33:3:33:4 | definition of s0 | The object $@ of type NamedStruct0 does not use the same type names as re-declaration $@ of type NamedStruct0 | object2.c:33:3:33:4 | definition of s0 | s0 | object1.c:24:3:24:4 | definition of s0 | s0 | +| object2.c:38:3:38:4 | definition of s1 | The object $@ of type NamedStruct1 does not use the same type names as re-declaration $@ of type NamedStruct1 | object2.c:38:3:38:4 | definition of s1 | s1 | object1.c:29:3:29:4 | definition of s1 | s1 | diff --git a/c/misra/test/rules/RULE-8-3/function1.c b/c/misra/test/rules/RULE-8-3/function1.c index 2072748047..f65c98c2ac 100644 --- a/c/misra/test/rules/RULE-8-3/function1.c +++ b/c/misra/test/rules/RULE-8-3/function1.c @@ -12,7 +12,7 @@ long f5(int f5a) { return 0; } // COMPLIANT int f6(int f6a) { return 0; } // NON_COMPLIANT -int f20(int f20a); // COMPLIANT - overloaded function +int f20(int f20a); // NON_COMPLIANT typedef int wi; typedef int hi; @@ -24,4 +24,8 @@ a f21(wi w, wi h) { // NON_COMPLIANT void f22(int f22b, int f22a) { // NON_COMPLIANT return; +} + +void f23(int f23a) { // COMPLIANT + return; } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-3/function2.c b/c/misra/test/rules/RULE-8-3/function2.c index 979e002466..d31aaf17e5 100644 --- a/c/misra/test/rules/RULE-8-3/function2.c +++ b/c/misra/test/rules/RULE-8-3/function2.c @@ -8,7 +8,7 @@ long f5(int f5a) { return 0; } // COMPLIANT long f6(int f6a) { return 0; } // NON_COMPLIANT -int f20(int f20a, int f20b); // COMPLIANT -- overloaded function +int f20(int f20a, int f20b); // NON_COMPLIANT typedef int wi; typedef int hi; @@ -16,4 +16,6 @@ typedef long a; extern a f21(wi w, hi h); // NON_COMPLIANT -extern void f22(int f22a, int f22b); // NON_COMPLIANT \ No newline at end of file +extern void f22(int f22a, int f22b); // NON_COMPLIANT + +extern void f23(int); // COMPLIANT \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected b/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected index b6a53071d9..6610bf236e 100644 --- a/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected +++ b/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected @@ -1,3 +1,4 @@ -| test.h:2:12:2:13 | i1 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:4:3:4:4 | i1 | i1 | -| test.h:3:5:3:6 | i2 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:5:3:5:4 | i2 | i2 | -| test.h:5:13:5:14 | f2 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:7:3:7:4 | call to f2 | call to f2 | +| test2.h:2:13:2:14 | f6 | Declaration with external linkage is accessed in only one translation unit $@. | test2.h:3:22:3:23 | call to f6 | call to f6 | +| test.c:3:5:3:6 | i1 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:11:3:11:4 | i1 | i1 | +| test.c:4:5:4:6 | i2 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:12:3:12:4 | i2 | i2 | +| test.c:6:6:6:7 | f2 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:14:3:14:4 | call to f2 | call to f2 | diff --git a/c/misra/test/rules/RULE-8-7/test.c b/c/misra/test/rules/RULE-8-7/test.c index b2cc2a0684..3789a1d269 100644 --- a/c/misra/test/rules/RULE-8-7/test.c +++ b/c/misra/test/rules/RULE-8-7/test.c @@ -1,4 +1,11 @@ #include "test.h" +int i = 0; +int i1 = 0; +int i2; // NON_COMPLIANT - accessed one translation unit +void f1() {} // Definition +void f2() {} // Definition +static void f3(){}; // COMPLIANT - internal linkage +void f4() {} // Definition void f() { i = 0; i1 = 0; diff --git a/c/misra/test/rules/RULE-8-7/test.h b/c/misra/test/rules/RULE-8-7/test.h index 692bb8e3db..782099de02 100644 --- a/c/misra/test/rules/RULE-8-7/test.h +++ b/c/misra/test/rules/RULE-8-7/test.h @@ -1,7 +1,6 @@ extern int i; // COMPLIANT - accessed multiple translation units extern int i1; // NON_COMPLIANT - accessed one translation unit -int i2; // NON_COMPLIANT - accessed one translation unit extern void f1(); // COMPLIANT - accessed multiple translation units extern void f2(); // NON_COMPLIANT - accessed one translation unit -static void f3(); // COMPLIANT - internal linkage -extern void f3(); // COMPLIANT - internal linkage \ No newline at end of file +extern void f4(); // COMPLIANT - accessed across translation units +extern void f5(); // COMPLIANT - no definition \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-7/test1.c b/c/misra/test/rules/RULE-8-7/test1.c index 77377e78df..5c3b3759c9 100644 --- a/c/misra/test/rules/RULE-8-7/test1.c +++ b/c/misra/test/rules/RULE-8-7/test1.c @@ -1,5 +1,7 @@ -#include "test.h" +#include "test2.h" void f() { i = 0; f1(); + f4(); + f5(); } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-7/test2.h b/c/misra/test/rules/RULE-8-7/test2.h new file mode 100644 index 0000000000..d203c3259a --- /dev/null +++ b/c/misra/test/rules/RULE-8-7/test2.h @@ -0,0 +1,3 @@ +#include "test.h" +extern void f6() {} // NON_COMPLIANT +static void test() { f6(); } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.qlref b/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.qlref deleted file mode 100644 index 70b6073e14..0000000000 --- a/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.testref b/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.testref new file mode 100644 index 0000000000..23ed7c9fc5 --- /dev/null +++ b/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.testref @@ -0,0 +1 @@ +c/common/test/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-9-7/UninitializedAtomicObject.expected b/c/misra/test/rules/RULE-9-7/UninitializedAtomicObject.expected new file mode 100644 index 0000000000..f96fc6aa13 --- /dev/null +++ b/c/misra/test/rules/RULE-9-7/UninitializedAtomicObject.expected @@ -0,0 +1,4 @@ +| test.c:24:15:24:16 | definition of l3 | Atomic object 'l3' has no initializer or corresponding use of 'atomic_init()'. | +| test.c:27:15:27:16 | definition of l4 | Atomic object 'l4' has no initializer or corresponding use of 'atomic_init()'. | +| test.c:31:15:31:16 | definition of l5 | Atomic object 'l5' has no initializer or corresponding use of 'atomic_init()'. | +| test.c:41:15:41:16 | definition of l7 | Atomic object 'l7' has no initializer or corresponding use of 'atomic_init()'. | diff --git a/c/misra/test/rules/RULE-9-7/UninitializedAtomicObject.qlref b/c/misra/test/rules/RULE-9-7/UninitializedAtomicObject.qlref new file mode 100644 index 0000000000..11219b0741 --- /dev/null +++ b/c/misra/test/rules/RULE-9-7/UninitializedAtomicObject.qlref @@ -0,0 +1 @@ +rules/RULE-9-7/UninitializedAtomicObject.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-9-7/test.c b/c/misra/test/rules/RULE-9-7/test.c new file mode 100644 index 0000000000..90645f6372 --- /dev/null +++ b/c/misra/test/rules/RULE-9-7/test.c @@ -0,0 +1,46 @@ +#include "stdatomic.h" +#include "threads.h" + +_Atomic int g1; // COMPLIANT +_Atomic int g2 = 0; // COMPLIANT + +int f_thread(void *x); + +void f_starts_thread() { + thrd_t t; + thrd_create(&t, f_thread, 0); +} + +void f_may_initialize_argument(void *p1) {} + +int main(int argc, char *argv[]) { + _Atomic int l1 = 1; // COMPLIANT + f_starts_thread(); + + _Atomic int l2; // COMPLIANT + atomic_init(&l2, 0); + f_starts_thread(); + + _Atomic int l3; // NON-COMPLIANT + f_starts_thread(); + + _Atomic int l4; // NON-COMPLIANT + f_starts_thread(); + atomic_init(&l4, 0); + + _Atomic int l5; // NON-COMPLIANT + if (g1 == 0) { + atomic_init(&l5, 0); + } + f_starts_thread(); + + _Atomic int l6; // COMPLIANT + f_may_initialize_argument(&l6); + f_starts_thread(); + + _Atomic int l7; // NON_COMPLIANT + if (g1 == 0) { + f_may_initialize_argument(&l7); + } + f_starts_thread(); +} \ No newline at end of file diff --git a/change_notes/2023-07-28-rule-11-4-improvements.md b/change_notes/2023-07-28-rule-11-4-improvements.md new file mode 100644 index 0000000000..3c385359a8 --- /dev/null +++ b/change_notes/2023-07-28-rule-11-4-improvements.md @@ -0,0 +1,12 @@ + - `RULE-11-1` - `ConversionBetweenFunctionPointerAndOtherType.ql`: + - Fixed issue #331 - consider `0` a null pointer constant. + - `RULE-11-4` - `ConversionBetweenPointerToObjectAndIntegerType.ql`: + - Fixed issue #331 - consider `0` a null pointer constant. + - Improve reporting of the order of the cast and the actual types involved. + - Improve reporting where the result is expanded from a macro by either reporting the macro itself (if it is not dependent on the context) or by including a link to the macro in the alert message. + - `RULE-11-5` - `ConversionFromPointerToVoidIntoPointerToObject.ql`: + - Fixed issue #331 - consider `0` a null pointer constant. + - `RULE-11-6` - `CastBetweenPointerToVoidAndArithmeticType.ql`: + - Fixed issue #331 - accept integer constant expressions with value `0` instead of null pointer constants. + - `RULE-11-9` - `MacroNullNotUsedAsIntegerNullPointerConstant.ql`: + - Remove false positives in branches of ternary expressions, where `0` was used correctly. \ No newline at end of file diff --git a/change_notes/2023-12-05-a7-2-1-typo.md b/change_notes/2023-12-05-a7-2-1-typo.md new file mode 100644 index 0000000000..f87fc7cf8b --- /dev/null +++ b/change_notes/2023-12-05-a7-2-1-typo.md @@ -0,0 +1 @@ + * `A7-2-1` - fix typo in some alert messages. \ No newline at end of file diff --git a/change_notes/2024-01-30-m0-3-2.md b/change_notes/2024-01-30-m0-3-2.md new file mode 100644 index 0000000000..b074f6b2b1 --- /dev/null +++ b/change_notes/2024-01-30-m0-3-2.md @@ -0,0 +1 @@ + * `M0-3-2` - the alert messages now include the name of the called function. \ No newline at end of file diff --git a/change_notes/2024-06-03-a3-1-5-trivial-defs.md b/change_notes/2024-06-03-a3-1-5-trivial-defs.md new file mode 100644 index 0000000000..29a7f48eb5 --- /dev/null +++ b/change_notes/2024-06-03-a3-1-5-trivial-defs.md @@ -0,0 +1,4 @@ + - `A3-1-5` - `TrivialOrTemplateFunctionDefinedOutsideClassDefinition.ql`: + - Query deleted - rule was never intended to cover this case (see https://forum.misra.org.uk/archive/index.php?thread-1588.html). + - `A3-1-5` - `NonTrivialNonTemplateFunctionDefinedInsideClassDefinition.ql`: + - Removed false positives caused by flagging member functions in template instantiations diff --git a/change_notes/2024-06-21-misra-cpp-2023-support.md b/change_notes/2024-06-21-misra-cpp-2023-support.md new file mode 100644 index 0000000000..e314d447fa --- /dev/null +++ b/change_notes/2024-06-21-misra-cpp-2023-support.md @@ -0,0 +1,2 @@ +- `MISRA C++ 2023`: + - Extend the project structure and provide initial support for query writing. diff --git a/change_notes/2024-07-05-fix-fp-576-STR34-C.md b/change_notes/2024-07-05-fix-fp-576-STR34-C.md new file mode 100644 index 0000000000..340d8f4288 --- /dev/null +++ b/change_notes/2024-07-05-fix-fp-576-STR34-C.md @@ -0,0 +1,2 @@ +- `STR34-C` - `CastCharBeforeConvertingToLargerSizes.ql`: + - Fixes #576. Do not consider integer type aliases in templates. \ No newline at end of file diff --git a/change_notes/2024-07-10-fix-fn-119-m0-2-1.md b/change_notes/2024-07-10-fix-fn-119-m0-2-1.md new file mode 100644 index 0000000000..08d139ddbe --- /dev/null +++ b/change_notes/2024-07-10-fix-fn-119-m0-2-1.md @@ -0,0 +1,2 @@ +- `M0-2-1` - `DoNotPassAliasedPointerToRestrictQualifiedParam.ql`: + - Fixes #119. Adds shared query to cover missing detection of overlapping arrays or pointers in specific list of functions that list undefined behaviour when their parameters overlap. \ No newline at end of file diff --git a/change_notes/2024-07-11-fix-fp-406.md b/change_notes/2024-07-11-fix-fp-406.md new file mode 100644 index 0000000000..78e607ecb6 --- /dev/null +++ b/change_notes/2024-07-11-fix-fp-406.md @@ -0,0 +1,2 @@ + - `A13-3-1` - `FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql`: + - Fixes #406. Exclude detection of overloaded implicit copy/move constructors. \ No newline at end of file diff --git a/change_notes/2024-07-12-support-doxygen-comment-groups.md b/change_notes/2024-07-12-support-doxygen-comment-groups.md new file mode 100644 index 0000000000..b0d7a148ba --- /dev/null +++ b/change_notes/2024-07-12-support-doxygen-comment-groups.md @@ -0,0 +1,2 @@ +- `A2-7-3` - `UndocumentedUserDefinedType.ql`: + - Fixes #391. Declarations for which a Doxygen comment group provides documentation will no longer produce results. \ No newline at end of file diff --git a/change_notes/2024-07-16-fix-fp-606-A2-7-3.md b/change_notes/2024-07-16-fix-fp-606-A2-7-3.md new file mode 100644 index 0000000000..a4fc343b76 --- /dev/null +++ b/change_notes/2024-07-16-fix-fp-606-A2-7-3.md @@ -0,0 +1,2 @@ +- `A2-7-3` - `UndocumentedUserDefinedType.ql`: + - Fixes #606. Fix false positive relating to friend functions in template classes. \ No newline at end of file diff --git a/change_notes/2024-07-23-fix-fp-646-M0-1-10.md b/change_notes/2024-07-23-fix-fp-646-M0-1-10.md new file mode 100644 index 0000000000..8854c7b59a --- /dev/null +++ b/change_notes/2024-07-23-fix-fp-646-M0-1-10.md @@ -0,0 +1,2 @@ +- `M0-1-10` - `EncapsulatingFunctions.qll`: + - Fixes #646. Consider typedef'd `int` return types for `main()` function as MainFunction. diff --git a/change_notes/2024-07-30-fix-fp-650-PRE32-C.md b/change_notes/2024-07-30-fix-fp-650-PRE32-C.md new file mode 100644 index 0000000000..e1ea391499 --- /dev/null +++ b/change_notes/2024-07-30-fix-fp-650-PRE32-C.md @@ -0,0 +1,2 @@ +- `PRE32-C` - `MacroOrFunctionArgsContainHashToken.ql`: + - Fixes #650. Correctly identifies presence of preprocessor directives in function calls. diff --git a/change_notes/2024-08-06-fix-fp-658-M0-1-3.md b/change_notes/2024-08-06-fix-fp-658-M0-1-3.md new file mode 100644 index 0000000000..47a26705ae --- /dev/null +++ b/change_notes/2024-08-06-fix-fp-658-M0-1-3.md @@ -0,0 +1,2 @@ +- `M0-1-3` - `UnusedLocalVariable.ql`: + - Fixes #658. Considers usage of const/constexpr variables in array size and function parameters that are used in arguments of template functions. diff --git a/change_notes/2024-09-11-rule-12-2-improvements.md b/change_notes/2024-09-11-rule-12-2-improvements.md new file mode 100644 index 0000000000..0e713a5088 --- /dev/null +++ b/change_notes/2024-09-11-rule-12-2-improvements.md @@ -0,0 +1,6 @@ +- `RULE-12-2` - `RightHandOperandOfAShiftRange.ql`: + - Reduce false positives related to ranges determined by `%=`. + - Reduce false positives for integer constants with explicit size suffix were incorrectly identified as smaller types. + - Improve explanation of results, providing additional information on types and size ranges. + - Combine results stemming from the expansion of a macro, where the result is not dependent on the context. + \ No newline at end of file diff --git a/change_notes/2024-09-16-rule-5-8-consider-linkage.md b/change_notes/2024-09-16-rule-5-8-consider-linkage.md new file mode 100644 index 0000000000..2877d53f50 --- /dev/null +++ b/change_notes/2024-09-16-rule-5-8-consider-linkage.md @@ -0,0 +1,2 @@ + - `RULE-5-8` - `IdentifiersWithExternalLinkageNotUnique.ql` + - Remove false positives where conflicting declarations do not appear in the same link target. \ No newline at end of file diff --git a/change_notes/2024-09-17-essential-types-unary.md b/change_notes/2024-09-17-essential-types-unary.md new file mode 100644 index 0000000000..401f59a9a6 --- /dev/null +++ b/change_notes/2024-09-17-essential-types-unary.md @@ -0,0 +1,4 @@ + - `RULE-10-1` - `OperandsOfAnInappropriateEssentialType.ql` + - Reduce false negatives by supporting operands to the `~` operator with the incorrect essential type. + - Reduce false positives by identifying the essential type of `!` as essentially boolean type. + - Improve clarity reporting by reporting the violating operand, instead of the operator, and addressing message typos. \ No newline at end of file diff --git a/change_notes/2024-09-17-fix-fp-678-m0-1-9.md b/change_notes/2024-09-17-fix-fp-678-m0-1-9.md new file mode 100644 index 0000000000..e068825f4c --- /dev/null +++ b/change_notes/2024-09-17-fix-fp-678-m0-1-9.md @@ -0,0 +1,2 @@ +- `M0-1-9` - `DeadCode.qll`: + - Fixes #678. Remove dead code false positive when integer constant expression is used to define the size of an array. diff --git a/change_notes/2024-09-17-rule-8-3-linker-aware.md b/change_notes/2024-09-17-rule-8-3-linker-aware.md new file mode 100644 index 0000000000..3e48bb1228 --- /dev/null +++ b/change_notes/2024-09-17-rule-8-3-linker-aware.md @@ -0,0 +1,2 @@ + - `RULE-8-3` - `DeclarationsOfAnObjectSameNameAndType.ql` + - Remove false positives where two conflicting declarations are never linked together. \ No newline at end of file diff --git a/change_notes/2024-09-18-handle-warning-suppresion-flags b/change_notes/2024-09-18-handle-warning-suppresion-flags new file mode 100644 index 0000000000..12bf30e937 --- /dev/null +++ b/change_notes/2024-09-18-handle-warning-suppresion-flags @@ -0,0 +1,2 @@ +- `A1-1-2` - `CompilerWarningLevelNotInCompliance.ql`: + - Fixes #689 false negatives where '-Wno-foo' was treated as enabling, rather than disabling warnings. \ No newline at end of file diff --git a/change_notes/2024-09-19-c-extensions.md b/change_notes/2024-09-19-c-extensions.md new file mode 100644 index 0000000000..2f78574679 --- /dev/null +++ b/change_notes/2024-09-19-c-extensions.md @@ -0,0 +1,4 @@ + - `RULE-1-2` - `LanguageExtensionsShouldNotBeUsed.ql`: + - Improve reporting by describing which language extensions are used. + - Improve reporting by aggregating results generated from a macro expansion at the generating macro location. + - Reduce false positives for the variable length array check by permitting those extensions which are included in the C99 standard. \ No newline at end of file diff --git a/change_notes/2024-09-19-fix-fp-665-M3-4-1.md b/change_notes/2024-09-19-fix-fp-665-M3-4-1.md new file mode 100644 index 0000000000..63c5f91b56 --- /dev/null +++ b/change_notes/2024-09-19-fix-fp-665-M3-4-1.md @@ -0,0 +1,2 @@ +- `M3-4-1` - `UnnecessaryExposedIdentifierDeclarationShared.qll`: + - Fixes #665. Exclude variables that are constexpr and coming from template instantiations. diff --git a/change_notes/2024-09-20-fix-7-2-fps.md b/change_notes/2024-09-20-fix-7-2-fps.md new file mode 100644 index 0000000000..897aebadb7 --- /dev/null +++ b/change_notes/2024-09-20-fix-7-2-fps.md @@ -0,0 +1,3 @@ + - `RULE-7-2` - `UOrUSuffixRepresentedInUnsignedType.ql` + - Remove false positives where integer constants are generated from macros. + - Remove false positives where a signed integer is implicitly converted to unsigned, which is permitted by the standard. \ No newline at end of file diff --git a/change_notes/2024-09-25-dead-code-improvements.md b/change_notes/2024-09-25-dead-code-improvements.md new file mode 100644 index 0000000000..9cd8d95ff5 --- /dev/null +++ b/change_notes/2024-09-25-dead-code-improvements.md @@ -0,0 +1,5 @@ + - `M0-1-9` - `DeadCode.ql` + - Remove false positives for statements where the enclosing function is compiled multiple times, either as part of different targets or a different template instantiations. Previously we would see false positives where a statement was dead in one instance of the code, but not other instances. We now only consider a statement dead if it is dead in all instances of that code. +- `RULE-2-2` - `DeadCode.ql`: + - Query has been rewritten to report only _operations_ that are considered dead, not statements. This should reduce false positives. + - Remove false positives for operations where the enclosing function is compiled multiple times, either as part of different targets or a different template instantiations. Previously we would see false positives where a operation was dead in one instance of the code, but not other instances. We now only consider a operation dead if it is dead in all instances of that code. \ No newline at end of file diff --git a/change_notes/2024-09-28-improved-noreturn-rules.md b/change_notes/2024-09-28-improved-noreturn-rules.md new file mode 100644 index 0000000000..99fb4a0f46 --- /dev/null +++ b/change_notes/2024-09-28-improved-noreturn-rules.md @@ -0,0 +1,3 @@ + - `A7-6-1`, `MSC53-CPP`, `RULE-9-6-4` - `FunctionNoReturnAttbrituteCondition.qll` + - Analysis expanded from functions with "noreturn" attribute, now includes the "noreturn" specifier as well to handle new c rules. No difference in C++ results expected. + - Exclude compiler generated functions from being reported. \ No newline at end of file diff --git a/change_notes/2024-10-02-c-perf-issues.md b/change_notes/2024-10-02-c-perf-issues.md new file mode 100644 index 0000000000..c9fcac1a05 --- /dev/null +++ b/change_notes/2024-10-02-c-perf-issues.md @@ -0,0 +1,4 @@ + - `RULE-10-7` - `ImplicitConversionOfCompositeExpression.ql`: + - Improved performance on larger codebases. + - `SIG31-C` - `DoNotAccessSharedObjectsInSignalHandlers.ql`: + - Improved performance on larger codebases. \ No newline at end of file diff --git a/change_notes/2024-10-02-fix-fp-711-M0-1-10.md b/change_notes/2024-10-02-fix-fp-711-M0-1-10.md new file mode 100644 index 0000000000..cff5d5ab43 --- /dev/null +++ b/change_notes/2024-10-02-fix-fp-711-M0-1-10.md @@ -0,0 +1,2 @@ +- `M0-1-10` - `UnusedFunction.ql`: + - Fixes #711. Excludes constexpr functions, considers functions from GoogleTest as an EntryPoint and does not consider special member functions. Another query called UnusedSplMemberFunction.ql is created that reports unused special member functions. This is done so as to enable deviations to be applied to this case. diff --git a/change_notes/2024-10-03-misra-c-query-suites.md b/change_notes/2024-10-03-misra-c-query-suites.md new file mode 100644 index 0000000000..c60aac8941 --- /dev/null +++ b/change_notes/2024-10-03-misra-c-query-suites.md @@ -0,0 +1,10 @@ + - The following query suites have been added or modified for MISRA C: + - A new query suite has been created `misra-c-default.qls` to avoid confusion with the MISRA C++ query suites. The `misra-default.qls` suite has been deprecated, and will be removed in a future releases, and is replaced by the `misra-c-default.qls` suite. + - The `misra-c-default.qls` suite has been specified as the default for the pack, and will include our most up-to-date coverage for MISRA C. + - A new query suite `misra-c-2012-third-edition-with-amendment-2.qls` has been created to represent our previous MISRA C coverage. Note: this query suite will run the rules that were present in MISRA C 2012, Third Edition, First Revision and Amendment 2. The interpretation of those rules may be updated to reflect changes in more recent MISRA standards. + - Three new query suites, `misra-c-mandatory.qls`, `misra-c-required.qls` and `misra-c-advisory.qls`, have been added to enable running mandatory, required or advisory queries. + - The following query suites have been added or modified for MISRA C++: + - A new query suite has been created `misra-cpp-default.qls` to avoid confusion with the MISRA C query suites. The `misra-default.qls` suite has been deprecated, and will be removed in a future releases, and is replaced by the `misra-cpp-default.qls` suite. + - The `misra-cpp-default.qls` suite has been specified as the default for the pack, and will include our most up-to-date coverage for MISRA C. + - A new query suite has been created `misra-cpp-single-translation-unit.qls` to avoid confusion with the MISRA C query suites. The `misra-single-translation-unit.qls` suite has been deprecated, and will be removed in a future releases, and is replaced by the `misra-cpp-single-translation-unit.qls` suite. + - Three new query suites, `misra-cpp-mandatory.qls`, `misra-c-required.qls` and `misra-c-advisory.qls`, have been added to enable running mandatory, required or advisory queries. \ No newline at end of file diff --git a/change_notes/2024-10-04-fix-constexpr-arr-size-fp-a0-1-1.md b/change_notes/2024-10-04-fix-constexpr-arr-size-fp-a0-1-1.md new file mode 100644 index 0000000000..184efa9462 --- /dev/null +++ b/change_notes/2024-10-04-fix-constexpr-arr-size-fp-a0-1-1.md @@ -0,0 +1,2 @@ +- `A0-1-1` - `UselessAssignments.qll`: + - Remove (dead code) useless assignment false positive when integer constant expression is used to define the size of an array. diff --git a/change_notes/2024-10-08-upgrade-to-2.16.6.md b/change_notes/2024-10-08-upgrade-to-2.16.6.md new file mode 100644 index 0000000000..9f1e11d3d3 --- /dev/null +++ b/change_notes/2024-10-08-upgrade-to-2.16.6.md @@ -0,0 +1,3 @@ +- Updated the CodeQL version to `2.16.6`. +- `M0-1-2` - `InfeasiblePath.ql`: + - This query may now report additional results within templates where a relational operation is performed which has a constant value given the specified arguments. \ No newline at end of file diff --git a/change_notes/2024-10-10-rule-18-8-vla-rule-changes-amendment4.md b/change_notes/2024-10-10-rule-18-8-vla-rule-changes-amendment4.md new file mode 100644 index 0000000000..f465836052 --- /dev/null +++ b/change_notes/2024-10-10-rule-18-8-vla-rule-changes-amendment4.md @@ -0,0 +1,4 @@ +- `RULE-18-8` - `VariableLengthArrayTypesUsed.ql`: + - Implement changes declared in MISRA C 2012 Amendment 4. This rule now only bans the use of VLA objects. Rules restricting the use of VLA types -- specifically, pointers to VLA types -- are now implemented in `RULE-18-10`. +- `EXP-35-C` - `DoNotModifyObjectsWithTemporaryLifetime.ql` + - Refactor component into a shared library, should not have any effect on rule results. \ No newline at end of file diff --git a/change_notes/2024-10-11-specifiers-rule-11-misra-c.md b/change_notes/2024-10-11-specifiers-rule-11-misra-c.md new file mode 100644 index 0000000000..5f74dc6b3f --- /dev/null +++ b/change_notes/2024-10-11-specifiers-rule-11-misra-c.md @@ -0,0 +1,4 @@ +- `RULE-11-3`, `RULE-11-4`, `RULE-11-5`, `RULE-11-7` - `CastBetweenObjectPointerAndDifferentObjectType.ql`, `ConversionBetweenPointerToObjectAndIntegerType.ql`, `ConversionFromPointerToVoidIntoPointerToObject.ql`, `CastBetweenPointerToObjectAndNonIntArithmeticType.ql`: + - Removed false positives where casts involved a specified void type pointer, e.g. `const void*`, which should not be considered as a pointer to object. +- `RULE-11-5` - `ConversionFromPointerToVoidIntoPointerToObject.ql`: + - Addressed false negatives where the pointer-to-void was specified. \ No newline at end of file diff --git a/change_notes/2024-10-15-a7-1-3-multi-refs.md b/change_notes/2024-10-15-a7-1-3-multi-refs.md new file mode 100644 index 0000000000..39e00495cb --- /dev/null +++ b/change_notes/2024-10-15-a7-1-3-multi-refs.md @@ -0,0 +1,2 @@ +- `A7-1-3` - `CvQualifiersNotPlacedOnTheRightHandSide.ql`: + - Removed false positives where a correctly CV-qualified typedef variable type was also referenced in the initializer. \ No newline at end of file diff --git a/change_notes/2024-10-15-fix-fp-739-a14-5-2.md b/change_notes/2024-10-15-fix-fp-739-a14-5-2.md new file mode 100644 index 0000000000..6e3f422718 --- /dev/null +++ b/change_notes/2024-10-15-fix-fp-739-a14-5-2.md @@ -0,0 +1,2 @@ +- `A14-5-2` - `NonTemplateMemberDefinedInTemplate.ql` + - Fixes #739. Correctly detect template parameters specified in using alias base types, e.g. `using T1 = some_type::Type;`. diff --git a/change_notes/2024-10-15-lits-and-constants-10-4.md b/change_notes/2024-10-15-lits-and-constants-10-4.md new file mode 100644 index 0000000000..cfcb309204 --- /dev/null +++ b/change_notes/2024-10-15-lits-and-constants-10-4.md @@ -0,0 +1,5 @@ + - `RULE-10-4` - `OperandswithMismatchedEssentialTypeCategory.ql`: + - Removed false positives where a specified or typedef'd enum type was compared to an enum constant type. + - `EssentialType` - for all queries related to essential types: + - `\n` and other control characters are now correctly deduced as essentially char type, instead of an essentially integer type. + - Enum constants for anonymous enums are now correctly deduced as an essentially signed integer type instead of essentially enum. \ No newline at end of file diff --git a/change_notes/2024-10-17-a5-2-6-no-ambiguity.md b/change_notes/2024-10-17-a5-2-6-no-ambiguity.md new file mode 100644 index 0000000000..6e00b3bbaf --- /dev/null +++ b/change_notes/2024-10-17-a5-2-6-no-ambiguity.md @@ -0,0 +1,3 @@ + - `A5-2-6` - `OperandsOfAlogicalAndOrNotParenthesized.ql`: + - Remove false positives where the operator is identical. + - Improve alert message to clarify which expression needs to be parenthesized. \ No newline at end of file diff --git a/change_notes/2024-10-17-suffixes.md b/change_notes/2024-10-17-suffixes.md new file mode 100644 index 0000000000..16d8ca4cda --- /dev/null +++ b/change_notes/2024-10-17-suffixes.md @@ -0,0 +1,4 @@ + - `5.13.4` - `UnsignedLiteralsNotAppropriatelySuffixed.ql`: + - Expand detection to binary literals. + - `M2-13-3` - `MissingUSuffix.ql`: + - Expand detection to binary literals. \ No newline at end of file diff --git a/change_notes/2024-10-18-init-base-class-deleted.md b/change_notes/2024-10-18-init-base-class-deleted.md new file mode 100644 index 0000000000..992e1e88a2 --- /dev/null +++ b/change_notes/2024-10-18-init-base-class-deleted.md @@ -0,0 +1,2 @@ +- `A12-1-1`, `RULE-15-1-2` - `InitializeAllVirtualBaseClasses.ql`, `ExplicitConstructorBaseClassInitialization.ql`: + - Remove false positives for deleted member functions. \ No newline at end of file diff --git a/change_notes/2024-10-20-8-13-fixes.md b/change_notes/2024-10-20-8-13-fixes.md new file mode 100644 index 0000000000..6ee8e3a32c --- /dev/null +++ b/change_notes/2024-10-20-8-13-fixes.md @@ -0,0 +1,7 @@ + - `RULE-8-13` - `PointerShouldPointToConstTypeWhenPossible.ql` + - Exclude false positives where a variable occurs in a file compiled multiple times, but where it may only be const in some of those scenarios. + - Exclude results for local scope variables in functions that use assembly code, as CodeQL cannot determine the impact of the assembly. + - Exclude false positives when an assignment is made to a struct field. + - Exclude false positives where the object pointed to by the variable is modified using `*p++ = ...`. + - Exclude false positives for functions without bodies. + - Rules that rely on the determination of side-effects of an expression may change as a result of considering `*p++ = ...` as having a side-effect on `p`. \ No newline at end of file diff --git a/change_notes/2024-10-21-rule-1-3-main.md b/change_notes/2024-10-21-rule-1-3-main.md new file mode 100644 index 0000000000..7bd8d4bd54 --- /dev/null +++ b/change_notes/2024-10-21-rule-1-3-main.md @@ -0,0 +1,3 @@ + - `RULE-1-3` - `OccurrenceOfUndefinedBehavior.ql`: + - Improve alert message to report the undefined behavior triggered. + - Address both false positives and false negatives in identifying standard compliant main methods. Previously, `void main()` was considered permitted and `int main(void)` banned. In addition, we now detect main methods as standard compliant if they use typedefs, and if arrays are used in the definition of `argv`. \ No newline at end of file diff --git a/change_notes/2024-10-21-rule-5-4-conditional.md b/change_notes/2024-10-21-rule-5-4-conditional.md new file mode 100644 index 0000000000..cfc22f3642 --- /dev/null +++ b/change_notes/2024-10-21-rule-5-4-conditional.md @@ -0,0 +1,3 @@ + - `RULE-5-4` - `MacroIdentifiersNotDistinct.ql`: + - Exclude false positives related to conditional compilation, where a macro may be defined twice, but not within the same compilation. + - Improve alert message in the case the 63 char limit is not relevant by using the form "Definition of macro `` is not distinct from alternative definition of `` in ``. \ No newline at end of file diff --git a/change_notes/2024-10-22-fix-fp-m6-5-3.md b/change_notes/2024-10-22-fix-fp-m6-5-3.md new file mode 100644 index 0000000000..0d8ca573d9 --- /dev/null +++ b/change_notes/2024-10-22-fix-fp-m6-5-3.md @@ -0,0 +1,2 @@ +- `M6-5-3` - `Loops.qll`: + - Fixes #755. Specifies that the access to the loop counter must be via non-const address. diff --git a/change_notes/2024-10-22-rule-2-5.md b/change_notes/2024-10-22-rule-2-5.md new file mode 100644 index 0000000000..6de3f0be11 --- /dev/null +++ b/change_notes/2024-10-22-rule-2-5.md @@ -0,0 +1,2 @@ + - `RULE-2-5` - `UnusedMacroDeclaration.ql`: + - Exclude false positives where a macro was used before definition, for example a header guard. \ No newline at end of file diff --git a/change_notes/2024-10-22-update-release-artifacts.md b/change_notes/2024-10-22-update-release-artifacts.md new file mode 100644 index 0000000000..46d0ed0c30 --- /dev/null +++ b/change_notes/2024-10-22-update-release-artifacts.md @@ -0,0 +1,4 @@ + - Modifications to the release artifacts: + - New CodeQL pack release artifacts have been created. These release artifacts can be downloaded from the release, and will be published to the GitHub registry under the `codeql` org for ease of deployment. + - The user manual has been updated to describe how to use the CodeQL packs. + - We no longer require a separate download of the CodeQL Standard Library for C++ - all queries have been pre-compiled and linked with the appropriate standard library. \ No newline at end of file diff --git a/change_notes/2024-10-23-cvalue-widening.md b/change_notes/2024-10-23-cvalue-widening.md new file mode 100644 index 0000000000..1d7a0f876a --- /dev/null +++ b/change_notes/2024-10-23-cvalue-widening.md @@ -0,0 +1,2 @@ + - `M5-0-3`, `M5-0-7`, `M5-0-8`, `M5-0-9` - `CvalueExpressionConvertedToDifferentUnderlyingType.ql`, `ExplicitFloatingIntegralConversionOfACValueExpr.ql`, `ExplicitWideningConversionOfACValueExpr.ql`, `ExplicitSignedness.ql`: + - Reduce false positives from misidentifying an explicitly casted expression used as a function argument or return value as a `cvalue`. diff --git a/change_notes/2024-10-24-compatible-types.md b/change_notes/2024-10-24-compatible-types.md new file mode 100644 index 0000000000..05afbd64d9 --- /dev/null +++ b/change_notes/2024-10-24-compatible-types.md @@ -0,0 +1,2 @@ + - `DCL40-C` - `IncompatibleFunctionDeclarations.ql`: + - Reduce false positives by identifying compatible integer arithmetic types (e.g. "signed int" and "int"). \ No newline at end of file diff --git a/change_notes/2024-10-28-essential-types-bitwise.md b/change_notes/2024-10-28-essential-types-bitwise.md new file mode 100644 index 0000000000..a382290351 --- /dev/null +++ b/change_notes/2024-10-28-essential-types-bitwise.md @@ -0,0 +1,2 @@ + - `RULE-10-1`, `RULE-10-3`, `RULE-10-4`, `RULE-10-5`, `RULE-10-6`, `RULE-10-7`, `RULE-10-8`, `RULE-12-2` - `OperandsOfAnInappropriateEssentialType.ql`, `AssignmentOfIncompatibleEssentialType.ql`, `OperandsWithMismatchedEssentialTypeCategory.ql`, `InappropriateEssentialTypeCast.ql`, `AssignmentToWiderEssentialType,ql`, `ImplicitConversionOfCompositeExpression.ql`, `InappropriateCastOfCompositeExpression.ql`: + - False positives and false negatives removed due to fixing incorrect essential type of the binary bitwise operations `^`, `|` and `&`. Previously the standard type was used, instead of applying the essential type rules which dictate that if both arguments have the same signedness, the essential type will have the same signedness and a rank equal to the larger of the two operands. \ No newline at end of file diff --git a/change_notes/2024-10-30-fix-issue-629.md b/change_notes/2024-10-30-fix-issue-629.md new file mode 100644 index 0000000000..1e7421f6f6 --- /dev/null +++ b/change_notes/2024-10-30-fix-issue-629.md @@ -0,0 +1,2 @@ +- `A7-1-7` - `IdentifierDeclarationAndInitializationNotOnSeparateLines.ql` + - Fixes #629. Adds brackets, excluding expressions statements in macros. diff --git a/change_notes/2024-11-11-fix-fp-789.md b/change_notes/2024-11-11-fix-fp-789.md new file mode 100644 index 0000000000..b06ebb9b11 --- /dev/null +++ b/change_notes/2024-11-11-fix-fp-789.md @@ -0,0 +1,3 @@ +- `A7-1-2` - `VariableMissingConstexpr.ql`: + - Do not report on member variables if the class has un-instantiated member function(s). + - Check a call's qualifier as well whether it can be compile time evaluated or not. diff --git a/change_notes/2024-11-13-fix-fp-796.md b/change_notes/2024-11-13-fix-fp-796.md new file mode 100644 index 0000000000..5fa32f57e8 --- /dev/null +++ b/change_notes/2024-11-13-fix-fp-796.md @@ -0,0 +1,2 @@ + - `A13-3-1` - `FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql`: + - Reduce false positives by explicitly checking that the locations of overloaded functions are different. diff --git a/change_notes/2024-11-27-c-object-refactor.md b/change_notes/2024-11-27-c-object-refactor.md new file mode 100644 index 0000000000..511ce1b7ce --- /dev/null +++ b/change_notes/2024-11-27-c-object-refactor.md @@ -0,0 +1,21 @@ +- `CON34-C` - `AppropriateThreadObjectStorageDurations.ql`: + - Improved analysis for detecting objects with automatic storage duration + - New reports will include `a.x`, `a[x]` for object `a` with automatic storage duration +- `DCL30-C` - `AppropriateStorageDurationsFunctionReturn.ql`: + - Improved analysis for detecting objects with automatic storage duration + - New reports will include `a.x`, `a[x]` for object `a` with automatic storage duration + - False positives related to returning copying pointer values +- `EXP35-C` - `DoNotModifyObjectsWithTemporaryLifetime.ql`: + - Improved analysis for detecting objects with temporary lifetime + - More non-lvalue expressions that produce temporary objects detected, for instance `(x = y).x`, previously only `f().x` discovered +- `MEM33-C` - `AllocStructsWithAFlexibleArrayMemberDynamically.ql`: + - Improved analysis for detecting objects with automatic storage duration + - New reports will include struct literals with a flexible array member +- `RULE-18-9` - `ModifiableLValueSubscriptedWithTemporaryLifetime.ql`: + - Problems will be reported at more obviously non-lvalue locations + - Implementation refactored to be shared with other libraries + - No other changes expected +- `RULE-18-9` - `ArrayToPointerConversionOfTemporaryLifetime.ql`: + - Problems will be reported at more obviously non-lvalue locations + - Implementation refactored to be shared with other libraries + - No other changes expected \ No newline at end of file diff --git a/change_notes/2024-11-27-raii-concurrency-analysis-perf.md b/change_notes/2024-11-27-raii-concurrency-analysis-perf.md new file mode 100644 index 0000000000..3a08427808 --- /dev/null +++ b/change_notes/2024-11-27-raii-concurrency-analysis-perf.md @@ -0,0 +1,2 @@ + - `Concurrency` - for all queries related to RAII-style mutexes + - These types of locks have been refactored to improve performance in some queries. No change in query results expected. \ No newline at end of file diff --git a/change_notes/2024-11-27-resource-leak-analysis-refactor.md b/change_notes/2024-11-27-resource-leak-analysis-refactor.md new file mode 100644 index 0000000000..8f2799b543 --- /dev/null +++ b/change_notes/2024-11-27-resource-leak-analysis-refactor.md @@ -0,0 +1,10 @@ +- `ERR57-CPP` - `DoNotLeakResourcesWhenHandlingExceptions.ql`: + - Resource leak detection code refactored for sharing across queries + - Control flow no longer uses "cut nodes." This could impact performance positively or negatively, however measurements have been taken that indicate no significant change + - Some false positives have been suppressed due to slightly different control flow approach + - Leaked mutex locks and open files are reported at slightly different location, reported at call site (e.g. `f.open(...)`, `m.lock()`) rather than on the variable itself (`f` and `m`). +- `A15-1-4` - `ValidResourcesStateBeforeThrow.ql`: + - Resource leak detection code refactored for sharing across queries + - Control flow no longer uses "cut nodes." This could impact performance positively or negatively, however measurements have been taken that indicate no significant change + - Some false positives have been suppressed due to slightly different control flow approach + - Leaked mutex locks and open files are reported at slightly different location, reported at call site (e.g. `f.open(...)`, `m.lock()`) rather than on the variable itself (`f` and `m`). \ No newline at end of file diff --git a/change_notes/2024-12-05-upgrade-to-2.18.4.md b/change_notes/2024-12-05-upgrade-to-2.18.4.md new file mode 100644 index 0000000000..6f3d4ba404 --- /dev/null +++ b/change_notes/2024-12-05-upgrade-to-2.18.4.md @@ -0,0 +1,3 @@ +- Updated the CodeQL version to `2.18.4`. +- `A12-8-6` - `CopyAndMoveNotDeclaredProtected.ql`: + - Implicitly created copy and move constructors will no longer be flagged in tenplate instantiations when they are unused, or trivial (tracked at https://github.com/github/codeql-coding-standards/issues/811). \ No newline at end of file diff --git a/change_notes/2024-12-08-identifier-hiding.md b/change_notes/2024-12-08-identifier-hiding.md new file mode 100644 index 0000000000..b769b16e57 --- /dev/null +++ b/change_notes/2024-12-08-identifier-hiding.md @@ -0,0 +1,7 @@ + - `A2-10-1` - `IdentifierHiding.ql`: + - Improved evaluation performance. + - Addressed false negatives where nested loops used the same variable name. + - Exclude cases where a variable declared in a lambda expression shadowed a global or namespace variable that did not appear in the same translation unit. + - `RULE-5-3` - `IdentifierHidingC.ql`: + - Improved evaluation performance. + - Addressed false negatives where nested loops used the same variable name. \ No newline at end of file diff --git a/change_notes/2024-12-10-a15-4-4-deviations.md b/change_notes/2024-12-10-a15-4-4-deviations.md new file mode 100644 index 0000000000..4a595e3e00 --- /dev/null +++ b/change_notes/2024-12-10-a15-4-4-deviations.md @@ -0,0 +1,2 @@ + - `A15-4-4` - `MissingNoExcept.ql`: + - Enable deviations on either declarations or definitions. \ No newline at end of file diff --git a/change_notes/2024-12-10-refactor-concurrency-library.md b/change_notes/2024-12-10-refactor-concurrency-library.md new file mode 100644 index 0000000000..ccefe85f19 --- /dev/null +++ b/change_notes/2024-12-10-refactor-concurrency-library.md @@ -0,0 +1,2 @@ + - `Concurrency.qll` - for all queries using this library + - This has been refactored into a set of smaller utility files. No impact on query results or performance expected. \ No newline at end of file diff --git a/change_notes/2024-12-10-udpate-a7-1-1.md b/change_notes/2024-12-10-udpate-a7-1-1.md new file mode 100644 index 0000000000..6efa1ae01f --- /dev/null +++ b/change_notes/2024-12-10-udpate-a7-1-1.md @@ -0,0 +1,2 @@ +- `A7-1-1` - `DeclarationUnmodifiedObjectMissingConstSpecifier.ql`: + - Exclude rvalue references. diff --git a/change_notes/2024-12-12-complex-floating-essential-types.md b/change_notes/2024-12-12-complex-floating-essential-types.md new file mode 100644 index 0000000000..5f5b6b519f --- /dev/null +++ b/change_notes/2024-12-12-complex-floating-essential-types.md @@ -0,0 +1,8 @@ + - `EssentialType` - for all queries related to essential types: + - Complex floating types are now considered a different essential type than real floating types. + - `RULE-10-1` `RULE-10-3`, `RULE-10-4`, `RULE-10-5`, `RULE-10-7`, `RULE-10-8` - `OperandsOfAnInappropriateEssentialType.ql`, `AssignmentOfIncompatibleEssentialType.ql`, `OperandsWithMismatchedEssentialTypeCategory.ql`, `InappropriateEssentialTypeCast.ql`, `ImplicitConversionOfCompositeExpression.ql`, `InappropriateCastOfCompositeExpression.ql`: + - Updates to rules handling complex floating types in MISRA-C 2012 Amendment 3 have been implemented. +- `RULE-14-1`, `LoopOverEssentiallyFloatType.ql`: + - Query updated to account for the existence of complex essentially floating point types. No change in query results or performance expected. + - `DIR-4-6` - `PlainNumericalTypeUsedOverExplicitTypedef.ql`: + - Updates from MISRA-C 2012 Amendment 3 specifying complex fixed width typedef support has been implemented. \ No newline at end of file diff --git a/change_notes/2024-12-12-lessen-emergent-language-feature-restrictions.md b/change_notes/2024-12-12-lessen-emergent-language-feature-restrictions.md new file mode 100644 index 0000000000..2893ba620b --- /dev/null +++ b/change_notes/2024-12-12-lessen-emergent-language-feature-restrictions.md @@ -0,0 +1,2 @@ + - `RULE-1-4` - `EmergentLanguageFeaturesUsed.ql`: + - Remove restrictions on `stdnoreturn.h`, `stdalign.h`. \ No newline at end of file diff --git a/change_notes/2024-12-13-implement-misra-c-amendment4-rule-amendments.md b/change_notes/2024-12-13-implement-misra-c-amendment4-rule-amendments.md new file mode 100644 index 0000000000..b168ccaf78 --- /dev/null +++ b/change_notes/2024-12-13-implement-misra-c-amendment4-rule-amendments.md @@ -0,0 +1,11 @@ + - `RULE-11-3` - `CastBetweenObjectPointerAndDifferentObjectType.ql` + - Constrain exception that pointer types to may be cast to char types, so that it does not apply to atomic pointer types, in compliance with MISRA-C 2012 Amendment 4. + - `RULE-11-8` - `CastRemovesConstOrVolatileQualification.ql` + - Query expanded to detect cases of removing `_Atomic` qualification, in compliance with MISRA-C 2012 Amendment 4. + - `EXP33-C`, `RULE-9-1`, `A8-5-0`, `EXP53-CPP` - `DoNotReadUninitializedMemory.ql`, `ObjectWithAutoStorageDurationReadBeforeInit.ql`, `MemoryNotInitializedBeforeItIsRead.ql`, `DoNotReadUninitializedMemory.ql` + - Atomic local variables excluded from query results, in compliance with MISRA-C 2012 Amendment 4, and to reduce false positives in the other standards. + - `RULE-13-2` - `UnsequencedAtomicReads.ql` + - New query to find expressions which read an atomic variable more than once between sequence points, to address new case from MISRA-C 2012 Amendment 4. + - `RULE-3-1` - `CharacterSequencesAndUsedWithinAComment.ql` + - Add exception allowing URLs inside of cpp-style `/* ... */` comments, in compliance with MISRA-C 2012 Amendment 4. + - No longer report cases of `//*some comment` in this rule. \ No newline at end of file diff --git a/change_notes/2024-12-17-fix-fp-824-a15-4-4 b/change_notes/2024-12-17-fix-fp-824-a15-4-4 new file mode 100644 index 0000000000..89ccf49815 --- /dev/null +++ b/change_notes/2024-12-17-fix-fp-824-a15-4-4 @@ -0,0 +1,2 @@ + - `A15-4-4` - `MissingNoExcept.ql`: + - Reduce false positives by not reporting on functions that have a noexcept specification with a complex expression or call other such functions. diff --git a/change_notes/2024-12-18-fix-fp-540-a3-9-1.md b/change_notes/2024-12-18-fix-fp-540-a3-9-1.md new file mode 100644 index 0000000000..fbd09ca840 --- /dev/null +++ b/change_notes/2024-12-18-fix-fp-540-a3-9-1.md @@ -0,0 +1,2 @@ + - `A3-9-1` - `VariableWidthIntegerTypesUsed.ql`: + - Reduce false positives by not considering variables from template instantiations. diff --git a/change_notes/2024-9-20-a1-1-2-improvements.md b/change_notes/2024-9-20-a1-1-2-improvements.md new file mode 100644 index 0000000000..25e393954b --- /dev/null +++ b/change_notes/2024-9-20-a1-1-2-improvements.md @@ -0,0 +1,2 @@ +- `A1-1-2` - `CompilerWarningLevelNotInCompliance.ql`: + - Report non-compliance for compilations that use the error-suppressing `-w` flag. diff --git a/change_notes/2025-01-09-return-reference.md b/change_notes/2025-01-09-return-reference.md new file mode 100644 index 0000000000..69480916c7 --- /dev/null +++ b/change_notes/2025-01-09-return-reference.md @@ -0,0 +1,2 @@ + - `M7-5-1`, `RULE-6-8-2` - `FunctionReturnAutomaticVarCondition.ql`, `ReturnReferenceOrPointerToAutomaticLocalVariable.ql`: + - Remove false positives for member and global variables reported under this rule. \ No newline at end of file diff --git a/change_notes/2025-01-21-a7-1-2-remove-function-constexpr.md b/change_notes/2025-01-21-a7-1-2-remove-function-constexpr.md new file mode 100644 index 0000000000..ac9964adc9 --- /dev/null +++ b/change_notes/2025-01-21-a7-1-2-remove-function-constexpr.md @@ -0,0 +1,2 @@ + - `A7-1-2` - `FunctionMissingConstexpr.ql` + - Address false positives by removing the query - the rule is not intended to cover functions. \ No newline at end of file diff --git a/change_notes/2025-01-29-implement-misra-clarifications-change-categories.md b/change_notes/2025-01-29-implement-misra-clarifications-change-categories.md new file mode 100644 index 0000000000..04ef636392 --- /dev/null +++ b/change_notes/2025-01-29-implement-misra-clarifications-change-categories.md @@ -0,0 +1,6 @@ + - `RULE-13-6` - `SizeofOperandWithSideEffect.ql`: + - Changed from Mandatory to Required in implementation of Technical Corrigenda 2. + - `RULE-17-5` - `ArrayFunctionArgumentNumberOfElements.ql`: + - Changed from Advisory to Required in implementation of Technical Corrigenda 2. + - `RULE-21-11` - `StandardHeaderFileTgmathhUsed.ql`: + - Changed from Required to Advisory in implementation of Amendment 3. \ No newline at end of file diff --git a/change_notes/2025-02-06-a3-1-5-audit.md b/change_notes/2025-02-06-a3-1-5-audit.md new file mode 100644 index 0000000000..1f56a25236 --- /dev/null +++ b/change_notes/2025-02-06-a3-1-5-audit.md @@ -0,0 +1,2 @@ + - `A3-1-5` - `NonTrivialNonTemplateFunctionDefinedInsideClassDefinition.ql`: + - Mark this as an `audit` query. As a consequence, it will no longer be run as part of the default query suite for AUTOSAR. It can still be run as part of the `autosar-audit.qls` query suite. The query has been downgraded because the rule allows for functions to be declared in the class body if they were "intended" to be inlined, and that developer intention cannot be determined automatically from the code. \ No newline at end of file diff --git a/change_notes/2025-02-06-m5-3-1-exclude-unknown-type.md b/change_notes/2025-02-06-m5-3-1-exclude-unknown-type.md new file mode 100644 index 0000000000..ba7f50af45 --- /dev/null +++ b/change_notes/2025-02-06-m5-3-1-exclude-unknown-type.md @@ -0,0 +1,2 @@ + - `M5-3-1` - `EachOperandOfTheOperatorOfTheLogicalAndOrTheLogicalOperatorsShallHaveTypeBool.ql`: + - Consistently exclude results in unevaluated contexts associated with uninstantiated templates, for example `noexcept` specifiers and `static_assert`s. \ No newline at end of file diff --git a/change_notes/2025-02-10-improve-perf-a5-1-9.md b/change_notes/2025-02-10-improve-perf-a5-1-9.md new file mode 100644 index 0000000000..5d355bab49 --- /dev/null +++ b/change_notes/2025-02-10-improve-perf-a5-1-9.md @@ -0,0 +1,3 @@ + - `A5-1-9` - `IdenticalLambdaExpressions.ql`: + - Performance has been improved. + - False positives due to repeated invocation of macros containing lambdas have been excluded. \ No newline at end of file diff --git a/change_notes/2025-02-13-deviations.md b/change_notes/2025-02-13-deviations.md new file mode 100644 index 0000000000..fb01cdf596 --- /dev/null +++ b/change_notes/2025-02-13-deviations.md @@ -0,0 +1,13 @@ + - A new in code deviation format has been introduced, using the C/C++ attribute syntax: + ``` + [[codeql::_deviation("")]] + ``` + This can be applied to functions, statements and variables to apply a deviation from the Coding Standards configuration file. The user manual has been updated to describe the new format. + - For those codebases that cannot use standard attributes, we have also introduced a comment based syntax + ``` + // codeql::_deviation() + // codeql::_deviation_next_line() + // codeql::_deviation_begin() + // codeql::_deviation_end() + ``` + Further information is available in the user manual. \ No newline at end of file diff --git a/change_notes/2025-02-13-fix-issue-718.md b/change_notes/2025-02-13-fix-issue-718.md new file mode 100644 index 0000000000..39e499d583 --- /dev/null +++ b/change_notes/2025-02-13-fix-issue-718.md @@ -0,0 +1,2 @@ +- `A2-7-3` - `UndocumentedUserDefinedType.ql` + - Fixes #718. Include trailing characters after group comment endings with ///@{ ... ///@}. diff --git a/change_notes/2025-02-17-iofstream-performance.md b/change_notes/2025-02-17-iofstream-performance.md new file mode 100644 index 0000000000..8e566d3778 --- /dev/null +++ b/change_notes/2025-02-17-iofstream-performance.md @@ -0,0 +1,2 @@ + - `A27-0-3`, `FIO309-C`, `FIO50-CPP`, `RULE-30-0-2` - `InterleavedInputOutputWithoutFlush.ql`, `DoNotAlternatelyIOFromStreamWithoutPositioning.ql`, `InterleavedInputOutputWithoutPosition.ql`, `ReadsAndWritesOnStreamNotSeparatedByPositioning.ql`: + - Reduce evaluation time on complex codebases. \ No newline at end of file diff --git a/change_notes/2025-02-20-rule-22-16-update-aliasing-for-performance.md b/change_notes/2025-02-20-rule-22-16-update-aliasing-for-performance.md new file mode 100644 index 0000000000..80ff92748f --- /dev/null +++ b/change_notes/2025-02-20-rule-22-16-update-aliasing-for-performance.md @@ -0,0 +1,3 @@ + - `RULE-22-16`, `ERR57-CPP`, `A15-1-4` - `MutexObjectsNotAlwaysUnlocked.ql`, `DoNotLeakResourcesWhenHandlingExceptions.ql`, `ValidResourcesStateBeforeThrow.ql`: + - Shared module `ResourceLeakAnalysis.qll` changed to not get aliases recursively for simplicity and improved performance. The recent update to these queries had logic intending to handle the case where an allocation node is an alias of a parent node, and the free operation releases that parent node. However, the behavior was incorrectly defined and not working, and in the presence of performance issues this behavior has been removed. + - (`RULE-22-16` only) The alias behavior has been updated to compare expressions with `HashCons` instead of `GlobalValueNumbering` for higher performance. GVN is more expensive generally, seemed to introduce low performance joins secondarily, and is stricter than `HashCons` in a contravening position, meaning a stricter analysis introduces a higher likelihood of false positives. \ No newline at end of file diff --git a/change_notes/2025-02-25-move-type-related-libraries.md b/change_notes/2025-02-25-move-type-related-libraries.md new file mode 100644 index 0000000000..9f4fbd0bf2 --- /dev/null +++ b/change_notes/2025-02-25-move-type-related-libraries.md @@ -0,0 +1,2 @@ + - All rules using `Type.qll`, `TypeUses.qll`, `Pointers.qll`, `TrivialType.qll`, `VariablyModifiedTypes.qll`: + - Files moved into `cpp/common/types` directory. No external changes in behavior expected. \ No newline at end of file diff --git a/change_notes/2025-02-25-update-macro-deduplication-library.md b/change_notes/2025-02-25-update-macro-deduplication-library.md new file mode 100644 index 0000000000..90b3ef51af --- /dev/null +++ b/change_notes/2025-02-25-update-macro-deduplication-library.md @@ -0,0 +1,4 @@ +- `RULE-2-8` - `UnusedObjectDefinition.ql`, `UnusedObjectDefinitionStrict.ql`: + - Refactor to allow additional parameters in non-macro results for library `DeduplicateMacroResults.qll`. + - Refactor to replace `Location` with `Locatable` in API of library `DeduplicationMacroResults.qll`. + - No observable difference in behavior expected. diff --git a/change_notes/2025-03-04-essential-types-with-explicit-conversions.md b/change_notes/2025-03-04-essential-types-with-explicit-conversions.md new file mode 100644 index 0000000000..aa32044087 --- /dev/null +++ b/change_notes/2025-03-04-essential-types-with-explicit-conversions.md @@ -0,0 +1,2 @@ + - `EssentialType` - for all queries related to essential types: + - Updated the way essential types of expressions with "conversions" (including explicit casts, parenthesis, and implicit conversions such as array-to-pointer conversions) are handled, to get proper essential types when parenthesis, casts, and generics interact. \ No newline at end of file diff --git a/change_notes/2025-03-04-more-accurate-type-comparisons.md b/change_notes/2025-03-04-more-accurate-type-comparisons.md new file mode 100644 index 0000000000..942d76f7af --- /dev/null +++ b/change_notes/2025-03-04-more-accurate-type-comparisons.md @@ -0,0 +1,6 @@ + - `RULE-8-3` - `DeclarationsOfAFunctionSameNameAndType.ql`, `DeclarationsOfAnObjectSameNameAndType.ql`: + - New shared module used to fix false positives for compound types referring to the same basic integer types under a different name, e.g., query will not report for `signed[4]` used in place of `int[4]` as per MISRA spec. + - Now query will report incompatibilities for two functions of the same name with a different number of parameters. + - Query result string updated to not use the word "Compatible," which is confusing, as it may falsely appear that the query is testing for compatibility as defined by C17. + - `RULE-8-4`, `DCL-40C` - `CompatibleDeclarationFunctionDefined.ql`, `CompatibleDeclarationObjectDefined.ql`, `IncomptatibleFunctionDeclarations.ql`: + - New shared module used to fix false positives by updating "compatible" type checks to more closely match the C17 standard. For instance, `int[3]` and `int[]` are compatible declarations (while `int[3]` and `int[4]` are not), and typedefs are now resolved as well. Some false positives may still occur regarding structs from different compilation units. \ No newline at end of file diff --git a/change_notes/2025-03-09-rule-8-7.md b/change_notes/2025-03-09-rule-8-7.md new file mode 100644 index 0000000000..3c3678ca6d --- /dev/null +++ b/change_notes/2025-03-09-rule-8-7.md @@ -0,0 +1,4 @@ + - `RULE-8-7` - `ShouldNotBeDefinedWithExternalLinkage.ql`: + - Remove false positives where the declaration is not defined in the database. + - Remove false positives where the definition and reference are in different translation units. + - Remove false positives where the reference occurs in a header file. \ No newline at end of file diff --git a/change_notes/2025-03-11-various-misra-amendments.md b/change_notes/2025-03-11-various-misra-amendments.md new file mode 100644 index 0000000000..19783fe803 --- /dev/null +++ b/change_notes/2025-03-11-various-misra-amendments.md @@ -0,0 +1,9 @@ + - `DIR-4-9` - `FunctionOverFunctionLikeMacro.ql`: + - Macros with `_Generic` now no longer reported. + - `RULE-1-4` - `EmergentLanguageFeaturesUsed.ql`: + - Ban on usage of `_Generics` removed. + - `RULE-18-6` - `ThreadLocalObjectAddressCopiedToGlobalObject.ql`: + - New query added to detect thread local objects assigned to static storage duration objects. + - `RULE-21-12` - `ExceptionHandlingFeaturesOfFenvhUsed.ql`: + - Added reports for `#include`ing "fenv.h", and for using `fesetenv`, `feupdatenv`, and `fesetround`. + - Report message altered to handle new cases. \ No newline at end of file diff --git a/change_notes/2025-03-26-deviations-suppression.md b/change_notes/2025-03-26-deviations-suppression.md new file mode 100644 index 0000000000..5dcb5e8dba --- /dev/null +++ b/change_notes/2025-03-26-deviations-suppression.md @@ -0,0 +1 @@ + - The `DeviationsSuppression.ql` query has been restored after being incorrectly deleted in a previous release. \ No newline at end of file diff --git a/change_notes/2025-03-27-detect-precision-limit-in-trig-functions.md b/change_notes/2025-03-27-detect-precision-limit-in-trig-functions.md new file mode 100644 index 0000000000..914b25a2a2 --- /dev/null +++ b/change_notes/2025-03-27-detect-precision-limit-in-trig-functions.md @@ -0,0 +1,2 @@ + - `DIR-4-11` - `LowPrecisionPeriodicTrigonometricFunctionCall.ql`: + - New query within rule added to detect calls to periodic trigonometric functions with values outside of pi*k for k that depends on implementation and application precision goals, assuming k=1 for 32 bit floating types and k=10 for 64 bit floating types. diff --git a/change_notes/2025-03-31-allow-atomics-threads-and-threadlocals-in-misra-c.md b/change_notes/2025-03-31-allow-atomics-threads-and-threadlocals-in-misra-c.md new file mode 100644 index 0000000000..b59e04610f --- /dev/null +++ b/change_notes/2025-03-31-allow-atomics-threads-and-threadlocals-in-misra-c.md @@ -0,0 +1,2 @@ + - `RULE-1-4` - `EmergentLanguageFeaturesUsed.ql`: + - Allow usage of atomics, `thread.h`, and `_Thread_local` as per Misra C 2012 Amendment 4. \ No newline at end of file diff --git a/change_notes/2025-04-08-address-cross-compiler-compatibility-in-misra-2023.md b/change_notes/2025-04-08-address-cross-compiler-compatibility-in-misra-2023.md new file mode 100644 index 0000000000..abe4c2bba8 --- /dev/null +++ b/change_notes/2025-04-08-address-cross-compiler-compatibility-in-misra-2023.md @@ -0,0 +1,12 @@ + - `RULE-21-22`, `RULE-21-23` - `TgMathArgumentWithInvalidEssentialType.ql`, `TgMathArgumentsWithDifferingStandardType.ql` + - Change type-generic macro analysis for finding macro parameters to be compatible with gcc, by ignoring early arguments inserted by gcc. + - Change explicit conversion logic to ignore the explicit casts inserted in macro bodies by clang, which previously overruled the argument essential type. + - `RULE-13-2` - `UnsequencedAtomicReads.ql`: + - Handle statement expression implementation of atomic operations in gcc. + - `RULE-21-25` - `InvalidMemoryOrderArgument.ql`: + - Handle case of where the enum `memory_order` is declared via a typedef as an anonymous enum. + - Rewrite how atomically sequenced operations are found; no longer look for builtins or internal functions, instead look for macros with the exact expected name and analyze the macro bodies for the memory sequence parameter. + - `RULE-9-7` - `UninitializedAtomicArgument.ql`: + - Handle gcc case where `atomic_init` is defined is a call to `atomic_store`, and take a more flexible approach to finding the initialized atomic variable. + - `DIR-4-15` - `PossibleMisuseOfUndetectedInfinity.ql`, `PossibleMisuseOfUndetectedNaN.ql`: + - Fix issue when analyzing clang/gcc implementations of floating point classification macros, where analysis incorrectly determined that `x` in `isinf(x)` was guaranteed to be infinite at the call site itself, affecting later analysis involving `x`. \ No newline at end of file diff --git a/change_notes/2025-04-09-new-cert-c-recommendation-query-suite.md b/change_notes/2025-04-09-new-cert-c-recommendation-query-suite.md new file mode 100644 index 0000000000..910433e351 --- /dev/null +++ b/change_notes/2025-04-09-new-cert-c-recommendation-query-suite.md @@ -0,0 +1,9 @@ + - The following query suites have been added or modified for CERT C: + - A new query suite has been created `cert-c-default.qls` to avoid confusion with the CERT C++ query suites. The `cert-default.qls` suite has been deprecated, and will be removed in a future releases, and is replaced by the `cert-c-default.qls` suite. + - The `cert-c-default.qls` suite has been specified as the default for the pack, and will include our most up-to-date coverage for CERT C. + - One new query suite, `cert-c-recommended.qls` has been added to enable running CERT recommendations (as opposed to rules) that will be added in the future. + - The default query suite, `cert-c-default.qls` has been set to exclude CERT recommendations (as opposed to rules) that will be added in the future. + - The following query suites have been added or modified for CERT C++: + - A new query suite has been created `cert-cpp-default.qls` to avoid confusion with the CERT C query suites. The `cert-default.qls` suite has been deprecated, and will be removed in a future releases, and is replaced by the `cert-cpp-default.qls` suite. + - The `cert-cpp-default.qls` suite has been specified as the default for the pack, and will include our most up-to-date coverage for CERT C. + - A new query suite has been created `cert-cpp-single-translation-unit.qls` to avoid confusion with the CERT C query suites. The `cert-single-translation-unit.qls` suite has been deprecated, and will be removed in a future releases, and is replaced by the `cert-cpp-single-translation-unit.qls` suite. \ No newline at end of file diff --git a/change_notes/2025-04-14-update-infinity-nan-detection.md b/change_notes/2025-04-14-update-infinity-nan-detection.md new file mode 100644 index 0000000000..fe484a37fe --- /dev/null +++ b/change_notes/2025-04-14-update-infinity-nan-detection.md @@ -0,0 +1,4 @@ + - `DIR-4-15` - `PossibleMisuseOfUndetectedInfinity.ql`, `PossibleMisuseOfUndetectedNaN.ql`: + - Add logic to suppress NaNs from the CodeQL extractor in the new restricted range analysis, which can have unexpected downstream effects. + - Alter the behavior of floating point class guards (such as `isinf`, `isfinite`, `isnan`) to more correctly reflect the branches that have been guarded. + - Query files have been moved/refactored to share logic across MISRA-C and MISRA-C++; no observable change in behavior from this is expected. \ No newline at end of file diff --git a/change_notes/2025-04-25-improve-type-comparison-performance.md b/change_notes/2025-04-25-improve-type-comparison-performance.md new file mode 100644 index 0000000000..39c462fbf2 --- /dev/null +++ b/change_notes/2025-04-25-improve-type-comparison-performance.md @@ -0,0 +1,6 @@ + - `RULE-8-3`, `RULE-8-4`, `DCL40-C`, `RULE-23-5`: `DeclarationsOfAFunctionSameNameAndType.ql`, `DeclarationsOfAnObjectSameNameAndType.ql`, `CompatibleDeclarationOfFunctionDefined.ql`, `CompatibleDeclarationObjectDefined.ql`, `IncompatibleFunctionDeclarations.ql`, `DangerousDefaultSelectionForPointerInGeneric.ql`: + - Added pragmas to alter join order on function parameter equivalence (names and types). + - Refactored expression which the optimizer was confused by, and compiled into a cartesian product. + - Altered the module `Compatible.qll` to compute equality in two stages. Firstly, all pairs of possible type comparisons (including recursive comparisons) are found, then those pairwise comparisons are evaluated in a second stage. This greatly reduces the number of comparisons and greatly improves performance. + - `RULE-23-5`: `DangerousDefaultSelectionForPointerInGeneric.ql`: + - Altered the module `SimpleAssignment.qll` in accordance with the changes to `Compatible.qll`. \ No newline at end of file diff --git a/change_notes/2025-05-01-cert-extra-props.md b/change_notes/2025-05-01-cert-extra-props.md new file mode 100644 index 0000000000..3244360703 --- /dev/null +++ b/change_notes/2025-05-01-cert-extra-props.md @@ -0,0 +1,2 @@ + - All CERT rules now include additional tags to represent the [Risk Assessment](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RiskAssessment) properties specified on CERT rules. + - In addition, new query suites are included which allow the selection of queries that represent CERT Rules (not Recommendations) for each of the Levels (1-3). These are called `cert--.qls` and can be used either directly in the CodeQL CLI, or via the CodeQL Action. \ No newline at end of file diff --git a/change_notes/2025-05-15-misra-c-2023.md b/change_notes/2025-05-15-misra-c-2023.md new file mode 100644 index 0000000000..defd2ff823 --- /dev/null +++ b/change_notes/2025-05-15-misra-c-2023.md @@ -0,0 +1,4 @@ + - Support for MISRA C 2023 is now completed. + - The default query suites for MISRA C now target MISRA C 2023. + - The user manual has been updated to list MISRA C 2023 as completed. + - The `misra-c-2012-third-edition-with-amendment-2.qls` query suite can be used to run the queries present in MISRA C 2012 (3rd Edition) and Amendment 2. \ No newline at end of file diff --git a/change_notes/2025-06-06-same-source-performance.md b/change_notes/2025-06-06-same-source-performance.md new file mode 100644 index 0000000000..e0dfc36dea --- /dev/null +++ b/change_notes/2025-06-06-same-source-performance.md @@ -0,0 +1,2 @@ + - `FIO39-C`, `FIO50-CPP`, `A27-0-3`, `RULE-30-0-2`: `IOFstreamMissingPositioning.ql`, `InterleavedInputOutputWithoutPosition.ql`, `InterleavedInputOutputWithoutFlush.ql`, `ReadsAndWritesOnStreamNotSeparatedByPositioning.ql`. + - Improved performance for codebases with large numbers of stream or file accesses. \ No newline at end of file diff --git a/change_notes/2025-06-10-a3-9-1-functions.md b/change_notes/2025-06-10-a3-9-1-functions.md new file mode 100644 index 0000000000..8366d2172f --- /dev/null +++ b/change_notes/2025-06-10-a3-9-1-functions.md @@ -0,0 +1,2 @@ + - `A3-9-1` - `VariableWidthIntegerTypesUsed.ql`: + - This query now reports the use of non-fixed width integer types in function return types, with the exception of `char` types and for `main` functions. \ No newline at end of file diff --git a/change_notes/2025-07-11-typo-in-alert-message..md b/change_notes/2025-07-11-typo-in-alert-message..md new file mode 100644 index 0000000000..077f2efb66 --- /dev/null +++ b/change_notes/2025-07-11-typo-in-alert-message..md @@ -0,0 +1,2 @@ +- `SIG30-C`: `CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql` + - Fixed a misspelling of "asynchronous" in the alert message. diff --git a/change_notes/2025-08-15-m5-2-2-virtual-base.md b/change_notes/2025-08-15-m5-2-2-virtual-base.md new file mode 100644 index 0000000000..f57b630ad9 --- /dev/null +++ b/change_notes/2025-08-15-m5-2-2-virtual-base.md @@ -0,0 +1,5 @@ + - `M5-2-2` - `PointerToAVirtualBaseClassCastToAPointer.ql`: + - Report casts where the from or to types are typedefs to virtual base classes or derived classes. + - Report casts to a reference type which is a derived type. + - Report casts where the base class is the parent of a virtual base class. + - The alert message has been updated to refer to the virtual base class derivation. \ No newline at end of file diff --git a/change_notes/2025-08-15-typo-in-alert-message.md b/change_notes/2025-08-15-typo-in-alert-message.md new file mode 100644 index 0000000000..a953f3e86d --- /dev/null +++ b/change_notes/2025-08-15-typo-in-alert-message.md @@ -0,0 +1,2 @@ +- `ENV34-C`, `RULE-21-20`, `RULE-25-5-3`: `DoNotStorePointersReturnedByEnvFunctions.ql`, `CallToSetlocaleInvalidatesOldPointers.ql`, `CallToSetlocaleInvalidatesOldPointersMisra.ql` + - Fixed a misspelling of "subsequent" in the alert message. diff --git a/change_notes/2025-08-18-fix-alert-reporting.md b/change_notes/2025-08-18-fix-alert-reporting.md new file mode 100644 index 0000000000..fc1883ed7a --- /dev/null +++ b/change_notes/2025-08-18-fix-alert-reporting.md @@ -0,0 +1,3 @@ + - `RULE-1-2`, `RULE-23-3`, `RULE-23-5`, `RULE-23-6`: + - Results that occur in nested macro invocations are now reported in the macro that defines the contravening code, rather than the macro which is first expanded. + - Results the occur in arguments to macro invocations are now reported in at the macro invocation site, instead of the macro definition site. \ No newline at end of file diff --git a/change_notes/2025-1-04-misra-c-technical-corrigenda-2.md b/change_notes/2025-1-04-misra-c-technical-corrigenda-2.md new file mode 100644 index 0000000000..6849951810 --- /dev/null +++ b/change_notes/2025-1-04-misra-c-technical-corrigenda-2.md @@ -0,0 +1,12 @@ + - `RULE-8-3` - `DeclarationsOfAFunctionSameNameAndType.ql`: + - Implement new exception, unnamed parameters are not covered by this rule. + - `RULE-10-2` - `AdditionSubtractionOnEssentiallyCharType.ql`: + - Disallow `+` and `-` operations with an essentially char type and other types larger than int type. + - Note, this change affects the essential type of such expressions, which may affect other essential types rules. + - `RULE-18-1`, `M5-0-16` - `PointerAndDerivedPointerMustAddressSameArray.ql`, `PointerAndDerivedPointerAccessDifferentArray.ql`: + - Treat casts to byte pointers as pointers to arrays of the size of the pointed-to type. + - Fix typo in report message, "passed" replaced with "past." + - Suppress results where range analysis appears potentially unreliable. + - `RULE-21-10`, `RULE-25-5-3`, `ENV34-C` - `CallToSetlocaleInvalidatesOldPointers.ql`, `CallToSetlocaleInvalidatesOldPointersMisra.ql`, `DoNotStorePointersReturnedByEnvFunctions.ql`: + - Report usage of returned pointers from `asctime`, `ctime`, during a call to either of the former. + - Report usage of returned pointers from `gmtime`, `localtime`, during a call to either of the former. \ No newline at end of file diff --git a/change_notes/2025-11-19-exclude-raii-style-locks-from-con51-cpp.md b/change_notes/2025-11-19-exclude-raii-style-locks-from-con51-cpp.md new file mode 100644 index 0000000000..f7b9ce4836 --- /dev/null +++ b/change_notes/2025-11-19-exclude-raii-style-locks-from-con51-cpp.md @@ -0,0 +1,2 @@ + - `CON51-CPP` - `EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions.ql`: + - Exclude RAII-style locks from query results, as they cannot be leaked, and are recommended to avoid alerts in this rule. \ No newline at end of file diff --git a/change_notes/2025-7-15-fix-performance-issues-in-2.20.7.md b/change_notes/2025-7-15-fix-performance-issues-in-2.20.7.md new file mode 100644 index 0000000000..a936579a97 --- /dev/null +++ b/change_notes/2025-7-15-fix-performance-issues-in-2.20.7.md @@ -0,0 +1,4 @@ + - `DCL40-C`, `RULE-8-4`: `IncompatibleFunctionDeclarations.ql`, `CompatibleDeclarationFunctionDefined.ql`. + - Fixed performance issues introduced when upgrading to CodeQL `2.20.7` by removing unnecessary check that matching function declarations have matching names. + - `RULE-7-5`: `IncorrectlySizedIntegerConstantMacroArgument.ql`. + - Added a `bindingset` to improve performance when checking if a literal matches the size of an integer constant macro. \ No newline at end of file diff --git a/cpp/autosar/src/codeql-pack.lock.yml b/cpp/autosar/src/codeql-pack.lock.yml index 514e6963d0..a45ea8f438 100644 --- a/cpp/autosar/src/codeql-pack.lock.yml +++ b/cpp/autosar/src/codeql-pack.lock.yml @@ -2,13 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.9.3 + version: 4.0.3 codeql/dataflow: - version: 0.0.4 + version: 2.0.3 + codeql/mad: + version: 1.0.19 + codeql/rangeanalysis: + version: 1.0.19 codeql/ssa: - version: 0.1.5 + version: 1.0.19 codeql/tutorial: - version: 0.1.5 + version: 1.0.19 + codeql/typeflow: + version: 1.0.19 + codeql/typetracking: + version: 2.0.3 codeql/util: - version: 0.1.5 + version: 2.0.6 + codeql/xml: + version: 1.0.19 compiled: false diff --git a/cpp/autosar/src/codingstandards/cpp/CommonTypes.qll b/cpp/autosar/src/codingstandards/cpp/CommonTypes.qll index aafbe85433..3c8ea46b08 100644 --- a/cpp/autosar/src/codingstandards/cpp/CommonTypes.qll +++ b/cpp/autosar/src/codingstandards/cpp/CommonTypes.qll @@ -1,7 +1,7 @@ import cpp as default /* - * Implementations of the C/C++ Fixed Width Types from cstdint.h. + * Implementations of the C/C++ Fixed Width Types from cstdint. * * TODO: Deprecate once this is available in the CodeQL standard library. */ diff --git a/cpp/autosar/src/codingstandards/cpp/HardwareOrProtocolInterface.qll b/cpp/autosar/src/codingstandards/cpp/HardwareOrProtocolInterface.qll index d92a28e477..b0b20b82d9 100644 --- a/cpp/autosar/src/codingstandards/cpp/HardwareOrProtocolInterface.qll +++ b/cpp/autosar/src/codingstandards/cpp/HardwareOrProtocolInterface.qll @@ -3,14 +3,16 @@ import codingstandards.cpp.CommonTypes as CommonTypes abstract class HardwareOrProtocolInterfaceClass extends Class { } +class HardwareOrProtocolInterfaceComment extends Comment { + HardwareOrProtocolInterfaceComment() { + exists(getContents().regexpFind("(?m)^\\s*(//|\\*)\\s*@HardwareOrProtocolInterface\\s*$", _, _)) + } +} + class AnnotatedHardwareOrProtocolInterfaceClass extends HardwareOrProtocolInterfaceClass { AnnotatedHardwareOrProtocolInterfaceClass() { - exists(Comment c, string contents | - c.getCommentedElement() = this.getADeclarationEntry() and - contents = - c.getContents() - .splitAt("\n") - .regexpFind("^\\s*(//|\\*)\\s*@HardwareOrProtocolInterface\\s*$", _, _) + exists(HardwareOrProtocolInterfaceComment c | + c.getCommentedElement() = this.getADeclarationEntry() ) } } diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index dbaf86e72a..4382b97321 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,8 +1,8 @@ name: codeql/autosar-cpp-coding-standards -version: 2.32.0-dev +version: 2.52.0-dev description: AUTOSAR C++14 Guidelines R22-11, R21-11, R20-11, R19-11 and R19-03 suites: codeql-suites license: MIT dependencies: codeql/common-cpp-coding-standards: '*' - codeql/cpp-all: 0.9.3 + codeql/cpp-all: 4.0.3 diff --git a/cpp/autosar/src/rules/A0-4-1/FloatingPointImplementationShallComplyWithIeeeStandard.ql b/cpp/autosar/src/rules/A0-4-1/FloatingPointImplementationShallComplyWithIeeeStandard.ql index 9123e7de2f..0a59b423d0 100644 --- a/cpp/autosar/src/rules/A0-4-1/FloatingPointImplementationShallComplyWithIeeeStandard.ql +++ b/cpp/autosar/src/rules/A0-4-1/FloatingPointImplementationShallComplyWithIeeeStandard.ql @@ -18,7 +18,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.TypeUses +import codingstandards.cpp.types.Uses class NumericLimits extends Class { NumericLimits() { this.hasQualifiedName("std", ["numeric_limits", "__libcpp_numeric_limits"]) } diff --git a/cpp/autosar/src/rules/A1-1-2/CompilerWarningLevelNotInCompliance.ql b/cpp/autosar/src/rules/A1-1-2/CompilerWarningLevelNotInCompliance.ql index bd98ad9162..1499191236 100644 --- a/cpp/autosar/src/rules/A1-1-2/CompilerWarningLevelNotInCompliance.ql +++ b/cpp/autosar/src/rules/A1-1-2/CompilerWarningLevelNotInCompliance.ql @@ -20,13 +20,57 @@ import codingstandards.cpp.autosar predicate hasResponseFileArgument(Compilation c) { c.getAnArgument().matches("@%") } -predicate hasWarningOption(Compilation c) { c.getAnArgument().regexpMatch("-W[\\w=-]+") } +class CompilationWithNoWarnings extends Compilation { + CompilationWithNoWarnings() { + getAnArgument() = "-w" + or + not exists(EnableWarningFlag enableFlag | + this.getAnArgument() = enableFlag and + not exists(DisableWarningFlag disableFlag | + this.getAnArgument() = disableFlag and + enableFlag.getWarningType() = disableFlag.getWarningType() + ) + ) + } +} + +class CompilationArgument extends string { + Compilation compilation; + + CompilationArgument() { this = compilation.getAnArgument() } +} + +/** + * Compiler flags of type -Wfoo or -Wfoo=bar, which enables the `foo` warning. + */ +class EnableWarningFlag extends CompilationArgument { + string warningType; + + EnableWarningFlag() { + warningType = regexpCapture("^-W([\\w-]+)(=.*)?$", 1) and + not this instanceof DisableWarningFlag + } + + string getWarningType() { result = warningType } +} + +/** + * Compiler flags of type -Wno-foo or -Wfoo=0, which disables the `foo` warning + * and overrules -Wfoo. + */ +class DisableWarningFlag extends CompilationArgument { + string warningType; + + DisableWarningFlag() { + warningType = regexpCapture("^-Wno-([\\w-]+)", 1) or + warningType = regexpCapture("^-W([\\w-]+)=0", 1) + } + + string getWarningType() { result = warningType } +} from File f where not isExcluded(f, ToolchainPackage::compilerWarningLevelNotInComplianceQuery()) and - exists(Compilation c | f = c.getAFileCompiled() | - not hasResponseFileArgument(c) and - not hasWarningOption(c) - ) + exists(CompilationWithNoWarnings c | f = c.getAFileCompiled() | not hasResponseFileArgument(c)) select f, "No warning-level options were used in the compilation of '" + f.getBaseName() + "'." diff --git a/cpp/autosar/src/rules/A12-1-1/ExplicitConstructorBaseClassInitialization.ql b/cpp/autosar/src/rules/A12-1-1/ExplicitConstructorBaseClassInitialization.ql index e1aeec46a0..66fe0345dc 100644 --- a/cpp/autosar/src/rules/A12-1-1/ExplicitConstructorBaseClassInitialization.ql +++ b/cpp/autosar/src/rules/A12-1-1/ExplicitConstructorBaseClassInitialization.ql @@ -16,29 +16,11 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.Constructor +import codingstandards.cpp.rules.initializeallvirtualbaseclasses.InitializeAllVirtualBaseClasses -from Constructor c, Class declaringType, Class baseClass, string type -where - not isExcluded(c, InitializationPackage::explicitConstructorBaseClassInitializationQuery()) and - declaringType = c.getDeclaringType() and - ( - declaringType.getABaseClass() = baseClass and type = "" - or - baseClass.(VirtualBaseClass).getAVirtuallyDerivedClass().getADerivedClass+() = declaringType and - type = " virtual" - ) and - // There is not an initializer on the constructor for this particular base class - not exists(ConstructorBaseClassInit init | - c.getAnInitializer() = init and - init.getInitializedClass() = baseClass and - not init.isCompilerGenerated() - ) and - // Must be a defined constructor - c.hasDefinition() and - // Not a compiler-generated constructor - not c.isCompilerGenerated() and - // Not a defaulted constructor - not c.isDefaulted() -select c, "Constructor for $@ does not explicitly call constructor for" + type + " base class $@.", - declaringType, declaringType.getSimpleName(), baseClass, baseClass.getSimpleName() +class ExplicitConstructorBaseClassInitializationQuery extends InitializeAllVirtualBaseClassesSharedQuery +{ + ExplicitConstructorBaseClassInitializationQuery() { + this = InitializationPackage::explicitConstructorBaseClassInitializationQuery() + } +} diff --git a/cpp/autosar/src/rules/A12-8-4/MoveConstructorUsesCopySemantics.ql b/cpp/autosar/src/rules/A12-8-4/MoveConstructorUsesCopySemantics.ql index 4996afd34e..a71d49d844 100644 --- a/cpp/autosar/src/rules/A12-8-4/MoveConstructorUsesCopySemantics.ql +++ b/cpp/autosar/src/rules/A12-8-4/MoveConstructorUsesCopySemantics.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType /** * A literal with no values. diff --git a/cpp/autosar/src/rules/A12-8-5/CopyAssignmentAndAMoveHandleSelfAssignment.ql b/cpp/autosar/src/rules/A12-8-5/CopyAssignmentAndAMoveHandleSelfAssignment.ql index a2ce643784..9697176711 100644 --- a/cpp/autosar/src/rules/A12-8-5/CopyAssignmentAndAMoveHandleSelfAssignment.ql +++ b/cpp/autosar/src/rules/A12-8-5/CopyAssignmentAndAMoveHandleSelfAssignment.ql @@ -17,43 +17,11 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.Operator +import codingstandards.cpp.rules.copyandmoveassignmentsshallhandleselfassignment.CopyAndMoveAssignmentsShallHandleSelfAssignment -predicate isUserCopyOrUserMove(Operator o) { - o instanceof UserCopyOperator or - o instanceof UserMoveOperator +class CopyAssignmentAndAMoveHandleSelfAssignmentQuery extends CopyAndMoveAssignmentsShallHandleSelfAssignmentSharedQuery +{ + CopyAssignmentAndAMoveHandleSelfAssignmentQuery() { + this = OperatorInvariantsPackage::copyAssignmentAndAMoveHandleSelfAssignmentQuery() + } } - -predicate callsStdSwap(Function f) { - exists(FunctionCall fc | - fc.getTarget().hasGlobalOrStdName("swap") and - fc.getEnclosingFunction() = f - ) -} - -predicate callsNoExceptSwap(Operator o) { - exists(Function f, FunctionCall fc | - callsStdSwap(f) and - fc.getEnclosingFunction() = o and - fc.getTarget() = f - ) -} - -predicate checksForSelfAssignment(Operator o) { - exists(IfStmt i, ComparisonOperation c | - i.getEnclosingFunction() = o and - i.getCondition() = c and - ( - c.getLeftOperand().toString() = "this" or - c.getRightOperand().toString() = "this" - ) - ) -} - -from Operator o -where - not isExcluded(o, OperatorInvariantsPackage::copyAssignmentAndAMoveHandleSelfAssignmentQuery()) and - isUserCopyOrUserMove(o) and - not callsNoExceptSwap(o) and - not checksForSelfAssignment(o) -select o, "User defined copy or user defined move does not handle self-assignment correctly." diff --git a/cpp/autosar/src/rules/A13-1-2/UserDefinedLiteralOperatorSuffixViolation.ql b/cpp/autosar/src/rules/A13-1-2/UserDefinedLiteralOperatorSuffixViolation.ql index 7fe8bcdbe7..c739035596 100644 --- a/cpp/autosar/src/rules/A13-1-2/UserDefinedLiteralOperatorSuffixViolation.ql +++ b/cpp/autosar/src/rules/A13-1-2/UserDefinedLiteralOperatorSuffixViolation.ql @@ -15,9 +15,9 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.UserDefinedLiteral +import codingstandards.cpp.UserDefinedLiteral as udl -from UserDefinedLiteral udl +from udl::UserDefinedLiteral udl where not isExcluded(udl, NamingPackage::userDefinedLiteralOperatorSuffixViolationQuery()) and not udl.hasCompliantSuffix() diff --git a/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallNotHaveSideEffects.ql b/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallNotHaveSideEffects.ql index 0cbb9f101e..b41a57f900 100644 --- a/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallNotHaveSideEffects.ql +++ b/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallNotHaveSideEffects.ql @@ -14,11 +14,11 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.UserDefinedLiteral +import codingstandards.cpp.UserDefinedLiteral as udl import codingstandards.cpp.SideEffect import codingstandards.cpp.sideeffect.DefaultEffects -from UserDefinedLiteral udl, SideEffect e +from udl::UserDefinedLiteral udl, SideEffect e where not isExcluded(udl, SideEffects2Package::userDefinedLiteralsOperatorsShallNotHaveSideEffectsQuery()) and diff --git a/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql b/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql index b010e616cb..4593065e01 100644 --- a/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql +++ b/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql @@ -14,12 +14,12 @@ */ import cpp -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import codingstandards.cpp.autosar -import codingstandards.cpp.UserDefinedLiteral +import codingstandards.cpp.UserDefinedLiteral as udl import codingstandards.cpp.SideEffect -from UserDefinedLiteral udl, Expr retExpr +from udl::UserDefinedLiteral udl, Expr retExpr where not isExcluded(udl, SideEffects2Package::userDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParametersQuery()) and diff --git a/cpp/autosar/src/rules/A13-2-1/AssignmentOperatorReturnThis.ql b/cpp/autosar/src/rules/A13-2-1/AssignmentOperatorReturnThis.ql index ae0acc3bb5..4e6b7d6f0c 100644 --- a/cpp/autosar/src/rules/A13-2-1/AssignmentOperatorReturnThis.ql +++ b/cpp/autosar/src/rules/A13-2-1/AssignmentOperatorReturnThis.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.Operator -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow predicate returnsThisPointer(UserAssignmentOperator o) { exists(PointerDereferenceExpr p, ThisExpr t, ReturnStmt r | diff --git a/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql b/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql index 393c1222fd..7b31ae5d9e 100644 --- a/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql +++ b/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql @@ -14,10 +14,12 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.FunctionEquivalence class Candidate extends TemplateFunction { Candidate() { - this.getAParameter().getType().(RValueReferenceType).getBaseType() instanceof TemplateParameter + this.getAParameter().getType().(RValueReferenceType).getBaseType() instanceof + TypeTemplateParameter } } @@ -29,28 +31,18 @@ where OperatorsPackage::functionThatContainsForwardingReferenceAsItsArgumentOverloadedQuery()) and not f.isDeleted() and f = c.getAnOverload() and + // Ensure the functions are not equivalent to each other (refer #796). + not f = getAnEquivalentFunction(c) and // allow for overloading with different number of parameters, because there is no // confusion on what function will be called. f.getNumberOfParameters() = c.getNumberOfParameters() and - //build a dynamic select statement that guarantees to read that the overloading function is the explicit one - if - (f instanceof CopyConstructor or f instanceof MoveConstructor) and - f.isCompilerGenerated() - then ( - ( - f instanceof CopyConstructor and - msg = "implicit copy constructor" - or - f instanceof MoveConstructor and - msg = "implicit move constructor" - ) and - firstMsgSegment = " with a forwarding reference parameter " and - overloaded = f and - overload = c - ) else ( - msg = "function with a forwarding reference parameter" and - firstMsgSegment = " " and - overloaded = c and - overload = f - ) + //ignore implicit copy and move constructor overloads + not ( + f.isCompilerGenerated() and + (f instanceof CopyConstructor or f instanceof MoveConstructor) + ) and + msg = "function with a forwarding reference parameter" and + firstMsgSegment = " " and + overloaded = c and + overload = f select overload, "Function" + firstMsgSegment + "overloads a $@.", overloaded, msg diff --git a/cpp/autosar/src/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.ql b/cpp/autosar/src/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.ql index 4a81e32b0f..a8fb1ace66 100644 --- a/cpp/autosar/src/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.ql +++ b/cpp/autosar/src/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.ql @@ -15,10 +15,10 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.TypeUses +import codingstandards.cpp.types.Uses import codingstandards.cpp.Operator -predicate templateDefinitionMentionsTypeParameter(Declaration d, TemplateParameter tp) { +predicate templateDefinitionMentionsTypeParameter(Declaration d, TypeTemplateParameter tp) { exists(Type t | ( // direct reference, e.g., fields. @@ -50,36 +50,36 @@ predicate templateDefinitionMentionsTypeParameter(Declaration d, TemplateParamet } /** - * The set of `TemplateParameter` references within an `Enum`. + * The set of `TypeTemplateParameter` references within an `Enum`. */ -TemplateParameter enumTemplateReferences(Enum e) { +TypeTemplateParameter enumTemplateReferences(Enum e) { templateDefinitionMentionsTypeParameter(e.getADeclaration(), result) or result = e.getExplicitUnderlyingType() } /** - * The set of `TemplateParameter` references within an `Class`. + * The set of `TypeTemplateParameter` references within an `Class`. */ -TemplateParameter classTemplateReferences(Class c) { +TypeTemplateParameter classTemplateReferences(Class c) { templateDefinitionMentionsTypeParameter(c.getAMember(), result) or c.getADerivation().getBaseType() = result } /** - * The set of all of the `TemplateParameter`s referenced by a `EnumConstant`. + * The set of all of the `TypeTemplateParameter`s referenced by a `EnumConstant`. */ -TemplateParameter enumConstantTemplateReferences(EnumConstant ec) { +TypeTemplateParameter enumConstantTemplateReferences(EnumConstant ec) { templateDefinitionMentionsTypeParameter(ec.getDeclaringType(), result) } /** - * The set of all `TemplateParameter`s referenced by a `Function`. + * The set of all `TypeTemplateParameter`s referenced by a `Function`. */ -TemplateParameter functionTemplateReferences(Function mf) { +TypeTemplateParameter functionTemplateReferences(Function mf) { // the type of the function - exists(TemplateParameter tp | + exists(TypeTemplateParameter tp | result = tp and ( mf.getType().refersTo(result) @@ -115,10 +115,10 @@ TemplateParameter functionTemplateReferences(Function mf) { } /** - * The set of all `TemplateParameters` available as arguments to the declaring + * The set of all `TypeTemplateParameters` available as arguments to the declaring * element of some `Declarations`. */ -TemplateParameter templateParametersOfDeclaringTemplateClass(Declaration d) { +TypeTemplateParameter templateParametersOfDeclaringTemplateClass(Declaration d) { result = d.getDeclaringType().getATemplateArgument() } @@ -149,7 +149,7 @@ where not d instanceof UserNegationOperator and // for each declaration within a template class get the // template parameters of the declaring class - not exists(TemplateParameter t | + not exists(TypeTemplateParameter t | t = templateParametersOfDeclaringTemplateClass(d) and // and require that the declaration depends on at least // one of those template parameters. @@ -167,7 +167,10 @@ where mf = c.getAMemberFunction() and not mf.isCompilerGenerated() and not exists(mf.getBlock()) ) ) - ) + ) and + // Omit using alias (cf. https://github.com/github/codeql-coding-standards/issues/739) + // Exclude Using alias which refer directly to a TypeParameter + not d.(UsingAliasTypedefType).getBaseType() instanceof TypeTemplateParameter select d, "Member " + d.getName() + " template class does not use any of template arguments of its $@.", d.getDeclaringType(), "declaring type" diff --git a/cpp/autosar/src/rules/A14-5-3/NonMemberGenericOperatorCondition.ql b/cpp/autosar/src/rules/A14-5-3/NonMemberGenericOperatorCondition.ql index a2211368ed..c2d28d3ef9 100644 --- a/cpp/autosar/src/rules/A14-5-3/NonMemberGenericOperatorCondition.ql +++ b/cpp/autosar/src/rules/A14-5-3/NonMemberGenericOperatorCondition.ql @@ -18,7 +18,7 @@ import codingstandards.cpp.autosar class NonMemberGenericOperator extends TemplateFunction { NonMemberGenericOperator() { this instanceof Operator and - exists(TemplateParameter tp, Type pType | + exists(TypeTemplateParameter tp, Type pType | pType = getAParameter().getType().getUnspecifiedType() //Parameter Type | pType = tp or diff --git a/cpp/autosar/src/rules/A14-8-2/ExplicitSpecializationsOfFunctionTemplatesUsed.ql b/cpp/autosar/src/rules/A14-8-2/ExplicitSpecializationsOfFunctionTemplatesUsed.ql index e53b532493..86218a47d6 100644 --- a/cpp/autosar/src/rules/A14-8-2/ExplicitSpecializationsOfFunctionTemplatesUsed.ql +++ b/cpp/autosar/src/rules/A14-8-2/ExplicitSpecializationsOfFunctionTemplatesUsed.ql @@ -16,8 +16,11 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.functiontemplatesexplicitlyspecialized.FunctionTemplatesExplicitlySpecialized -from FunctionTemplateSpecialization f -where not isExcluded(f, TemplatesPackage::explicitSpecializationsOfFunctionTemplatesUsedQuery()) -select f, "Specialization of function template from primary template located in $@.", - f.getPrimaryTemplate(), f.getPrimaryTemplate().getFile().getBaseName() +class ExplicitSpecializationsOfFunctionTemplatesUsedQuery extends FunctionTemplatesExplicitlySpecializedSharedQuery +{ + ExplicitSpecializationsOfFunctionTemplatesUsedQuery() { + this = TemplatesPackage::explicitSpecializationsOfFunctionTemplatesUsedQuery() + } +} diff --git a/cpp/autosar/src/rules/A15-1-2/PointerExceptionObject.ql b/cpp/autosar/src/rules/A15-1-2/PointerExceptionObject.ql index 348e02609c..b2f101082f 100644 --- a/cpp/autosar/src/rules/A15-1-2/PointerExceptionObject.ql +++ b/cpp/autosar/src/rules/A15-1-2/PointerExceptionObject.ql @@ -15,10 +15,8 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.exceptionobjecthavepointertype.ExceptionObjectHavePointerType -from Expr thrownExpr -where - not isExcluded(thrownExpr, Exceptions1Package::pointerExceptionObjectQuery()) and - thrownExpr = any(ThrowExpr te).getExpr() and - thrownExpr.getType().getUnspecifiedType() instanceof PointerType -select thrownExpr, "Exception object with pointer type " + thrownExpr.getType() + " is thrown here." +class PointerExceptionObjectQuery extends ExceptionObjectHavePointerTypeSharedQuery { + PointerExceptionObjectQuery() { this = Exceptions1Package::pointerExceptionObjectQuery() } +} diff --git a/cpp/autosar/src/rules/A15-1-3/ThrownExceptionsShouldBeUnique.ql b/cpp/autosar/src/rules/A15-1-3/ThrownExceptionsShouldBeUnique.ql index 1459b79b43..97e9133a7a 100644 --- a/cpp/autosar/src/rules/A15-1-3/ThrownExceptionsShouldBeUnique.ql +++ b/cpp/autosar/src/rules/A15-1-3/ThrownExceptionsShouldBeUnique.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.exceptions.ExceptionFlow -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.valuenumbering.HashCons /** Find a value which defines the exception thrown by the `DirectThrowExpr`, if any. */ diff --git a/cpp/autosar/src/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.ql b/cpp/autosar/src/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.ql index 9fcd8fa609..1b3a3cfed2 100644 --- a/cpp/autosar/src/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.ql +++ b/cpp/autosar/src/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.ql @@ -15,7 +15,7 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.autosar import codingstandards.cpp.exceptions.ExceptionFlow import codingstandards.cpp.exceptions.ExceptionSpecifications diff --git a/cpp/autosar/src/rules/A15-4-2/NoExceptFunctionThrows.ql b/cpp/autosar/src/rules/A15-4-2/NoExceptFunctionThrows.ql index 0c5bbb6011..169b5fc8f3 100644 --- a/cpp/autosar/src/rules/A15-4-2/NoExceptFunctionThrows.ql +++ b/cpp/autosar/src/rules/A15-4-2/NoExceptFunctionThrows.ql @@ -15,25 +15,8 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.exceptions.ExceptionFlow -import ExceptionPathGraph -import codingstandards.cpp.exceptions.ExceptionSpecifications +import codingstandards.cpp.rules.noexceptfunctionshouldnotpropagatetothecaller.NoexceptFunctionShouldNotPropagateToTheCaller -class NoExceptThrowingFunction extends ExceptionThrowingFunction { - NoExceptThrowingFunction() { - // Can exit with an exception - exists(getAFunctionThrownType(_, _)) and - // But is marked noexcept(true) or equivalent - isNoExceptTrue(this) - } +class NoExceptFunctionThrowsQuery extends NoexceptFunctionShouldNotPropagateToTheCallerSharedQuery { + NoExceptFunctionThrowsQuery() { this = Exceptions1Package::noExceptFunctionThrowsQuery() } } - -from - NoExceptThrowingFunction f, ExceptionFlowNode exceptionSource, ExceptionFlowNode functionNode, - ExceptionType exceptionType -where - not isExcluded(f, Exceptions1Package::noExceptFunctionThrowsQuery()) and - f.hasExceptionFlow(exceptionSource, functionNode, exceptionType) -select f, exceptionSource, functionNode, - "Function " + f.getName() + " is declared noexcept(true) but can throw exceptions of type " + - exceptionType.getExceptionName() + "." diff --git a/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql b/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql index 7701a8a1ea..058a77175f 100644 --- a/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql +++ b/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql @@ -19,15 +19,51 @@ import codingstandards.cpp.autosar import codingstandards.cpp.exceptions.ExceptionSpecifications import codingstandards.cpp.exceptions.ExceptionFlow +// These functions have a noexcept specification that could not be resolved +// to noexcept(true). So either, they are noexcept(false) functions which +// means, they can throw an exception OR they have an expression which +// could not be resolved to "true" or "false". Even in this case, lets +// be more conservative and assume they may thrown an exception. +class FunctionWithUnknownNoExcept extends Function { + FunctionWithUnknownNoExcept() { + // Exists a noexcept specification but not noexcept(true) + exists(this.getADeclarationEntry().getNoExceptExpr()) and + not isNoExceptTrue(this) + } +} + +// This predicate checks if a function can call to other functions +// that may have a noexcept specification which cannot be resolved to +// noexcept(true). +predicate mayCallThrowingFunctions(Function f) { + // Exists a call in this function + exists(Call fc | + fc.getEnclosingFunction() = f and + ( + // Either this call is to a function with an unknown noexcept OR + fc.getTarget() instanceof FunctionWithUnknownNoExcept + or + // That function can further have calls to unknown noexcept functions. + mayCallThrowingFunctions(fc.getTarget()) + ) + ) +} + from Function f where - not isExcluded(f, Exceptions1Package::missingNoExceptQuery()) and + not isExcluded(f.getADeclarationEntry(), Exceptions1Package::missingNoExceptQuery()) and // No thrown exceptions not exists(getAFunctionThrownType(f, _)) and // But not marked noexcept(true) not isNoExceptTrue(f) and // Not explicitly marked noexcept(false) not isNoExceptExplicitlyFalse(f) and + // Not having a noexcept specification that + // could not be computed as true or false above. + not exists(f.getADeclarationEntry().getNoExceptExpr()) and + // Not calling function(s) which have a noexcept specification that + // could not be computed as true. + not mayCallThrowingFunctions(f) and // Not compiler generated not f.isCompilerGenerated() and // The function is defined in this database diff --git a/cpp/autosar/src/rules/A18-1-2/VectorboolSpecializationUsed.ql b/cpp/autosar/src/rules/A18-1-2/VectorboolSpecializationUsed.ql index 2d94fde98c..5bbe181927 100644 --- a/cpp/autosar/src/rules/A18-1-2/VectorboolSpecializationUsed.ql +++ b/cpp/autosar/src/rules/A18-1-2/VectorboolSpecializationUsed.ql @@ -17,23 +17,10 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.StdNamespace +import codingstandards.cpp.rules.vectorshouldnotbespecializedwithbool.VectorShouldNotBeSpecializedWithBool -predicate isVectorBool(ClassTemplateInstantiation c) { - c.getNamespace() instanceof StdNS and - c.getTemplateArgument(0) instanceof BoolType and - c.getSimpleName() = "vector" +class VectorboolSpecializationUsedQuery extends VectorShouldNotBeSpecializedWithBoolSharedQuery { + VectorboolSpecializationUsedQuery() { + this = BannedTypesPackage::vectorboolSpecializationUsedQuery() + } } - -predicate isUsingVectorBool(ClassTemplateInstantiation c) { - isVectorBool(c) or - isUsingVectorBool(c.getTemplateArgument(_)) -} - -from Variable v, ClassTemplateInstantiation c -where - v.getUnderlyingType() = c and - not v.isFromTemplateInstantiation(_) and - isUsingVectorBool(c) and - not isExcluded(v, BannedTypesPackage::vectorboolSpecializationUsedQuery()) -select v, "Use of std::vector specialization." diff --git a/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql b/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql index 842dc14390..353c985137 100644 --- a/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql +++ b/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SmartPointers -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import SingleObjectSmartPointerArrayConstructionFlow::PathGraph class AutosarSmartPointerArraySpecialisation extends AutosarSmartPointer { diff --git a/cpp/autosar/src/rules/A18-5-2/DoNotUseNonPlacementNew.ql b/cpp/autosar/src/rules/A18-5-2/DoNotUseNonPlacementNew.ql index 082827f5bb..3cfccbf11e 100644 --- a/cpp/autosar/src/rules/A18-5-2/DoNotUseNonPlacementNew.ql +++ b/cpp/autosar/src/rules/A18-5-2/DoNotUseNonPlacementNew.ql @@ -15,7 +15,6 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow from NewOrNewArrayExpr na where diff --git a/cpp/autosar/src/rules/A18-5-4/GlobalSizedOperatorDeleteNotDefined.ql b/cpp/autosar/src/rules/A18-5-4/GlobalSizedOperatorDeleteNotDefined.ql index 7819cfad4d..274b18301c 100644 --- a/cpp/autosar/src/rules/A18-5-4/GlobalSizedOperatorDeleteNotDefined.ql +++ b/cpp/autosar/src/rules/A18-5-4/GlobalSizedOperatorDeleteNotDefined.ql @@ -15,14 +15,11 @@ import cpp import codingstandards.cpp.autosar -import OperatorDelete +import codingstandards.cpp.rules.globalsizedoperatordeletenotdefined.GlobalSizedOperatorDeleteNotDefined -from OperatorDelete unsized_delete -where - not isExcluded(unsized_delete, DeclarationsPackage::globalSizedOperatorDeleteNotDefinedQuery()) and - not unsized_delete.isSizeDelete() and - not exists(OperatorDelete od | unsized_delete.isNoThrowDelete() = od.isNoThrowDelete() | - od.isSizeDelete() - ) -select unsized_delete, - "Unsized function '" + unsized_delete.getName() + "' defined globally without sized version." +class GlobalSizedOperatorDeleteNotDefinedQuery extends GlobalSizedOperatorDeleteNotDefinedSharedQuery +{ + GlobalSizedOperatorDeleteNotDefinedQuery() { + this = DeclarationsPackage::globalSizedOperatorDeleteNotDefinedQuery() + } +} diff --git a/cpp/autosar/src/rules/A18-5-4/GlobalUnsizedOperatorDeleteNotDefined.ql b/cpp/autosar/src/rules/A18-5-4/GlobalUnsizedOperatorDeleteNotDefined.ql index 2c96660704..2bd0ada800 100644 --- a/cpp/autosar/src/rules/A18-5-4/GlobalUnsizedOperatorDeleteNotDefined.ql +++ b/cpp/autosar/src/rules/A18-5-4/GlobalUnsizedOperatorDeleteNotDefined.ql @@ -15,14 +15,11 @@ import cpp import codingstandards.cpp.autosar -import OperatorDelete +import codingstandards.cpp.rules.globalunsizedoperatordeletenotdefined.GlobalUnsizedOperatorDeleteNotDefined -from OperatorDelete sized_delete -where - not isExcluded(sized_delete, DeclarationsPackage::globalUnsizedOperatorDeleteNotDefinedQuery()) and - sized_delete.isSizeDelete() and - not exists(OperatorDelete od | sized_delete.isNoThrowDelete() = od.isNoThrowDelete() | - not od.isSizeDelete() - ) -select sized_delete, - "Sized function '" + sized_delete.getName() + "' defined globally without unsized version." +class GlobalUnsizedOperatorDeleteNotDefinedQuery extends GlobalUnsizedOperatorDeleteNotDefinedSharedQuery +{ + GlobalUnsizedOperatorDeleteNotDefinedQuery() { + this = DeclarationsPackage::globalUnsizedOperatorDeleteNotDefinedQuery() + } +} diff --git a/cpp/autosar/src/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.ql b/cpp/autosar/src/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.ql index 7b68030476..cf83f055bd 100644 --- a/cpp/autosar/src/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.ql +++ b/cpp/autosar/src/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import codingstandards.cpp.standardlibrary.Utility /* diff --git a/cpp/autosar/src/rules/A18-9-2/ForwardingValuesToOtherFunctions.ql b/cpp/autosar/src/rules/A18-9-2/ForwardingValuesToOtherFunctions.ql index b0dd714209..72de362ebc 100644 --- a/cpp/autosar/src/rules/A18-9-2/ForwardingValuesToOtherFunctions.ql +++ b/cpp/autosar/src/rules/A18-9-2/ForwardingValuesToOtherFunctions.ql @@ -14,20 +14,12 @@ */ import cpp -import codingstandards.cpp.standardlibrary.Utility import codingstandards.cpp.autosar +import codingstandards.cpp.rules.forwardingreferencesandforwardnotusedtogether.ForwardingReferencesAndForwardNotUsedTogether -from FunctionCall c, Parameter a, string message -where - not isExcluded(c, MoveForwardPackage::forwardingValuesToOtherFunctionsQuery()) and - a.getAnAccess() = c.getAnArgument() and - ( - c instanceof StdMoveCall and - a instanceof ForwardParameter and - message = "Function `std::forward` should be used for forwarding the forward reference $@." - or - c instanceof StdForwardCall and - a instanceof ConsumeParameter and - message = "Function `std::move` should be used for forwarding rvalue reference $@." - ) -select c, message, a, a.getName() +class ForwardingValuesToOtherFunctionsQuery extends ForwardingReferencesAndForwardNotUsedTogetherSharedQuery +{ + ForwardingValuesToOtherFunctionsQuery() { + this = MoveForwardPackage::forwardingValuesToOtherFunctionsQuery() + } +} diff --git a/cpp/autosar/src/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.ql b/cpp/autosar/src/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.ql index d87366c624..a3acf916ec 100644 --- a/cpp/autosar/src/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.ql +++ b/cpp/autosar/src/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.standardlibrary.Utility -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow from StdForwardCall f, Access a where diff --git a/cpp/autosar/src/rules/A2-10-4/IdentifierNameOfStaticNonMemberObjectReusedInNamespace.ql b/cpp/autosar/src/rules/A2-10-4/IdentifierNameOfStaticNonMemberObjectReusedInNamespace.ql index e04bb89cfa..79e17305fb 100644 --- a/cpp/autosar/src/rules/A2-10-4/IdentifierNameOfStaticNonMemberObjectReusedInNamespace.ql +++ b/cpp/autosar/src/rules/A2-10-4/IdentifierNameOfStaticNonMemberObjectReusedInNamespace.ql @@ -22,7 +22,7 @@ class CandidateVariable extends Variable { isStatic() and not this instanceof MemberVariable and //exclude partially specialized template variables - not exists(TemplateVariable v | this = v.getAnInstantiation()) + not this.isSpecialization() } } diff --git a/cpp/autosar/src/rules/A2-13-1/EscapeSequenceOutsideISO.ql b/cpp/autosar/src/rules/A2-13-1/EscapeSequenceOutsideISO.ql index d8382f51c8..0f1d9a3271 100644 --- a/cpp/autosar/src/rules/A2-13-1/EscapeSequenceOutsideISO.ql +++ b/cpp/autosar/src/rules/A2-13-1/EscapeSequenceOutsideISO.ql @@ -16,11 +16,8 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.backslashcharactermisuse.BackslashCharacterMisuse -from StringLiteral l, string es -where - not isExcluded(l, LiteralsPackage::escapeSequenceOutsideISOQuery()) and - es = l.getANonStandardEscapeSequence(_, _) and - // Exclude universal-character-names, which begin with \u or \U - not es.toLowerCase().matches("\\u") -select l, "This literal contains the non-standard escape sequence " + es + "." +class EscapeSequenceOutsideISOQuery extends BackslashCharacterMisuseSharedQuery { + EscapeSequenceOutsideISOQuery() { this = LiteralsPackage::escapeSequenceOutsideISOQuery() } +} diff --git a/cpp/autosar/src/rules/A2-3-1/InvalidCharacterInComment.ql b/cpp/autosar/src/rules/A2-3-1/InvalidCharacterInComment.ql index a3090003d3..fdcc74b115 100644 --- a/cpp/autosar/src/rules/A2-3-1/InvalidCharacterInComment.ql +++ b/cpp/autosar/src/rules/A2-3-1/InvalidCharacterInComment.ql @@ -18,21 +18,23 @@ import cpp import codingstandards.cpp.autosar -bindingset[s] -string getCharOutsideBasicSourceCharSet(string s) { - result = s.regexpFind("[\\u0000-\\u007f]", _, _) and - not result.regexpMatch("[\\p{Alnum}\\p{Space}_{}\\[\\]#()<>%:;.?*+-/^&|~!=,\\\\\"'@]") - or - result = s.regexpFind("[\\u00c0-\\u00df][\\u0080-\\u00bf]", _, _) - or - result = s.regexpFind("[\\u00e0-\\u00ef][\\u0080-\\u00bf]{2}", _, _) - or - result = s.regexpFind("[\\u00f0-\\u00f7][\\u0080-\\u00bf]{3}", _, _) +string getCharOutsideBasicSourceCharSet(Comment c) { + exists(string s | s = c.getContents() | + result = + s.regexpFind("(?![\\p{Alnum}\\p{Space}_{}\\[\\]#()<>%:;.?*+-/^&|~!=,\\\\\"'@])[\\u0000-\\u007f]", + _, _) + or + result = s.regexpFind("[\\u00c0-\\u00df][\\u0080-\\u00bf]", _, _) + or + result = s.regexpFind("[\\u00e0-\\u00ef][\\u0080-\\u00bf]{2}", _, _) + or + result = s.regexpFind("[\\u00f0-\\u00f7][\\u0080-\\u00bf]{3}", _, _) + ) } from Comment c, string ch where not isExcluded(c, NamingPackage::invalidCharacterInCommentQuery()) and - ch = getCharOutsideBasicSourceCharSet(c.getContents()) + ch = getCharOutsideBasicSourceCharSet(c) select c, "Comment uses the character '" + ch + "' that is outside the language basic character set." diff --git a/cpp/autosar/src/rules/A2-7-1/SingleLineCommentEndsWithSlash.ql b/cpp/autosar/src/rules/A2-7-1/SingleLineCommentEndsWithSlash.ql index adbb1dccea..cd7d7c42cd 100644 --- a/cpp/autosar/src/rules/A2-7-1/SingleLineCommentEndsWithSlash.ql +++ b/cpp/autosar/src/rules/A2-7-1/SingleLineCommentEndsWithSlash.ql @@ -17,9 +17,10 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.linesplicingusedincomments.LineSplicingUsedInComments -from CppStyleComment c -where - not isExcluded(c, CommentsPackage::singleLineCommentEndsWithSlashQuery()) and - exists(c.getContents().regexpFind("\\\n", _, _)) -select c, "C++ comment includes \\ as the last character of a line" +class SingleLineCommentEndsWithSlashQuery extends LineSplicingUsedInCommentsSharedQuery { + SingleLineCommentEndsWithSlashQuery() { + this = CommentsPackage::singleLineCommentEndsWithSlashQuery() + } +} diff --git a/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql b/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql index a8bfe3b361..020d1d4ee1 100644 --- a/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql +++ b/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql @@ -25,6 +25,39 @@ private predicate isInFunctionScope(Declaration d) { isInFunctionScope(d.getDeclaringType()) } +private string doxygenCommentGroupStrings(boolean opening) { + opening = true and result = ["///@{", "/**@{*/"] + or + opening = false and result = ["///@}%", "/**@}*/"] +} + +pragma[inline] +private predicate isBetweenDoxygenCommentGroup( + Location loc, Comment opening, Comment body, Comment closing +) { + // All in the same file + loc.getFile() = opening.getLocation().getFile() and + loc.getFile() = closing.getLocation().getFile() and + loc.getFile() = body.getLocation().getFile() and + // The comments are doxygen comments + opening.getContents().matches(doxygenCommentGroupStrings(true)) and + closing.getContents().matches(doxygenCommentGroupStrings(false)) and + // The closing comment is after the opening comment + opening.getLocation().getStartLine() < closing.getLocation().getStartLine() and + // The `body` comment directly precedes the opening comment + body.getLocation().getEndLine() = opening.getLocation().getStartLine() - 1 and + // There are no other opening/closing comment pairs between the opening and closing comments + not exists(Comment c | + c.getContents().matches(doxygenCommentGroupStrings(_)) and + c.getLocation().getStartLine() > opening.getLocation().getStartLine() and + c.getLocation().getStartLine() < closing.getLocation().getStartLine() + ) and + // `loc` is between the opening and closing comments and after the body comment + loc.getStartLine() > opening.getLocation().getStartLine() and + loc.getStartLine() < closing.getLocation().getStartLine() and + loc.getStartLine() > body.getLocation().getEndLine() +} + /** * A declaration which is required to be preceded by documentation by AUTOSAR A2-7-3. */ @@ -32,26 +65,46 @@ class DocumentableDeclaration extends Declaration { string declarationType; DocumentableDeclaration() { - this instanceof UserType and - declarationType = "user-defined type" and - // Exclude template parameter types. - not this.(UserType).involvesTemplateParameter() - or - this instanceof Function and - declarationType = "function" and - // Exclude compiler generated functions, which cannot reasonably be documented. - not this.(Function).isCompilerGenerated() and - // Exclude instantiated template functions, which cannot reasonably be documented. - not this.(Function).isFromTemplateInstantiation(_) and - // Exclude anonymous lambda functions. - not exists(LambdaExpression lc | lc.getLambdaFunction() = this) - or - this instanceof MemberVariable and - declarationType = "member variable" and - // Exclude memeber variables in instantiated templates, which cannot reasonably be documented. - not this.(MemberVariable).isFromTemplateInstantiation(_) and - // Exclude compiler generated variables, such as those for anonymous lambda functions - not this.(MemberVariable).isCompilerGenerated() + // Within the users codebase, not a system header + exists(this.getFile().getRelativePath()) and + // Not required to be documented, as used within same scope + not isInFunctionScope(this) and + ( + this instanceof UserType and + declarationType = "user-defined type" and + // Exclude template parameter types. + not this.(UserType).involvesTemplateParameter() + or + this instanceof Function and + declarationType = "function" and + // Exclude compiler generated functions, which cannot reasonably be documented. + not this.(Function).isCompilerGenerated() and + // Exclude instantiated template functions, which cannot reasonably be documented. + not this.(Function).isFromTemplateInstantiation(_) and + // Exclude anonymous lambda functions. + not exists(LambdaExpression lc | lc.getLambdaFunction() = this) and + //Exclude friend functions (because they have 2 entries in the database), and only one shows documented truly + not exists(FriendDecl d | + d.getFriend().(Function).getDefinition() = this.getADeclarationEntry() + ) + or + this instanceof MemberVariable and + declarationType = "member variable" and + // Exclude memeber variables in instantiated templates, which cannot reasonably be documented. + not this.(MemberVariable).isFromTemplateInstantiation(_) and + // Exclude compiler generated variables, such as those for anonymous lambda functions + not this.(MemberVariable).isCompilerGenerated() + ) + } + + private predicate hasDocumentedDefinition() { + // Check if the declaration has a documented definition + exists(DeclarationEntry de | de = getADeclarationEntry() and isDocumented(de)) + } + + private predicate hasOnlyDefinitions() { + // Check if the declaration has only definitions, i.e., no non-definition entries + not exists(DeclarationEntry de | de = getADeclarationEntry() and not de.isDefinition()) } /** Gets a `DeclarationEntry` for this declaration that should be documented. */ @@ -59,20 +112,16 @@ class DocumentableDeclaration extends Declaration { // Find a declaration entry that is not documented result = getADeclarationEntry() and not isDocumented(result) and - ( - // Report any non definition DeclarationEntry that is not documented - // as long as there is no corresponding documented definition (which must be for a forward declaration) - not result.isDefinition() and - not exists(DeclarationEntry de | - de = getADeclarationEntry() and de.isDefinition() and isDocumented(de) - ) - or + if result.isDefinition() + then // Report the definition DeclarationEntry, only if there are no non-definition `DeclarationEntry`'s // The rationale here is that documenting both the non-definition and definition declaration entries // is redundant - result.isDefinition() and - not exists(DeclarationEntry de | de = getADeclarationEntry() and not de.isDefinition()) - ) + hasOnlyDefinitions() + else + // Report any non definition DeclarationEntry that is not documented + // as long as there is no corresponding documented definition (which must be for a forward declaration) + not hasDocumentedDefinition() } /** Gets a string describing the type of declaration. */ @@ -80,11 +129,13 @@ class DocumentableDeclaration extends Declaration { } /** - * A `DeclarationEntry` is considered documented if it has an associated `Comment`, and the `Comment` - * precedes the `DeclarationEntry`. + * A `DeclarationEntry` is considered documented if it has an associated `Comment`, the `Comment` + * precedes the `DeclarationEntry`, and the `Comment` is not a doxygen comment group prefix. */ +cached predicate isDocumented(DeclarationEntry de) { exists(Comment c | c.getCommentedElement() = de | + not c.getContents() = doxygenCommentGroupStrings(true) and exists(Location commentLoc, Location deLoc | commentLoc = c.getLocation() and deLoc = de.getLocation() | @@ -96,13 +147,15 @@ predicate isDocumented(DeclarationEntry de) { commentLoc.getStartColumn() < deLoc.getStartColumn() ) ) + or + // The declaration entry is between a doxygen comment group + isBetweenDoxygenCommentGroup(de.getLocation(), _, _, _) } from DocumentableDeclaration d, DeclarationEntry de where not isExcluded(de, CommentsPackage::undocumentedUserDefinedTypeQuery()) and not isExcluded(d, CommentsPackage::undocumentedUserDefinedTypeQuery()) and - not isInFunctionScope(d) and d.getAnUndocumentedDeclarationEntry() = de select de, "Declaration entry for " + d.getDeclarationType() + " " + d.getName() + diff --git a/cpp/autosar/src/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.ql b/cpp/autosar/src/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.ql index c7ff6f6bf2..0294bfe2e6 100644 --- a/cpp/autosar/src/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.ql +++ b/cpp/autosar/src/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SmartPointers -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /* * Finds `std::shared_ptr` local variables which are not copy or move initialized, and are not used in diff --git a/cpp/autosar/src/rules/A27-0-4/CStyleStringsUsed.ql b/cpp/autosar/src/rules/A27-0-4/CStyleStringsUsed.ql index b698ecf351..b24a4a96cf 100644 --- a/cpp/autosar/src/rules/A27-0-4/CStyleStringsUsed.ql +++ b/cpp/autosar/src/rules/A27-0-4/CStyleStringsUsed.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow class InstanceOfCStyleString extends Expr { InstanceOfCStyleString() { diff --git a/cpp/autosar/src/rules/A3-1-5/NonTrivialNonTemplateFunctionDefinedInsideClassDefinition.ql b/cpp/autosar/src/rules/A3-1-5/NonTrivialNonTemplateFunctionDefinedInsideClassDefinition.ql index 251f94d6eb..9b250e487a 100644 --- a/cpp/autosar/src/rules/A3-1-5/NonTrivialNonTemplateFunctionDefinedInsideClassDefinition.ql +++ b/cpp/autosar/src/rules/A3-1-5/NonTrivialNonTemplateFunctionDefinedInsideClassDefinition.ql @@ -4,9 +4,10 @@ * @description A function that is not either trivial, a template function, or a member of a * template class may not be defined within a class body. * @kind problem - * @precision very-high + * @precision low * @problem.severity recommendation * @tags external/autosar/id/a3-1-5 + * external/autosar/audit * external/autosar/allocated-target/design * external/autosar/enforcement/partially-automated * external/autosar/obligation/required diff --git a/cpp/autosar/src/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.ql b/cpp/autosar/src/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.ql deleted file mode 100644 index 920875ca3b..0000000000 --- a/cpp/autosar/src/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.ql +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @id cpp/autosar/trivial-or-template-function-defined-outside-class-definition - * @name A3-1-5: A function shall be defined with a class body if and only if it is intended to be inlined - * @description A function that is either trivial, a template function, or a member of a template - * class may not be defined outside of a class body. - * @kind problem - * @precision very-high - * @problem.severity recommendation - * @tags external/autosar/id/a3-1-5 - * external/autosar/allocated-target/design - * external/autosar/enforcement/partially-automated - * external/autosar/obligation/required - */ - -import cpp -import codingstandards.cpp.autosar -import codingstandards.cpp.Class - -/* - * Find instances of `MemberFunction` where the `MemberFunction` is trivial - * and it is not inlined within the class. - */ - -from MemberFunction mf, string kind -where - not isExcluded(mf, ClassesPackage::trivialOrTemplateFunctionDefinedOutsideClassDefinitionQuery()) and - // The member function `mf` is not defined in the class body. - exists(FunctionDeclarationEntry fde | - fde = mf.getClassBodyDeclarationEntry() and not fde.isDefinition() - ) and - //ignore destructors - not mf instanceof Destructor and - // Report functions that are NOT defined in the class body if they are either trivial or - // either a template member or part of a template class (i.e., they should - // be defined in the class body) - ( - if - mf instanceof TemplateOrTemplateClassMemberFunction and - mf instanceof TrivialMemberFunction - then kind = "template" - else - if mf instanceof TrivialMemberFunction - then kind = "trivial" - else - if mf instanceof TemplateOrTemplateClassMemberFunction - then kind = "template" - else none() - ) -select mf, - "The " + kind + " member function " + mf.getName() + " is not defined in the class body of $@.", - mf.getDeclaringType(), mf.getDeclaringType().getName() diff --git a/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql b/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql index 84a38b0f6a..dfc73cebc8 100644 --- a/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql +++ b/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql @@ -17,22 +17,10 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.EncapsulatingFunctions -import codingstandards.cpp.BuiltInNumericTypes -import codingstandards.cpp.Type -import codingstandards.cpp.Operator +import codingstandards.cpp.rules.variablewidthintegertypesused.VariableWidthIntegerTypesUsed -from Variable v, Type typeStrippedOfSpecifiers -where - not isExcluded(v, DeclarationsPackage::variableWidthIntegerTypesUsedQuery()) and - typeStrippedOfSpecifiers = stripSpecifiers(v.getType()) and - ( - typeStrippedOfSpecifiers instanceof BuiltInIntegerType or - typeStrippedOfSpecifiers instanceof UnsignedCharType or - typeStrippedOfSpecifiers instanceof SignedCharType - ) and - not v instanceof ExcludedVariable and - //post-increment/post-decrement operators are required by the standard to have a dummy int parameter - not v.(Parameter).getFunction() instanceof PostIncrementOperator and - not v.(Parameter).getFunction() instanceof PostDecrementOperator -select v, "Variable '" + v.getName() + "' has variable-width type." +class VariableWidthIntegerTypesUsedQuery extends VariableWidthIntegerTypesUsedSharedQuery { + VariableWidthIntegerTypesUsedQuery() { + this = DeclarationsPackage::variableWidthIntegerTypesUsedQuery() + } +} diff --git a/cpp/autosar/src/rules/A4-10-1/NullPointerConstantNotNullptr.ql b/cpp/autosar/src/rules/A4-10-1/NullPointerConstantNotNullptr.ql index e77c8265d5..ce3c6f8461 100644 --- a/cpp/autosar/src/rules/A4-10-1/NullPointerConstantNotNullptr.ql +++ b/cpp/autosar/src/rules/A4-10-1/NullPointerConstantNotNullptr.ql @@ -16,17 +16,11 @@ import cpp import codingstandards.cpp.autosar -import semmle.code.cpp.commons.NULL +import codingstandards.cpp.rules.nullptrnottheonlyformofthenullpointerconstant.NullptrNotTheOnlyFormOfTheNullPointerConstant -from Literal l -where - not isExcluded(l, LiteralsPackage::nullPointerConstantNotNullptrQuery()) and - // Not the type of the nullptr literal - not l.getType() instanceof NullPointerType and - // Converted to a pointer type - l.getConversion().getType().getUnspecifiedType() instanceof PointerType and - // Value of zero - l.getValue() = "0" and - // Not the StringLiteral "0" - not l instanceof StringLiteral -select l, l.getValueText() + " is used as the null-pointer-constant but is not nullptr." +class NullPointerConstantNotNullptrQuery extends NullptrNotTheOnlyFormOfTheNullPointerConstantSharedQuery +{ + NullPointerConstantNotNullptrQuery() { + this = LiteralsPackage::nullPointerConstantNotNullptrQuery() + } +} diff --git a/cpp/autosar/src/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.ql b/cpp/autosar/src/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.ql index 34b6660778..ac2375f6aa 100644 --- a/cpp/autosar/src/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.ql +++ b/cpp/autosar/src/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.ql @@ -17,7 +17,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.Type -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import NonFinalClassToPointerArithmeticExprFlow::PathGraph class ArrayAccessOrPointerArith extends Expr { diff --git a/cpp/autosar/src/rules/A5-1-7/LambdaPassedToDecltype.ql b/cpp/autosar/src/rules/A5-1-7/LambdaPassedToDecltype.ql index afbd809664..971d3b9259 100644 --- a/cpp/autosar/src/rules/A5-1-7/LambdaPassedToDecltype.ql +++ b/cpp/autosar/src/rules/A5-1-7/LambdaPassedToDecltype.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow module LambdaExpressionToInitializerConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source.asExpr() instanceof LambdaExpression } diff --git a/cpp/autosar/src/rules/A5-1-7/LambdaPassedToTypeid.ql b/cpp/autosar/src/rules/A5-1-7/LambdaPassedToTypeid.ql index 08dbecc755..56952dace9 100644 --- a/cpp/autosar/src/rules/A5-1-7/LambdaPassedToTypeid.ql +++ b/cpp/autosar/src/rules/A5-1-7/LambdaPassedToTypeid.ql @@ -14,7 +14,7 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.autosar import LambdaExpressionToTypeidFlow::PathGraph diff --git a/cpp/autosar/src/rules/A5-1-9/IdenticalLambdaExpressions.ql b/cpp/autosar/src/rules/A5-1-9/IdenticalLambdaExpressions.ql index 8717fd000e..1520955716 100644 --- a/cpp/autosar/src/rules/A5-1-9/IdenticalLambdaExpressions.ql +++ b/cpp/autosar/src/rules/A5-1-9/IdenticalLambdaExpressions.ql @@ -24,6 +24,14 @@ where not lambdaExpression = otherLambdaExpression and not lambdaExpression.isFromTemplateInstantiation(_) and not otherLambdaExpression.isFromTemplateInstantiation(_) and - getLambdaHashCons(lambdaExpression) = getLambdaHashCons(otherLambdaExpression) + getLambdaHashCons(lambdaExpression) = getLambdaHashCons(otherLambdaExpression) and + // Do not report lambdas produced by the same macro in different invocations + not exists(Macro m, MacroInvocation m1, MacroInvocation m2 | + m1 = m.getAnInvocation() and + m2 = m.getAnInvocation() and + not m1 = m2 and // Lambdas in the same macro can be reported + m1.getAnExpandedElement() = lambdaExpression and + m2.getAnExpandedElement() = otherLambdaExpression + ) select lambdaExpression, "Lambda expression is identical to $@ lambda expression.", otherLambdaExpression, "this" diff --git a/cpp/autosar/src/rules/A5-1-9/LambdaEquivalence.qll b/cpp/autosar/src/rules/A5-1-9/LambdaEquivalence.qll index 040777e321..cab93608c5 100644 --- a/cpp/autosar/src/rules/A5-1-9/LambdaEquivalence.qll +++ b/cpp/autosar/src/rules/A5-1-9/LambdaEquivalence.qll @@ -211,7 +211,7 @@ private module HashCons { private newtype HC_Params = HC_NoParams() or - HC_ParamCons(HashConsExpr hc, int i, HC_Params list) { mk_ParamCons(hc, i, list, _) } + HC_ParamCons(Type t, string name, int i, HC_Params list) { mk_ParamCons(t, name, i, list, _) } /** * HashConsExpr is the hash-cons of an expression. The relationship between `Expr` @@ -624,11 +624,21 @@ private module HashCons { strictcount(access.getTarget()) = 1 } + /** + * Gets the name of a variable. + * + * Extracted for performance reasons, to avoid magic, which was causing performance issues in getParameter(int i). + */ + pragma[nomagic] + private string getVariableName(Variable v) { result = v.getName() } + /* Note: This changed from the original HashCons module to be able to find structural equivalent expression. */ private predicate mk_Variable(Type t, string name, VariableAccess access) { analyzableVariable(access) and exists(Variable v | - v = access.getTarget() and t = v.getUnspecifiedType() and name = v.getName() + v = access.getTarget() and + t = v.getUnspecifiedType() and + name = getVariableName(v) ) } @@ -1104,7 +1114,14 @@ private module HashCons { nee.getExpr().getFullyConverted() = child.getAnExpr() } - private predicate mk_StmtCons(HashConsStmt hc, int i, HC_Stmts list, BlockStmt block) { + private class LambdaBlockStmt extends BlockStmt { + LambdaBlockStmt() { + // Restricting to statements inside a lambda expressions. + this.getParentScope*() = any(LambdaExpression le).getLambdaFunction() + } + } + + private predicate mk_StmtCons(HashConsStmt hc, int i, HC_Stmts list, LambdaBlockStmt block) { hc = hashConsStmt(block.getStmt(i)) and ( exists(HashConsStmt head, HC_Stmts tail | @@ -1118,13 +1135,13 @@ private module HashCons { } private predicate mk_StmtConsInner( - HashConsStmt head, HC_Stmts tail, int i, HC_Stmts list, BlockStmt block + HashConsStmt head, HC_Stmts tail, int i, HC_Stmts list, LambdaBlockStmt block ) { list = HC_StmtCons(head, i, tail) and mk_StmtCons(head, i, tail, block) } - private predicate mk_BlockStmtCons(HC_Stmts hc, BlockStmt s) { + private predicate mk_BlockStmtCons(HC_Stmts hc, LambdaBlockStmt s) { if s.getNumStmt() > 0 then exists(HashConsStmt head, HC_Stmts tail | @@ -1275,13 +1292,14 @@ private module HashCons { mk_DeclConsInner(_, _, s.getNumDeclarations() - 1, hc, s) } - private predicate mk_ParamCons(HashConsExpr hc, int i, HC_Params list, Function f) { - hc = hashConsExpr(f.getParameter(i).getAnAccess()) and - ( - exists(HashConsExpr head, HC_Params tail | - mk_ParamConsInner(head, tail, i - 1, list, f) and - i > 0 - ) + private predicate mk_ParamCons(Type t, string name, int i, HC_Params list, Function f) { + exists(Parameter p | + p = f.getParameter(i) and + t = p.getType() and + name = p.getName() + | + mk_ParamConsInner(_, _, _, i - 1, list, f) and + i > 0 or i = 0 and list = HC_NoParams() @@ -1289,10 +1307,10 @@ private module HashCons { } private predicate mk_ParamConsInner( - HashConsExpr head, HC_Params tail, int i, HC_Params list, Function f + Type t, string name, HC_Params tail, int i, HC_Params list, Function f ) { - list = HC_ParamCons(head, i, tail) and - mk_ParamCons(head, i, tail, f) + list = HC_ParamCons(t, name, i, tail) and + mk_ParamCons(t, name, i, tail, f) } private predicate mk_FunctionCons( @@ -1302,7 +1320,7 @@ private module HashCons { name = f.getName() and body = hashConsStmt(f.getBlock()) and if f.getNumberOfParameters() > 0 - then mk_ParamConsInner(_, _, f.getNumberOfParameters() - 1, params, f) + then mk_ParamConsInner(_, _, _, f.getNumberOfParameters() - 1, params, f) else params = HC_NoParams() } @@ -1486,8 +1504,6 @@ private module HashCons { cached HashConsStmt hashConsStmt(Stmt s) { - // Restricting to statements inside a lambda expressions. - s.getParentScope*() = any(LambdaExpression le).getLambdaFunction() and exists(HC_Stmts list | mk_BlockStmtCons(list, s) and result = HC_BlockStmt(list) diff --git a/cpp/autosar/src/rules/A5-10-1/PointerToMemberVirtualFunctionWithNullPointerConstant.ql b/cpp/autosar/src/rules/A5-10-1/PointerToMemberVirtualFunctionWithNullPointerConstant.ql index 2289dc4e79..825347754d 100644 --- a/cpp/autosar/src/rules/A5-10-1/PointerToMemberVirtualFunctionWithNullPointerConstant.ql +++ b/cpp/autosar/src/rules/A5-10-1/PointerToMemberVirtualFunctionWithNullPointerConstant.ql @@ -16,19 +16,11 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.potentiallyvirtualpointeronlycomparestonullptr.PotentiallyVirtualPointerOnlyComparesToNullptr -from - EqualityOperation equalityComparison, MemberFunction virtualFunction, - FunctionAccess accessOperand, Expr otherOperand -where - not isExcluded(equalityComparison, - PointersPackage::pointerToMemberVirtualFunctionWithNullPointerConstantQuery()) and - virtualFunction.isVirtual() and - equalityComparison.getAnOperand() = accessOperand and - accessOperand.getTarget() = virtualFunction and - otherOperand = equalityComparison.getAnOperand() and - not otherOperand = accessOperand and - not otherOperand.getType() instanceof NullPointerType -select equalityComparison, - "A pointer to member virtual function $@ is tested for equality with non-null-pointer-constant $@. ", - virtualFunction, virtualFunction.getName(), otherOperand, otherOperand.toString() +class PointerToMemberVirtualFunctionWithNullPointerConstantQuery extends PotentiallyVirtualPointerOnlyComparesToNullptrSharedQuery +{ + PointerToMemberVirtualFunctionWithNullPointerConstantQuery() { + this = PointersPackage::pointerToMemberVirtualFunctionWithNullPointerConstantQuery() + } +} diff --git a/cpp/autosar/src/rules/A5-2-2/TraditionalCStyleCastsUsed.ql b/cpp/autosar/src/rules/A5-2-2/TraditionalCStyleCastsUsed.ql index 66a289dfe0..7e2d19d336 100644 --- a/cpp/autosar/src/rules/A5-2-2/TraditionalCStyleCastsUsed.ql +++ b/cpp/autosar/src/rules/A5-2-2/TraditionalCStyleCastsUsed.ql @@ -16,6 +16,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.Macro +import codingstandards.cpp.CStyleCasts /** * Gets the macro (if any) that generated the given `CStyleCast`. @@ -61,18 +62,10 @@ Macro getGeneratedFrom(CStyleCast c) { * argument type is compatible with a single-argument constructor. */ -from CStyleCast c, string extraMessage, Locatable l, string supplementary +from ExplicitUserDefinedCStyleCast c, string extraMessage, Locatable l, string supplementary where not isExcluded(c, BannedSyntaxPackage::traditionalCStyleCastsUsedQuery()) and - not c.isImplicit() and - not c.getType() instanceof UnknownType and - // For casts in templates that occur on types related to a template parameter, the copy of th - // cast in the uninstantiated template is represented as a `CStyleCast` even if in practice all - // the instantiations represent it as a `ConstructorCall`. To avoid the common false positive case - // of using the functional cast notation to call a constructor we exclude all `CStyleCast`s on - // uninstantiated templates, and instead rely on reporting results within instantiations. - not c.isFromUninstantiatedTemplate(_) and - // Exclude casts created from macro invocations of macros defined by third parties + // Not generated from a library macro not getGeneratedFrom(c) instanceof LibraryMacro and // If the cast was generated from a user-provided macro, then report the macro that generated the // cast, as the macro itself may have generated the cast diff --git a/cpp/autosar/src/rules/A5-2-4/ReinterpretCastUsed.ql b/cpp/autosar/src/rules/A5-2-4/ReinterpretCastUsed.ql index 92cf12d8a0..bf5805698d 100644 --- a/cpp/autosar/src/rules/A5-2-4/ReinterpretCastUsed.ql +++ b/cpp/autosar/src/rules/A5-2-4/ReinterpretCastUsed.ql @@ -16,7 +16,8 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.reinterpretcastused.ReinterpretCastUsed -from ReinterpretCast rc -where not isExcluded(rc, BannedSyntaxPackage::reinterpretCastUsedQuery()) -select rc, "Use of reinterpret_cast." +class ReinterpretCastUsedQuery extends ReinterpretCastUsedSharedQuery { + ReinterpretCastUsedQuery() { this = BannedSyntaxPackage::reinterpretCastUsedQuery() } +} diff --git a/cpp/autosar/src/rules/A5-2-6/OperandsOfALogicalAndOrNotParenthesized.ql b/cpp/autosar/src/rules/A5-2-6/OperandsOfALogicalAndOrNotParenthesized.ql index dd63288587..b2c3120556 100644 --- a/cpp/autosar/src/rules/A5-2-6/OperandsOfALogicalAndOrNotParenthesized.ql +++ b/cpp/autosar/src/rules/A5-2-6/OperandsOfALogicalAndOrNotParenthesized.ql @@ -17,11 +17,20 @@ import cpp import codingstandards.cpp.autosar -from BinaryLogicalOperation op, BinaryOperation binop +from BinaryLogicalOperation op, BinaryOperation binop, string leftOrRight where not isExcluded(op, OrderOfEvaluationPackage::operandsOfALogicalAndOrNotParenthesizedQuery()) and - op.getAnOperand() = binop and + ( + op.getLeftOperand() = binop and + leftOrRight = "Left" + or + op.getRightOperand() = binop and + leftOrRight = "Right" + ) and + // Ignore cases with the same operator + not op.getOperator() = binop.getOperator() and not exists(ParenthesisExpr p | p = binop.getFullyConverted()) and // Exclude binary operations expanded by a macro. not binop.isInMacroExpansion() -select op, "Binary $@ operand of logical operation is not parenthesized.", binop, "operator" +select op, "$@ of logical operation " + op.getOperator() + " is not parenthesized.", binop, + leftOrRight + " operand " + binop.getOperator() diff --git a/cpp/autosar/src/rules/A6-6-1/GotoStatementUsed.ql b/cpp/autosar/src/rules/A6-6-1/GotoStatementUsed.ql index 5e1c10e4c7..03b891e6db 100644 --- a/cpp/autosar/src/rules/A6-6-1/GotoStatementUsed.ql +++ b/cpp/autosar/src/rules/A6-6-1/GotoStatementUsed.ql @@ -16,9 +16,8 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.gotostatementshouldnotbeused.GotoStatementShouldNotBeUsed -from Stmt s -where - not isExcluded(s, BannedSyntaxPackage::gotoStatementUsedQuery()) and - (s instanceof GotoStmt or s instanceof ComputedGotoStmt) -select s, "Use of goto." +class GotoStatementUsedQuery extends GotoStatementShouldNotBeUsedSharedQuery { + GotoStatementUsedQuery() { this = BannedSyntaxPackage::gotoStatementUsedQuery() } +} diff --git a/cpp/autosar/src/rules/A7-1-1/DeclarationUnmodifiedObjectMissingConstSpecifier.ql b/cpp/autosar/src/rules/A7-1-1/DeclarationUnmodifiedObjectMissingConstSpecifier.ql index ff07bcbdb2..b961acce64 100644 --- a/cpp/autosar/src/rules/A7-1-1/DeclarationUnmodifiedObjectMissingConstSpecifier.ql +++ b/cpp/autosar/src/rules/A7-1-1/DeclarationUnmodifiedObjectMissingConstSpecifier.ql @@ -38,6 +38,7 @@ where not exists(LambdaExpression lc | lc.getACapture().getField() = v) and not v.isFromUninstantiatedTemplate(_) and not v.isCompilerGenerated() and + not v.getType() instanceof RValueReferenceType and //if the instantiation is not constexpr but the template is, still exclude it as a candidate not exists(TemplateVariable b | b.getAnInstantiation() = v and b.isConstexpr()) select v, "Non-constant variable " + v.getName() + cond + " and is not modified." diff --git a/cpp/autosar/src/rules/A7-1-2/FunctionMissingConstexpr.ql b/cpp/autosar/src/rules/A7-1-2/FunctionMissingConstexpr.ql deleted file mode 100644 index 1cd68447fe..0000000000 --- a/cpp/autosar/src/rules/A7-1-2/FunctionMissingConstexpr.ql +++ /dev/null @@ -1,160 +0,0 @@ -/** - * @id cpp/autosar/function-missing-constexpr - * @name A7-1-2: The constexpr specifier shall be used for functions whose return value can be determined at compile time - * @description Using 'constexpr' makes it clear that a function is intended to return a compile - * time constant. - * @kind problem - * @precision high - * @problem.severity recommendation - * @tags external/autosar/id/a7-1-2 - * maintainability - * external/autosar/allocated-target/implementation - * external/autosar/enforcement/automated - * external/autosar/obligation/required - */ - -import cpp -import codingstandards.cpp.autosar -import codingstandards.cpp.TrivialType - -/** Gets a non-variant member field. */ -Field getANonVariantField(Class c) { - result = c.getAField() and - result.isInitializable() and - not result instanceof AnonymousUnionField -} - -/** - * A `Field` holding an "anonymous union" as described by `[class.union]`. - * - * For example, the union in this example: - * ``` - * class C { - * union { - * int x; - * short y; - * }; - * } - * ``` - */ -class AnonymousUnionField extends Field { - AnonymousUnionField() { hasName("(unknown field)") } - - /** - * Get a direct or indirect union member. - * - * Indirect members can come from nested anonymous unions. - */ - Field getAVariantMember() { - exists(Field f | f = getType().(Union).getAField() | - if f instanceof AnonymousUnionField - then result = f.(AnonymousUnionField).getAVariantMember() - else result = f - ) - } - - /** - * Holds if one variant member of this anonymous union field is initialized using NSDMI. - */ - predicate isExplicitlyInitialized() { exists(getAVariantMember().getInitializer().getExpr()) } -} - -/** - * Get a union which is not initialized by NSDMI. - */ -AnonymousUnionField getAnUninitializedAnonymousUnionField(Class c) { - result = c.getAField() and - not result.isExplicitlyInitialized() -} - -/** - * A function that can be `constexpr` specified according to the constraints for a `constexpr` - * function as specified in `[dcl.constexpr]/3`. - */ -class EffectivelyConstExprFunction extends Function { - EffectivelyConstExprFunction() { - // Not already marked as constexpr - not isDeclaredConstexpr() and - // Not virtual - not isVirtual() and - // Returns a literal type (which can be 'void') - (isLiteralType(getType()) or this instanceof Constructor) and - // Exclude cases that shouldn't be const or can't be const - not this instanceof Destructor and - not this instanceof CopyAssignmentOperator and - not this instanceof MoveAssignmentOperator and - not this.isCompilerGenerated() and - // All parameters are literal types - forall(Parameter p | p = getAParameter() | isLiteralType(p.getType())) and - // The function body is either deleted, defaulted or does not include one of the precluding - // statement kinds and is both side-effect free and created by the user - ( - isDeleted() - or - isDefaulted() - or - not this = any(AsmStmt a).getEnclosingFunction() and - not this = any(GotoStmt g).getEnclosingFunction() and - not this = any(TryStmt t).getEnclosingFunction() and - not exists(LocalVariable lv | this = lv.getFunction() | - not isLiteralType(lv.getType()) - or - lv instanceof StaticStorageDurationVariable - or - lv.isThreadLocal() - or - not exists(lv.getInitializer().getExpr()) - ) and - // For `constexpr` functions, the compiler only checks the rules above - it doesn't check - // whether the function can be evaluated as a compile time constant until the function is used, - // and then only confirms that it evaluates to a compile-time constant for a specific set of - // arguments used in another constexpr calculation. We approximate this by identifying the set - // of functions that are (conservatively) side-effect free. - isSideEffectFree() and - // "User defined" in some way - hasDefinition() and - not isCompilerGenerated() - ) and - ( - // A constructor should satisfy the constraints as specified in `[dcl.constexpr]/4`. - this instanceof Constructor - implies - ( - // No virtual base class - not getDeclaringType().getDerivation(_).isVirtual() and - ( - // All non-variant members initialized by this constructor - forall(Field f | f = getANonVariantField(getDeclaringType()) | - exists(ConstructorFieldInit cfi | - // Even if this field has a `getInitializer()` a `ConstructorFieldInit` will also be - // present on each constructor - cfi.getEnclosingFunction() = this and cfi.getTarget() = f - ) - ) and - // At least one variant member is initialized for each `AnonymousUnionField` which is not - // initialized with a `Field.getInitializer()`. This is different to the non-variant - // member case above - forall(AnonymousUnionField f | - f = getAnUninitializedAnonymousUnionField(getDeclaringType()) - | - exists(ConstructorFieldInit cfi | - cfi.getEnclosingFunction() = this and cfi.getTarget() = f.getAVariantMember() - ) - ) - or - // The function is deleted or defaulted, and every field has an NSDMI, and there are no - // uninitialized anonymous union fields - (isDeleted() or isDefaulted()) and - forall(Field f | f = getANonVariantField(getDeclaringType()) | - exists(f.getInitializer().getExpr()) - ) and - not exists(getAnUninitializedAnonymousUnionField(getDeclaringType())) - ) - ) - ) - } -} - -from EffectivelyConstExprFunction ecef -where not isExcluded(ecef, ConstPackage::functionMissingConstexprQuery()) -select ecef, ecef.getName() + " function could be marked as 'constexpr'." diff --git a/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql b/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql index f0adab07d4..af3a00fadb 100644 --- a/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql +++ b/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType import codingstandards.cpp.SideEffect import semmle.code.cpp.controlflow.SSA import codingstandards.cpp.Expr @@ -35,13 +35,25 @@ predicate isTypeZeroInitializable(Type t) { t.getUnderlyingType() instanceof ArrayType } -from Variable v +from Variable v, string msg where not isExcluded(v, ConstPackage::variableMissingConstexprQuery()) and v.hasDefinition() and not v.isConstexpr() and not v instanceof Parameter and not v.isAffectedByMacro() and + ( + not v instanceof MemberVariable + or + // In case member functions are left un-instantiated, it is possible + // the member variable could be modified in them. + // Hence, don't raise an alert in case this member variable's class + // has a member function that doesn't have a definition. + not exists(MemberFunction mf | + mf.getDeclaringType() = v.getDeclaringType() and + mf.isFromUninstantiatedTemplate(_) + ) + ) and isLiteralType(v.getType()) and // Unfortunately, `isConstant` is not sufficient here because it doesn't include calls to // constexpr constructors, and does not take into account zero initialization @@ -66,5 +78,6 @@ where // Exclude variables in uninstantiated templates, as they may be incomplete not v.isFromUninstantiatedTemplate(_) and // Exclude compiler generated variables, which are not user controllable - not v.isCompilerGenerated() -select v, "Variable '" + v.getName() + "' could be marked 'constexpr'." + not v.isCompilerGenerated() and + if v instanceof MemberVariable and not v.isStatic() then msg = " and static." else msg = "." +select v, "Variable '" + v.getName() + "' could be marked 'constexpr'" + msg diff --git a/cpp/autosar/src/rules/A7-1-3/CvQualifiersNotPlacedOnTheRightHandSide.ql b/cpp/autosar/src/rules/A7-1-3/CvQualifiersNotPlacedOnTheRightHandSide.ql index 54968dc223..5d34f89c7d 100644 --- a/cpp/autosar/src/rules/A7-1-3/CvQualifiersNotPlacedOnTheRightHandSide.ql +++ b/cpp/autosar/src/rules/A7-1-3/CvQualifiersNotPlacedOnTheRightHandSide.ql @@ -20,37 +20,50 @@ import cpp import codingstandards.cpp.autosar /** - * Holds if declaration `e` using a `TypedefType` is CV-qualified - * - * For example, given `using intconstptr = int * const`: - * the predicate holds for `const/volatile intconstptr ptr1`, but not for `intconstptr ptr2` + * Unwrap layers of indirection that occur on the right side of the type. */ -predicate containsExtraSpecifiers(VariableDeclarationEntry e) { - e.getType().toString().matches("const %") or - e.getType().toString().matches("volatile %") +Type unwrapIndirection(Type type) { + if type instanceof DerivedType and not type instanceof SpecifiedType + then result = unwrapIndirection(type.(DerivedType).getBaseType()) + else result = type } // DeclStmts that have a TypedefType name use (ie TypeMention) in them //AND TypeMention.getStartColumn() - DeclStmt.getStartColumn() > len(const) //AND the declared thing contains one of these "extra" specifiers in the DeclarationEntry Location -from VariableDeclarationEntry e, TypedefType t, TypeMention tm +from + VariableDeclarationEntry e, TypedefType t, TypeMention tm, string message, Element explainer, + string explainerMessage where not isExcluded(e, ConstPackage::cvQualifiersNotPlacedOnTheRightHandSideQuery()) and - containsExtraSpecifiers(e) and + // Variable type is specified, and has the typedef type as a base type + unwrapIndirection(e.getType()).(SpecifiedType).getBaseType() = t and exists(string filepath, int startline | e.getLocation().hasLocationInfo(filepath, startline, _, _, _) and tm.getLocation().hasLocationInfo(filepath, startline, _, _, _) and e = t.getATypeNameUse() and tm.getMentionedType() = t and + // TypeMention occurs before the variable declaration + tm.getLocation().getStartColumn() < e.getLocation().getStartColumn() and exists(DeclStmt s | s.getDeclarationEntry(_) = e and - //const could fit in there + // TypeMention occurs after the start of the StmtDecl, with enough space for const/volatile tm.getLocation().getStartColumn() - s.getLocation().getStartColumn() > 5 - //volatile could fit in there - //but the above condition subsumes this one - //l.getStartColumn() - tm.getLocation().getStartColumn() > 8 ) + ) and + if exists(t.getFile().getRelativePath()) + then + message = + "There is possibly a const or volatile specifier on the left hand side of typedef name $@." and + explainer = t and + explainerMessage = t.getName() + else ( + // Type occurs outside source root, so don't link + message = + "There is possibly a const or volatile specifier on the left hand side of typedef name " + + t.getName() + "." and + // explainer not used in this case + explainer = e and + explainerMessage = "" ) -select e, - "There is possibly a const or volatile specifier on the left hand side of typedef name $@.", t, - t.getName() +select e, message, explainer, explainerMessage diff --git a/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql b/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql index 8c10a0f80c..addd8af697 100644 --- a/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql +++ b/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql @@ -19,26 +19,28 @@ import codingstandards.cpp.autosar class UniqueLineStmt extends Locatable { UniqueLineStmt() { not isAffectedByMacro() and - exists(Declaration d | - this = d.getADeclarationEntry() and - not d instanceof Parameter and - not d instanceof TemplateParameter and - // TODO - Needs to be enhanced to solve issues with - // templated inner classes. - not d instanceof Function and - not d.isFromTemplateInstantiation(_) and - not d.(Variable).isCompilerGenerated() and - not exists(RangeBasedForStmt f | f.getADeclaration() = d) and - not exists(DeclStmt declStmt, ForStmt f | - f.getInitialization() = declStmt and - declStmt.getADeclaration() = d - ) and - not exists(LambdaCapture lc | lc.getField().getADeclarationEntry() = this) + ( + exists(Declaration d | + this = d.getADeclarationEntry() and + not d instanceof Parameter and + not d instanceof TypeTemplateParameter and + // TODO - Needs to be enhanced to solve issues with + // templated inner classes. + not d instanceof Function and + not d.isFromTemplateInstantiation(_) and + not d.(Variable).isCompilerGenerated() and + not exists(RangeBasedForStmt f | f.getADeclaration() = d) and + not exists(DeclStmt declStmt, ForStmt f | + f.getInitialization() = declStmt and + declStmt.getADeclaration() = d + ) and + not exists(LambdaCapture lc | lc.getField().getADeclarationEntry() = this) + ) + or + this instanceof ExprStmt and + not exists(ForStmt f | f.getInitialization().getAChild*() = this) and + not exists(LambdaExpression l | l.getLambdaFunction().getBlock().getAChild*() = this) ) - or - this instanceof ExprStmt and - not exists(ForStmt f | f.getInitialization().getAChild*() = this) and - not exists(LambdaExpression l | l.getLambdaFunction().getBlock().getAChild*() = this) } } @@ -53,11 +55,9 @@ where //omit the cases where there is one struct identifier on a struct var line used with typedef not exists(Struct s | s.getADeclarationEntry() = e1 and e1 instanceof TypeDeclarationEntry) and not exists(Struct s | s.getATypeNameUse() = e1 and e1 instanceof TypeDeclarationEntry) and - exists(Location l1, Location l2 | - e1.getLocation() = l1 and - e2.getLocation() = l2 and - not l1 = l2 and - l1.getFile() = l2.getFile() and - l1.getStartLine() = l2.getStartLine() + exists(string file, int startline | + e1.getLocation().hasLocationInfo(file, startline, _, _, _) and + e2.getLocation().hasLocationInfo(file, startline, _, _, _) and + not e1.getLocation() = e2.getLocation() ) select e1, "Expression statement and identifier are on the same line." diff --git a/cpp/autosar/src/rules/A7-2-1/NonEnumeratorEnumValue.ql b/cpp/autosar/src/rules/A7-2-1/NonEnumeratorEnumValue.ql index 9b41c97129..f4dcd7f32e 100644 --- a/cpp/autosar/src/rules/A7-2-1/NonEnumeratorEnumValue.ql +++ b/cpp/autosar/src/rules/A7-2-1/NonEnumeratorEnumValue.ql @@ -47,7 +47,7 @@ where then description = "Cast to enum $@ with from expression with value " + c.getExpr().getValue().toFloat() + - "_+ which is not one of the enumerator values in function " + + " which is not one of the enumerator values in function " + c.getEnclosingFunction().getName() + "." else if exists(upperBound(c.getExpr())) diff --git a/cpp/autosar/src/rules/A7-2-2/EnumerationUnderlyingBaseTypeNotExplicitlyDefined.ql b/cpp/autosar/src/rules/A7-2-2/EnumerationUnderlyingBaseTypeNotExplicitlyDefined.ql index cf5273f45d..42924945cd 100644 --- a/cpp/autosar/src/rules/A7-2-2/EnumerationUnderlyingBaseTypeNotExplicitlyDefined.ql +++ b/cpp/autosar/src/rules/A7-2-2/EnumerationUnderlyingBaseTypeNotExplicitlyDefined.ql @@ -17,9 +17,11 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.enumerationnotdefinedwithanexplicitunderlyingtype.EnumerationNotDefinedWithAnExplicitUnderlyingType -from Enum e -where - not isExcluded(e, DeclarationsPackage::enumerationUnderlyingBaseTypeNotExplicitlyDefinedQuery()) and - not e.hasExplicitUnderlyingType() -select e, "Base type of enumeration is not explicitly specified." +class EnumerationUnderlyingBaseTypeNotExplicitlyDefinedQuery extends EnumerationNotDefinedWithAnExplicitUnderlyingTypeSharedQuery +{ + EnumerationUnderlyingBaseTypeNotExplicitlyDefinedQuery() { + this = DeclarationsPackage::enumerationUnderlyingBaseTypeNotExplicitlyDefinedQuery() + } +} diff --git a/cpp/autosar/src/rules/A7-3-1/DefinitionNotConsideredForUnqualifiedLookup.ql b/cpp/autosar/src/rules/A7-3-1/DefinitionNotConsideredForUnqualifiedLookup.ql index ac6e1b6ff9..75cb2016b5 100644 --- a/cpp/autosar/src/rules/A7-3-1/DefinitionNotConsideredForUnqualifiedLookup.ql +++ b/cpp/autosar/src/rules/A7-3-1/DefinitionNotConsideredForUnqualifiedLookup.ql @@ -16,56 +16,11 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.definitionnotconsideredforunqualifiedlookup.DefinitionNotConsideredForUnqualifiedLookup -/** - * Holds if `functionDecl` is a possible intended target of the `usingDecl`. - */ -pragma[noinline] -predicate isPossibleIntendedTarget( - FunctionDeclarationEntry functionDecl, UsingDeclarationEntry usingDecl -) { - // Extracted to improve the join order. With this approach, we first compute a set of using - // declarations and a set of possible intended targets - functionDecl.getDeclaration().isTopLevel() and - functionDecl.getDeclaration().getQualifiedName() = usingDecl.getDeclaration().getQualifiedName() and - functionDecl.getDeclaration().getNamespace().getParentNamespace*() = usingDecl.getParentScope() +class DefinitionNotConsideredForUnqualifiedLookupQuery extends DefinitionNotConsideredForUnqualifiedLookupSharedQuery +{ + DefinitionNotConsideredForUnqualifiedLookupQuery() { + this = ScopePackage::definitionNotConsideredForUnqualifiedLookupQuery() + } } - -/** - * Holds if `functionDecl` is a possible intended target of the `usingDecl`, and they exist at the - * given locations. - */ -pragma[noinline] -predicate isPossibleIntendedTargetLocation( - FunctionDeclarationEntry functionDecl, UsingDeclarationEntry usingDecl, File usingsFile, - File unavailableFile, int usingsStartLine, int unavailableStartLine -) { - // Extracted to improve the join order. With this approach, we take the set of possible intended - // targets computed in isPossibleIntendedTargets, and compute the files and start lines. - // This helps avoid the join order preferred by the optimiser if this is all written directly in - // the from-where-select, where it will eagerly join: - // - // usingDeclarationEntries -> enclosing files -> all other elements in those files - // - // which is expensive when there are a lot of files with using declarations - isPossibleIntendedTarget(functionDecl, usingDecl) and - usingsFile = usingDecl.getFile() and - unavailableFile = functionDecl.getFile() and - usingsStartLine = usingDecl.getLocation().getStartLine() and - unavailableStartLine = functionDecl.getLocation().getStartLine() -} - -from FunctionDeclarationEntry unavailableDecl, UsingDeclarationEntry usingDecl -where - not isExcluded(unavailableDecl, ScopePackage::definitionNotConsideredForUnqualifiedLookupQuery()) and - exists(File usingsFile, File unavailableFile, int usingsStartLine, int unavailableStartLine | - isPossibleIntendedTargetLocation(unavailableDecl, usingDecl, usingsFile, unavailableFile, - usingsStartLine, unavailableStartLine) and - // An approximation of order where we want the using to preceed the new declaration. - usingsFile = unavailableFile and - usingsStartLine < unavailableStartLine - ) -select unavailableDecl, - "Definition for '" + unavailableDecl.getName() + - "' is not available for unqualified lookup because it is declared after $@", usingDecl, - "using-declaration" diff --git a/cpp/autosar/src/rules/A7-3-1/HiddenInheritedNonOverridableMemberFunction.ql b/cpp/autosar/src/rules/A7-3-1/HiddenInheritedNonOverridableMemberFunction.ql index fa1859c229..fd9602f218 100644 --- a/cpp/autosar/src/rules/A7-3-1/HiddenInheritedNonOverridableMemberFunction.ql +++ b/cpp/autosar/src/rules/A7-3-1/HiddenInheritedNonOverridableMemberFunction.ql @@ -15,45 +15,11 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.Class +import codingstandards.cpp.rules.hiddeninheritednonoverridablememberfunction.HiddenInheritedNonOverridableMemberFunction -/** - * Holds if the class has a non-virtual member function with the given name. - */ -pragma[noinline, nomagic] -predicate hasNonVirtualMemberFunction(Class clazz, MemberFunction mf, string name) { - mf.getDeclaringType() = clazz and - mf.getName() = name and - not mf.isVirtual() and - // Exclude private member functions, which cannot be inherited. - not mf.isPrivate() +class HiddenInheritedNonOverridableMemberFunctionQuery extends HiddenInheritedNonOverridableMemberFunctionSharedQuery +{ + HiddenInheritedNonOverridableMemberFunctionQuery() { + this = ScopePackage::hiddenInheritedNonOverridableMemberFunctionQuery() + } } - -/** - * Holds if the member function is in a class with the given base class, and has the given name. - */ -pragma[noinline, nomagic] -predicate hasDeclarationBaseClass(MemberFunction mf, Class baseClass, string functionName) { - baseClass = mf.getDeclaringType().getABaseClass() and - functionName = mf.getName() -} - -from MemberFunction overridingDecl, MemberFunction hiddenDecl, Class baseClass, string name -where - not isExcluded(overridingDecl, ScopePackage::hiddenInheritedNonOverridableMemberFunctionQuery()) and - // Check if we are overriding a non-virtual inherited member function - hasNonVirtualMemberFunction(baseClass, hiddenDecl, name) and - hasDeclarationBaseClass(overridingDecl, baseClass, name) and - // Where the hidden member function isn't explicitly brought in scope through a using declaration. - not exists(UsingDeclarationEntry ude | - ude.getDeclaration() = hiddenDecl and - ude.getEnclosingElement() = overridingDecl.getDeclaringType() - ) and - // Exclude compiler generated member functions which include things like copy constructor that hide base class - // copy constructors. - not overridingDecl.isCompilerGenerated() and - // Exclude special member functions, which cannot be inherited. - not overridingDecl instanceof SpecialMemberFunction -select overridingDecl, - "Declaration for member '" + name + "' hides non-overridable inherited member function $@", - hiddenDecl, hiddenDecl.getName() diff --git a/cpp/autosar/src/rules/A7-3-1/HiddenInheritedOverridableMemberFunction.ql b/cpp/autosar/src/rules/A7-3-1/HiddenInheritedOverridableMemberFunction.ql index 437c8798f9..aa9105f9de 100644 --- a/cpp/autosar/src/rules/A7-3-1/HiddenInheritedOverridableMemberFunction.ql +++ b/cpp/autosar/src/rules/A7-3-1/HiddenInheritedOverridableMemberFunction.ql @@ -15,42 +15,11 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.hiddeninheritedoverridablememberfunction.HiddenInheritedOverridableMemberFunction -from FunctionDeclarationEntry overridingDecl, FunctionDeclarationEntry hiddenDecl -where - not isExcluded(overridingDecl, ScopePackage::hiddenInheritedOverridableMemberFunctionQuery()) and - // Check if we are overriding a virtual inherited member function - hiddenDecl.getDeclaration().isVirtual() and - // Exclude private member functions, which cannot be inherited. - not hiddenDecl.getDeclaration().(MemberFunction).isPrivate() and - // The overriding declaration hides the hidden declaration if: - ( - // 1. the overriding declaration overrides a function in a base class that is an overload of the hidden declaration - // and the hidden declaration isn't overriden in the same class. - exists(FunctionDeclarationEntry overridenDecl | - overridingDecl.getDeclaration().(MemberFunction).overrides(overridenDecl.getDeclaration()) and - overridenDecl.getDeclaration().getAnOverload() = hiddenDecl.getDeclaration() and - not exists(MemberFunction overridingFunc | - hiddenDecl.getDeclaration().(MemberFunction).getAnOverridingFunction() = overridingFunc and - overridingFunc.getDeclaringType() = overridingDecl.getDeclaration().getDeclaringType() - ) - ) and - // and the hidden declaration isn't explicitly brought in scope through a using declaration. - not exists(UsingDeclarationEntry ude | - ude.getDeclaration() = hiddenDecl.getDeclaration() and - ude.getEnclosingElement() = overridingDecl.getDeclaration().getDeclaringType() - ) - or - // 2. if the overriding declaration doesn't override a base member function but has the same name - // as the hidden declaration - not overridingDecl.getDeclaration().(MemberFunction).overrides(_) and - overridingDecl.getName() = hiddenDecl.getName() and - overridingDecl.getDeclaration().getDeclaringType().getABaseClass() = - hiddenDecl.getDeclaration().getDeclaringType() - ) and - // Limit the results to the declarations and not the definitions, if any. - (overridingDecl.getDeclaration().hasDefinition() implies not overridingDecl.isDefinition()) and - (hiddenDecl.getDeclaration().hasDefinition() implies not hiddenDecl.isDefinition()) -select overridingDecl, - "Declaration for member '" + overridingDecl.getName() + - "' hides overridable inherited member function $@", hiddenDecl, hiddenDecl.getName() +class HiddenInheritedOverridableMemberFunctionQuery extends HiddenInheritedOverridableMemberFunctionSharedQuery +{ + HiddenInheritedOverridableMemberFunctionQuery() { + this = ScopePackage::hiddenInheritedOverridableMemberFunctionQuery() + } +} diff --git a/cpp/autosar/src/rules/A7-4-1/AsmDeclarationUsed.ql b/cpp/autosar/src/rules/A7-4-1/AsmDeclarationUsed.ql index d94811ff18..44489151da 100644 --- a/cpp/autosar/src/rules/A7-4-1/AsmDeclarationUsed.ql +++ b/cpp/autosar/src/rules/A7-4-1/AsmDeclarationUsed.ql @@ -15,7 +15,8 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.asmdeclarationused.AsmDeclarationUsed -from AsmStmt a -where not isExcluded(a, BannedSyntaxPackage::asmDeclarationUsedQuery()) -select a, "Use of asm declaration" +class AsmDeclarationUsedQuery extends AsmDeclarationUsedSharedQuery { + AsmDeclarationUsedQuery() { this = BannedSyntaxPackage::asmDeclarationUsedQuery() } +} diff --git a/cpp/autosar/src/rules/A7-5-1/InvalidFunctionReturnType.ql b/cpp/autosar/src/rules/A7-5-1/InvalidFunctionReturnType.ql index 6994ab028f..c36bda6cdd 100644 --- a/cpp/autosar/src/rules/A7-5-1/InvalidFunctionReturnType.ql +++ b/cpp/autosar/src/rules/A7-5-1/InvalidFunctionReturnType.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow from Parameter p, ReturnStmt ret where diff --git a/cpp/autosar/src/rules/A7-5-2/RecursiveFunctions.ql b/cpp/autosar/src/rules/A7-5-2/RecursiveFunctions.ql index 13883624b3..6b305d9ca9 100644 --- a/cpp/autosar/src/rules/A7-5-2/RecursiveFunctions.ql +++ b/cpp/autosar/src/rules/A7-5-2/RecursiveFunctions.ql @@ -16,21 +16,8 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.functionscallthemselveseitherdirectlyorindirectly.FunctionsCallThemselvesEitherDirectlyOrIndirectly -class RecursiveCall extends FunctionCall { - RecursiveCall() { - this.getTarget().calls*(this.getEnclosingFunction()) and - not this.getTarget().hasSpecifier("is_constexpr") - } +class RecursiveFunctionsQuery extends FunctionsCallThemselvesEitherDirectlyOrIndirectlySharedQuery { + RecursiveFunctionsQuery() { this = FunctionsPackage::recursiveFunctionsQuery() } } - -from RecursiveCall call, string msg, FunctionCall fc -where - not isExcluded(fc, FunctionsPackage::recursiveFunctionsQuery()) and - fc.getTarget() = call.getTarget() and - if fc.getTarget() = fc.getEnclosingFunction() - then msg = "This call directly invokes its containing function $@." - else - msg = - "The function " + fc.getEnclosingFunction() + " is indirectly recursive via this call to $@." -select fc, msg, fc.getTarget(), fc.getTarget().getName() diff --git a/cpp/autosar/src/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.ql b/cpp/autosar/src/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.ql index 811d98eccb..0bf42ce4ca 100644 --- a/cpp/autosar/src/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.ql +++ b/cpp/autosar/src/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SmartPointers -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.standardlibrary.Utility Expr lifetimeAffectingSmartPointerExpr(Function f) { diff --git a/cpp/autosar/src/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.ql b/cpp/autosar/src/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.ql index 5dec96ed81..3cd310b59b 100644 --- a/cpp/autosar/src/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.ql +++ b/cpp/autosar/src/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.ql @@ -18,7 +18,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SmartPointers import codingstandards.cpp.standardlibrary.Utility -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow Expr underlyingObjectAffectingUniquePointerExpr(Function f) { result = diff --git a/cpp/autosar/src/rules/A8-4-4/FunctionReturnMultipleValueCondition.ql b/cpp/autosar/src/rules/A8-4-4/FunctionReturnMultipleValueCondition.ql index fa38b1d3f6..03f0c3cea6 100644 --- a/cpp/autosar/src/rules/A8-4-4/FunctionReturnMultipleValueCondition.ql +++ b/cpp/autosar/src/rules/A8-4-4/FunctionReturnMultipleValueCondition.ql @@ -16,7 +16,6 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow abstract class OutputValue extends Element { abstract string getOutputName(); diff --git a/cpp/autosar/src/rules/A8-4-7/TriviallyCopyableSmallType.qll b/cpp/autosar/src/rules/A8-4-7/TriviallyCopyableSmallType.qll index be7cd76bd2..09c6cdae69 100644 --- a/cpp/autosar/src/rules/A8-4-7/TriviallyCopyableSmallType.qll +++ b/cpp/autosar/src/rules/A8-4-7/TriviallyCopyableSmallType.qll @@ -1,6 +1,6 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType /** * Get the largest word size, in bytes. Some projects may have multiple different diff --git a/cpp/autosar/src/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.ql b/cpp/autosar/src/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.ql index 1509ee968a..3b30eb676a 100644 --- a/cpp/autosar/src/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.ql +++ b/cpp/autosar/src/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.ql @@ -21,6 +21,7 @@ import codingstandards.cpp.autosar import codingstandards.cpp.FunctionParameter import codingstandards.cpp.ConstHelpers import codingstandards.cpp.Operator +import semmle.code.cpp.dataflow.DataFlow /** * Non-const T& `Parameter`s to `Function`s diff --git a/cpp/autosar/src/rules/A8-5-4/ConfusingUseOfInitializerListConstructors.ql b/cpp/autosar/src/rules/A8-5-4/ConfusingUseOfInitializerListConstructors.ql index 2a44ca650e..180cbf7224 100644 --- a/cpp/autosar/src/rules/A8-5-4/ConfusingUseOfInitializerListConstructors.ql +++ b/cpp/autosar/src/rules/A8-5-4/ConfusingUseOfInitializerListConstructors.ql @@ -17,50 +17,11 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.initializerlistconstructoristheonlyconstructor.InitializerListConstructorIsTheOnlyConstructor -class StdInitializerList extends Class { - StdInitializerList() { hasQualifiedName("std", "initializer_list") } -} - -/** - * An _initializer-list constructor_ according to `[dcl.init.list]`. - * - * A `Constructor` where the first parameter refers to `std::initializer_list`, and any remaining - * parameters have default arguments. - */ -class InitializerListConstructor extends Constructor { - InitializerListConstructor() { - // The first parameter is a `std::intializer_list` parameter - exists(Type firstParamType | firstParamType = getParameter(0).getType() | - // Either directly `std::initializer_list` - firstParamType instanceof StdInitializerList - or - //A reference to `std::initializer_list` - firstParamType.(ReferenceType).getBaseType().getUnspecifiedType() instanceof - StdInitializerList - ) and - // All parameters other than the fi - forall(Parameter other | other = getParameter([1 .. (getNumberOfParameters() - 1)]) | - exists(other.getInitializer()) - ) +class ConfusingUseOfInitializerListConstructorsQuery extends InitializerListConstructorIsTheOnlyConstructorSharedQuery +{ + ConfusingUseOfInitializerListConstructorsQuery() { + this = InitializationPackage::confusingUseOfInitializerListConstructorsQuery() } } - -from Constructor c, InitializerListConstructor stdInitializerConstructor, string paramList -where - not isExcluded(c, InitializationPackage::confusingUseOfInitializerListConstructorsQuery()) and - // Not an initializer-list constructor - not c instanceof InitializerListConstructor and - // Constructor is not a special member function constructor - not c instanceof CopyConstructor and - not c instanceof MoveConstructor and - not c.getNumberOfParameters() = 0 and // default constructor - // And there is an initalizer-list constructor - stdInitializerConstructor = c.getDeclaringType().getAConstructor() and - // Determine the parameter type list of the constructor - paramList = - concat(string parameter | parameter = c.getAParameter().getType().getName() | parameter, ",") -select c, - "The constructor " + c.getQualifiedName() + "(" + paramList + - ") may be ignored in favour of $@ when using braced initialization.", stdInitializerConstructor, - "the constructor accepting std::initializer_list" diff --git a/cpp/autosar/src/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql b/cpp/autosar/src/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql index f40faad3dd..478f8dcdf0 100644 --- a/cpp/autosar/src/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql +++ b/cpp/autosar/src/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.CommonTypes as CommonTypes -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow class AccessAwareMemberFunction extends MemberFunction { Class c; diff --git a/cpp/autosar/src/rules/M0-1-10/UnusedFunction.ql b/cpp/autosar/src/rules/M0-1-10/UnusedFunction.ql index b8593e75c0..f175cb8992 100644 --- a/cpp/autosar/src/rules/M0-1-10/UnusedFunction.ql +++ b/cpp/autosar/src/rules/M0-1-10/UnusedFunction.ql @@ -26,5 +26,6 @@ where then name = unusedFunction.getQualifiedName() else name = unusedFunction.getName() ) and - not unusedFunction.isDeleted() + not unusedFunction.isDeleted() and + not unusedFunction instanceof SpecialMemberFunction select unusedFunction, "Function " + name + " is " + unusedFunction.getDeadCodeType() diff --git a/cpp/autosar/src/rules/M0-1-10/UnusedSplMemberFunction.ql b/cpp/autosar/src/rules/M0-1-10/UnusedSplMemberFunction.ql new file mode 100644 index 0000000000..bcbf6f4e1b --- /dev/null +++ b/cpp/autosar/src/rules/M0-1-10/UnusedSplMemberFunction.ql @@ -0,0 +1,31 @@ +/** + * @id cpp/autosar/unused-spl-member-function + * @name M0-1-10: Every defined function should be called at least once + * @description Uncalled functions complicate the program and can indicate a possible mistake on the + * part of the programmer. + * @kind problem + * @precision medium + * @problem.severity warning + * @tags external/autosar/id/m0-1-10 + * readability + * maintainability + * external/autosar/allocated-target/implementation + * external/autosar/enforcement/automated + * external/autosar/obligation/advisory + */ + +import cpp +import codingstandards.cpp.autosar +import codingstandards.cpp.deadcode.UnusedFunctions + +from UnusedFunctions::UnusedSplMemberFunction unusedSplMemFunction, string name +where + not isExcluded(unusedSplMemFunction, DeadCodePackage::unusedFunctionQuery()) and + ( + if exists(unusedSplMemFunction.getQualifiedName()) + then name = unusedSplMemFunction.getQualifiedName() + else name = unusedSplMemFunction.getName() + ) and + not unusedSplMemFunction.isDeleted() +select unusedSplMemFunction, + "Special member function " + name + " is " + unusedSplMemFunction.getDeadCodeType() diff --git a/cpp/autosar/src/rules/M0-1-2/InfeasiblePath.ql b/cpp/autosar/src/rules/M0-1-2/InfeasiblePath.ql index 76ccdead69..83e056472b 100644 --- a/cpp/autosar/src/rules/M0-1-2/InfeasiblePath.ql +++ b/cpp/autosar/src/rules/M0-1-2/InfeasiblePath.ql @@ -151,186 +151,19 @@ predicate isConstantRelationalOperation( * Holds if the `ConditionalNode` has an infeasible `path` for the reason given in `explanation`. */ predicate hasInfeasiblePath(ConditionalControlFlowNode node, string message) { - //deal with the infeasible in all uninstantiated templates separately - node.isFromUninstantiatedTemplate(_) and - node instanceof ConditionControllingUnreachable and - message = "The path is unreachable in a template." - or exists(boolean infeasiblePath, string explanation | - ( - not node.isFromUninstantiatedTemplate(_) and - not node.isFromTemplateInstantiation(_) and - message = "The " + infeasiblePath + " path is infeasible because " + explanation + "." - ) and - ( - hasCFGDeducedInfeasiblePath(node, infeasiblePath, explanation) and - not isConstantRelationalOperation(node, infeasiblePath, _) - or - isConstantRelationalOperation(node, infeasiblePath, explanation) - ) + not node.isFromTemplateInstantiation(_) and + if node.isFromUninstantiatedTemplate(_) + then message = "The path is unreachable in a template." + else message = "The " + infeasiblePath + " path is infeasible because " + explanation + "." + | + hasCFGDeducedInfeasiblePath(node, infeasiblePath, explanation) and + not isConstantRelationalOperation(node, infeasiblePath, _) + or + isConstantRelationalOperation(node, infeasiblePath, explanation) ) } -/** - * A newtype representing "unreachable" blocks in the program. We use a newtype here to avoid - * reporting the same block in multiple `Function` instances created from one function in a template. - */ -private newtype TUnreachableBasicBlock = - TUnreachableNonTemplateBlock(BasicBlock bb) { - bb.isUnreachable() and - // Exclude anything template related from this case - not bb.getEnclosingFunction().isFromTemplateInstantiation(_) and - not bb.getEnclosingFunction().isFromUninstantiatedTemplate(_) and - // Exclude compiler generated basic blocks - not isCompilerGenerated(bb) - } or - /** - * A `BasicBlock` that occurs in at least one `Function` instance for a template. `BasicBlock`s - * are matched up across templates by location. - */ - TUnreachableTemplateBlock( - string filepath, int startline, int startcolumn, int endline, int endcolumn, - GuardCondition uninstantiatedGuardCondition - ) { - exists(BasicBlock bb | - // BasicBlock occurs in this location - bb.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and - // And is contained in the `uninstantiatedFunction` only - // not from anything constructed from it - // because we want infeasible paths independent of parameters - exists(Function enclosing | enclosing = bb.getEnclosingFunction() | - //guard is in the template function - ( - enclosing.getBlock().getAChild*() = uninstantiatedGuardCondition and - //function template - enclosing.isFromUninstantiatedTemplate(_) and - uninstantiatedGuardCondition.isFromUninstantiatedTemplate(_) and - //true condition is unreachable: basic block starts on same line as guard - ( - not exists(uninstantiatedGuardCondition.getATrueSuccessor()) and - bb.hasLocationInfo(filepath, uninstantiatedGuardCondition.getLocation().getStartLine(), - startcolumn, endline, endcolumn) - or - //false condition is unreachable: false basic block starts on one line after its true basic block - not exists(uninstantiatedGuardCondition.getAFalseSuccessor()) and - bb.hasLocationInfo(filepath, - uninstantiatedGuardCondition.getATrueSuccessor().getLocation().getEndLine() + 1, - startcolumn, endline, endcolumn) - ) - ) - ) and - // And is unreachable - bb.isUnreachable() and - // //Exclude compiler generated control flow nodes - not isCompilerGenerated(bb) and - //Exclude nodes affected by macros, because our find-the-same-basic-block-by-location doesn't - //work in that case - not bb.(ControlFlowNode).isAffectedByMacro() - ) - } - -/** - * An unreachable basic block. - */ -class UnreachableBasicBlock extends TUnreachableBasicBlock { - /** Gets a `BasicBlock` which is represented by this set of unreachable basic blocks. */ - BasicBlock getABasicBlock() { none() } - - /** Gets a `GuardCondition` instance which we treat as the original GuardCondition. */ - GuardCondition getGuardCondition() { none() } - - predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - none() - } - - string toString() { result = "default" } -} - -/** - * A non-templated unreachable basic block. - */ -class UnreachableNonTemplateBlock extends UnreachableBasicBlock, TUnreachableNonTemplateBlock { - BasicBlock getBasicBlock() { this = TUnreachableNonTemplateBlock(result) } - - override BasicBlock getABasicBlock() { result = getBasicBlock() } - - override GuardCondition getGuardCondition() { result.controls(getBasicBlock(), true) } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - getBasicBlock().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } - - override string toString() { result = getBasicBlock().toString() } -} - -/** - * A templated unreachable basic block. - */ -class UnreachableTemplateBlock extends UnreachableBasicBlock, TUnreachableTemplateBlock { - override BasicBlock getABasicBlock() { - exists( - string filepath, int startline, int startcolumn, int endline, int endcolumn, - GuardCondition uninstantiatedGuardCondition - | - this = - TUnreachableTemplateBlock(filepath, startline, startcolumn, endline, endcolumn, - uninstantiatedGuardCondition) and - result.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and - exists(Function enclosing | - //guard is in the template function - ( - enclosing.getBlock().getAChild*() = uninstantiatedGuardCondition and - //function template - enclosing.isFromUninstantiatedTemplate(_) and - uninstantiatedGuardCondition.isFromUninstantiatedTemplate(_) and - //true condition is unreachable: basic block starts on same line as guard - ( - not exists(uninstantiatedGuardCondition.getATrueSuccessor()) and - this.hasLocationInfo(filepath, - uninstantiatedGuardCondition.getLocation().getStartLine(), startcolumn, endline, - endcolumn) - or - //false condition is unreachable: false basic block starts on one line after its true basic block - not exists(uninstantiatedGuardCondition.getAFalseSuccessor()) and - this.hasLocationInfo(filepath, - uninstantiatedGuardCondition.getATrueSuccessor().getLocation().getEndLine() + 1, - startcolumn, endline, endcolumn) - ) - ) - ) - | - result.isUnreachable() and - // Exclude compiler generated control flow nodes - not isCompilerGenerated(result) and - // Exclude nodes affected by macros, because our find-the-same-basic-block-by-location doesn't - // work in that case - not result.(ControlFlowNode).isAffectedByMacro() - ) - } - - override GuardCondition getGuardCondition() { - this = TUnreachableTemplateBlock(_, _, _, _, _, result) - } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this = TUnreachableTemplateBlock(filepath, startline, startcolumn, endline, endcolumn, _) - } - - override string toString() { result = getABasicBlock().toString() } -} - -class ConditionControllingUnreachable extends GuardCondition { - ConditionControllingUnreachable() { - exists(UnreachableTemplateBlock b | this = b.getGuardCondition()) - } -} - from ConditionalControlFlowNode cond, string explanation where not isExcluded(cond, DeadCodePackage::infeasiblePathQuery()) and diff --git a/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql b/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql index f088bb1b74..e89e9ec135 100644 --- a/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql +++ b/cpp/autosar/src/rules/M0-1-3/UnusedLocalVariable.ql @@ -18,12 +18,6 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.deadcode.UnusedVariables -/** Gets the constant value of a constexpr variable. */ -private string getConstExprValue(Variable v) { - result = v.getInitializer().getExpr().getValue() and - v.isConstexpr() -} - // This predicate is similar to getUseCount for M0-1-4 except that it also // considers static_asserts. This was created to cater for M0-1-3 specifically // and hence, doesn't attempt to reuse the M0-1-4 specific predicate @@ -41,7 +35,10 @@ int getUseCountConservatively(Variable v) { ) + // For static asserts too, check if there is a child which has the same value // as the constexpr variable. - count(StaticAssert s | s.getCondition().getAChild*().getValue() = getConstExprValue(v)) + count(StaticAssert s | s.getCondition().getAChild*().getValue() = getConstExprValue(v)) + + // In case an array type uses a constant in the same scope as the constexpr variable, + // consider it as used. + countUsesInLocalArraySize(v) } from PotentiallyUnusedLocalVariable v @@ -49,5 +46,13 @@ where not isExcluded(v, DeadCodePackage::unusedLocalVariableQuery()) and // Local variable is never accessed not exists(v.getAnAccess()) and + // Sometimes multiple objects representing the same entities are created in + // the AST. Check if those are not accessed as well. Refer issue #658 + not exists(LocalScopeVariable another | + another.getDefinitionLocation() = v.getDefinitionLocation() and + another.hasName(v.getName()) and + exists(another.getAnAccess()) and + another != v + ) and getUseCountConservatively(v) = 0 select v, "Local variable '" + v.getName() + "' in '" + v.getFunction().getName() + "' is not used." diff --git a/cpp/autosar/src/rules/M0-1-4/SingleUsePODVariable.qll b/cpp/autosar/src/rules/M0-1-4/SingleUsePODVariable.qll index 45ea8c35ab..8985f7254e 100644 --- a/cpp/autosar/src/rules/M0-1-4/SingleUsePODVariable.qll +++ b/cpp/autosar/src/rules/M0-1-4/SingleUsePODVariable.qll @@ -1,15 +1,9 @@ /** A module providing predicates that support identifying single use non volatile POD variables. */ import cpp -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType import codingstandards.cpp.deadcode.UnusedVariables -/** Gets the constant value of a constexpr variable. */ -private string getConstExprValue(Variable v) { - result = v.getInitializer().getExpr().getValue() and - v.isConstexpr() -} - /** * Gets the number of uses of variable `v` in an opaque assignment, where an opaque assignment is a cast from one type to the other, and `v` is assumed to be a member of the resulting type. * e.g., diff --git a/cpp/autosar/src/rules/M0-2-1/DoNotPassAliasedPointerToParam.ql b/cpp/autosar/src/rules/M0-2-1/DoNotPassAliasedPointerToParam.ql new file mode 100644 index 0000000000..d99ae486fc --- /dev/null +++ b/cpp/autosar/src/rules/M0-2-1/DoNotPassAliasedPointerToParam.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/autosar/do-not-pass-aliased-pointer-to-param + * @name M0-2-1: Do not pass aliased pointers as parameters of functions where it is undefined behaviour for those pointers to overlap + * @description Passing a aliased pointers as parameters of certain functions is undefined behavior. + * @kind problem + * @precision medium + * @problem.severity error + * @tags external/autosar/id/m0-2-1 + * correctness + * external/autosar/allocated-target/implementation + * external/autosar/enforcement/automated + * external/autosar/obligation/required + */ + +import cpp +import codingstandards.cpp.autosar +import codingstandards.cpp.rules.donotpassaliasedpointertorestrictqualifiedparamshared.DoNotPassAliasedPointerToRestrictQualifiedParamShared + +class DoNotPassAliasedPointerToRestrictQualifiedParamQuery extends DoNotPassAliasedPointerToRestrictQualifiedParamSharedSharedQuery +{ + DoNotPassAliasedPointerToRestrictQualifiedParamQuery() { + this = RepresentationPackage::doNotPassAliasedPointerToParamQuery() + } +} diff --git a/cpp/autosar/src/rules/M0-3-2/FunctionErroneousReturnValueNotTested.ql b/cpp/autosar/src/rules/M0-3-2/FunctionErroneousReturnValueNotTested.ql index aee4e40838..77e6278960 100644 --- a/cpp/autosar/src/rules/M0-3-2/FunctionErroneousReturnValueNotTested.ql +++ b/cpp/autosar/src/rules/M0-3-2/FunctionErroneousReturnValueNotTested.ql @@ -19,54 +19,11 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow -import semmle.code.cpp.controlflow.Guards +import codingstandards.cpp.rules.functionerroneousreturnvaluenottested.FunctionErroneousReturnValueNotTested -from FunctionCall fc -where - not isExcluded(fc, ExpressionsPackage::functionErroneousReturnValueNotTestedQuery()) and - fc.getTarget() - .hasGlobalOrStdName([ - // fcntl.h - "open", "openat", "fcntl", "creat", - // locale.h - "setlocale", - // stdlib.h - "system", "getenv", "getenv_s", - // signal.h - "signal", "raise", - // setjmp.h - "setjmp", - // stdio.h - "fopen", "fopen_s", "freopen", "freopen_s", "fclose", "fcloseall", "fflush", "setvbuf", - "fgetc", "getc", "fgets", "fputc", "getchar", "gets", "gets_s", "putchar", "puts", - "ungetc", "scanf", "fscanf", "sscanf", "scanf_s", "fscanf_s", "sscanf_s", "vscanf", - "vfscanf", "vsscanf", "vscanf_s", "vfscanf_s", "vsscanf_s", "printf", "fprintf", - "sprintf", "snprintf", "printf_s", "fprintf_s", "sprintf_s", "snprintf_s", "vprintf", - "vfprintf", "vsprintf", "vsnprintf", "vprintf_s", "vfprintf_s", "vsprintf_s", - "vsnprintf_s", "ftell", "fgetpos", "fseek", "fsetpos", "remove", "rename", "tmpfile", - "tmpfile_s", "tmpnam", "tmpnam_s", - // string.h - "strcpy_s", "strncpy_s", "strcat_s", "strncat_s", "memset_s", "memcpy_s", "memmove_s", - "strerror_s", - // threads.h - "thrd_create", "thrd_sleep", "thrd_detach", "thrd_join", "mtx_init", "mtx_lock", - "mtx_timedlock", "mtx_trylock", "mtx_unlock", "cnd_init", "cnd_signal", "cnd_broadcast", - "cnd_wait", "cnd_timedwait", "tss_create", "tss_get", "tss_set", - // time.h - "time", "clock", "timespec_get", "asctime_s", "ctime_s", "gmtime", "gmtime_s", - "localtime", "localtime_s", - // unistd.h - "write", "read", "close", "unlink", - // wchar.h - "fgetwc", "getwc", "fgetws", "fputwc", "putwc", "fputws", "getwchar", "putwchar", - "ungetwc", "wscanf", "fwscanf", "swscanf", "wscanf_s", "fwscanf_s", "swscanf_s", - "vwscanf", "vfwscanf", "vswscanf", "vwscanf_s", "vfwscanf_s", "vswscanf_s", "wprintf", - "fwprintf", "swprintf", "wprintf_s", "fwprintf_s", "swprintf_s", "snwprintf_s", - "vwprintf", "vfwprintf", "vswprintf", "vwprintf_s", "vfwprintf_s", "vswprintf_s", - "vsnwprintf_s" - ]) and - forall(GuardCondition gc | - not DataFlow::localFlow(DataFlow::exprNode(fc), DataFlow::exprNode(gc.getAChild*())) - ) -select fc, "Return value is not tested for errors." +class FunctionErrorInformationUntestedQuery extends FunctionErroneousReturnValueNotTestedSharedQuery +{ + FunctionErrorInformationUntestedQuery() { + this = ExpressionsPackage::functionErroneousReturnValueNotTestedQuery() + } +} diff --git a/cpp/autosar/src/rules/M10-1-3/AccessibleBaseClassBothVirtualAndNonVirtualInHierarchy.ql b/cpp/autosar/src/rules/M10-1-3/AccessibleBaseClassBothVirtualAndNonVirtualInHierarchy.ql index 6b6cead0ea..c16e5461f0 100644 --- a/cpp/autosar/src/rules/M10-1-3/AccessibleBaseClassBothVirtualAndNonVirtualInHierarchy.ql +++ b/cpp/autosar/src/rules/M10-1-3/AccessibleBaseClassBothVirtualAndNonVirtualInHierarchy.ql @@ -14,24 +14,11 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.virtualandnonvirtualclassinthehierarchy.VirtualAndNonVirtualClassInTheHierarchy -from Class c1, Class c2, Class c3, Class base, ClassDerivation cd1, ClassDerivation cd2 -where - not isExcluded(c3, - InheritancePackage::accessibleBaseClassBothVirtualAndNonVirtualInHierarchyQuery()) and - // for each pair of classes, get all of their derivations - cd1 = c1.getADerivation() and - cd2 = c2.getADerivation() and - // where they share the same base class - base = cd1.getBaseClass() and - base = cd2.getBaseClass() and - // but one is virtual, and one is not, and the derivations are in different classes - cd1.isVirtual() and - not cd2.isVirtual() and - // and there is some 'other class' that derives from both of these classes - c3.derivesFrom*(c1) and - c3.derivesFrom*(c2) and - // and the base class is accessible from the 'other class' - c3.getAMemberFunction().getEnclosingAccessHolder().canAccessClass(base, c3) -select c3, "Class inherits base class $@, which is derived virtual by $@ and non-virtual by $@.", - base, base.getName(), cd1, cd1.getDerivedClass().toString(), c2, cd2.getDerivedClass().toString() +class AccessibleBaseClassBothVirtualAndNonVirtualInHierarchyQuery extends VirtualAndNonVirtualClassInTheHierarchySharedQuery +{ + AccessibleBaseClassBothVirtualAndNonVirtualInHierarchyQuery() { + this = InheritancePackage::accessibleBaseClassBothVirtualAndNonVirtualInHierarchyQuery() + } +} diff --git a/cpp/autosar/src/rules/M12-1-1/DynamicTypeOfThisUsedFromConstructorOrDestructor.ql b/cpp/autosar/src/rules/M12-1-1/DynamicTypeOfThisUsedFromConstructorOrDestructor.ql index 35f41c179a..4b6c037aba 100644 --- a/cpp/autosar/src/rules/M12-1-1/DynamicTypeOfThisUsedFromConstructorOrDestructor.ql +++ b/cpp/autosar/src/rules/M12-1-1/DynamicTypeOfThisUsedFromConstructorOrDestructor.ql @@ -14,79 +14,11 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.objectsdynamictypeusedfromconstructorordestructor.ObjectsDynamicTypeUsedFromConstructorOrDestructor -predicate thisCall(FunctionCall c) { - c.getQualifier() instanceof ThisExpr or - c.getQualifier().(PointerDereferenceExpr).getChild(0) instanceof ThisExpr -} - -predicate virtualThisCall(FunctionCall c, Function overridingFunction) { - c.isVirtual() and - thisCall(c) and - overridingFunction = c.getTarget().(VirtualFunction).getAnOverridingFunction() -} - -class DynamicTypeExpr extends Expr { - DynamicTypeExpr() { - this instanceof TypeidOperator and - this.getEnclosingFunction().getDeclaringType().isPolymorphic() - or - this instanceof DynamicCast - or - virtualThisCall(this.(FunctionCall), _) +class DynamicTypeOfThisUsedFromConstructorOrDestructorQuery extends ObjectsDynamicTypeUsedFromConstructorOrDestructorSharedQuery +{ + DynamicTypeOfThisUsedFromConstructorOrDestructorQuery() { + this = InheritancePackage::dynamicTypeOfThisUsedFromConstructorOrDestructorQuery() } } - -/* - * Catch most cases: go into functions in the same class, but only catch direct - * references to "this". - */ - -predicate nonVirtualMemberFunction(MemberFunction mf, Class c) { - mf = c.getAMemberFunction() and - not mf instanceof Constructor and - not mf instanceof Destructor and - not mf.isVirtual() -} - -predicate callFromNonVirtual(MemberFunction source, Class c, MemberFunction targ) { - exists(FunctionCall fc | - fc.getEnclosingFunction() = source and fc.getTarget() = targ and thisCall(fc) - ) and - targ = c.getAMemberFunction() and - nonVirtualMemberFunction(source, c) -} - -predicate indirectlyInvokesDynamicTypeExpr(MemberFunction caller, DynamicTypeExpr target) { - target = - any(DynamicTypeExpr expr | - expr.getEnclosingFunction() = caller and - nonVirtualMemberFunction(caller, caller.getDeclaringType()) - ) - or - exists(MemberFunction mid | - indirectlyInvokesDynamicTypeExpr(mid, target) and - callFromNonVirtual(caller, caller.getDeclaringType(), mid) - ) -} - -from DynamicTypeExpr expr, FunctionCall call, MemberFunction mf, string explanation -where - not isExcluded(expr, InheritancePackage::dynamicTypeOfThisUsedFromConstructorOrDestructorQuery()) and - ( - mf instanceof Constructor or - mf instanceof Destructor - ) and - ( - mf = expr.getEnclosingFunction() and - explanation = "$@ uses the dynamic type of its own object." - or - mf != expr.getEnclosingFunction() and - mf = call.getEnclosingFunction() and - thisCall(call) and - indirectlyInvokesDynamicTypeExpr(call.getTarget(), expr) and - explanation = - "$@ calls " + call.getTarget().getQualifiedName() + - ", which uses the dynamic type of its own object." - ) -select expr, explanation, mf, mf.getQualifiedName() diff --git a/cpp/autosar/src/rules/M14-5-3/CopyAssignmentOperatorNotDeclared.ql b/cpp/autosar/src/rules/M14-5-3/CopyAssignmentOperatorNotDeclared.ql index 05e99d6e66..1b41fe81bc 100644 --- a/cpp/autosar/src/rules/M14-5-3/CopyAssignmentOperatorNotDeclared.ql +++ b/cpp/autosar/src/rules/M14-5-3/CopyAssignmentOperatorNotDeclared.ql @@ -34,10 +34,10 @@ class TemplateAssignmentOperatorMember extends MemberFunction { } /** - * is a copy assigment operator candidate if it has only one param and form in [T, T&, const T&, volatile T&, const volatile T&] + * is a copy assignment operator candidate if it has only one param and form in [T, T&, const T&, volatile T&, const volatile T&] */ predicate hasGenericCopyCompatibleParameter() { - exists(TemplateParameter tp, Type pType | + exists(TypeTemplateParameter tp, Type pType | pType = this.getAParameter().getType().getUnspecifiedType() and //Parameter Type ( tp = pType //T diff --git a/cpp/autosar/src/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.ql b/cpp/autosar/src/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.ql index 2736d39290..486a428474 100644 --- a/cpp/autosar/src/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.ql +++ b/cpp/autosar/src/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.ql @@ -16,27 +16,11 @@ import cpp import codingstandards.cpp.autosar -import NameInDependentBase +import codingstandards.cpp.rules.namenotreferredusingaqualifiedidorthis.NameNotReferredUsingAQualifiedIdOrThis -from - TemplateClass c, NameQualifiableElement fn, string targetName, Element actualTarget, - Element dependentTypeMemberWithSameName -where - not isExcluded(fn, TemplatesPackage::nameNotReferredUsingAQualifiedIdOrThisQuery()) and - not isCustomExcluded(fn) and - missingNameQualifier(fn) and - ( - fn = getConfusingFunctionAccess(c, targetName, actualTarget, dependentTypeMemberWithSameName) - or - fn = getConfusingFunctionCall(c, targetName, actualTarget, dependentTypeMemberWithSameName) and - not exists(Expr e | e = fn.(FunctionCall).getQualifier()) - or - fn = - getConfusingMemberVariableAccess(c, targetName, actualTarget, dependentTypeMemberWithSameName) and - not exists(Expr e | e = fn.(VariableAccess).getQualifier()) - ) and - not fn.isAffectedByMacro() -select fn, - "Use of unqualified identifier " + targetName + - " targets $@ but a member with the name also exists $@.", actualTarget, targetName, - dependentTypeMemberWithSameName, "in the dependent base class" +class NameNotReferredUsingAQualifiedIdOrThisQuery extends NameNotReferredUsingAQualifiedIdOrThisSharedQuery +{ + NameNotReferredUsingAQualifiedIdOrThisQuery() { + this = TemplatesPackage::nameNotReferredUsingAQualifiedIdOrThisQuery() + } +} diff --git a/cpp/autosar/src/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.ql b/cpp/autosar/src/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.ql index 401edf3b61..ea56b841ed 100644 --- a/cpp/autosar/src/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.ql +++ b/cpp/autosar/src/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.ql @@ -16,27 +16,11 @@ import cpp import codingstandards.cpp.autosar -import NameInDependentBase +import codingstandards.cpp.rules.namenotreferredusingaqualifiedidorthisaudit.NameNotReferredUsingAQualifiedIdOrThisAudit -from - TemplateClass c, NameQualifiableElement fn, string targetName, Element actualTarget, - Element dependentTypeMemberWithSameName -where - not isExcluded(fn, TemplatesPackage::nameNotReferredUsingAQualifiedIdOrThisAuditQuery()) and - not isCustomExcluded(fn) and - missingNameQualifier(fn) and - ( - fn = getConfusingFunctionAccess(c, targetName, actualTarget, dependentTypeMemberWithSameName) - or - fn = getConfusingFunctionCall(c, targetName, actualTarget, dependentTypeMemberWithSameName) and - not exists(Expr e | e = fn.(FunctionCall).getQualifier()) - or - not fn.(VariableAccess).getTarget() instanceof Parameter and - fn = - getConfusingMemberVariableAccess(c, targetName, actualTarget, dependentTypeMemberWithSameName) and - not exists(Expr e | e = fn.(VariableAccess).getQualifier()) - ) -select fn, - "Use of unqualified identifier " + targetName + - " targets $@ but a member with the name also exists $@.", actualTarget, targetName, - dependentTypeMemberWithSameName, "in the dependent base class" +class NameNotReferredUsingAQualifiedIdOrThisAuditQuery extends NameNotReferredUsingAQualifiedIdOrThisAuditSharedQuery +{ + NameNotReferredUsingAQualifiedIdOrThisAuditQuery() { + this = TemplatesPackage::nameNotReferredUsingAQualifiedIdOrThisAuditQuery() + } +} diff --git a/cpp/autosar/src/rules/M15-1-3/EmptyThrowOutsideCatch.ql b/cpp/autosar/src/rules/M15-1-3/EmptyThrowOutsideCatch.ql index 7e263d66bb..9f99e7c356 100644 --- a/cpp/autosar/src/rules/M15-1-3/EmptyThrowOutsideCatch.ql +++ b/cpp/autosar/src/rules/M15-1-3/EmptyThrowOutsideCatch.ql @@ -15,9 +15,8 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.emptythrowonlywithinacatchhandler.EmptyThrowOnlyWithinACatchHandler -from ReThrowExpr re -where - not isExcluded(re, Exceptions1Package::emptyThrowOutsideCatchQuery()) and - not re.getEnclosingElement+() instanceof CatchBlock -select re, "Rethrow outside catch block" +class EmptyThrowOutsideCatchQuery extends EmptyThrowOnlyWithinACatchHandlerSharedQuery { + EmptyThrowOutsideCatchQuery() { this = Exceptions1Package::emptyThrowOutsideCatchQuery() } +} diff --git a/cpp/autosar/src/rules/M18-2-1/MacroOffsetofUsed.ql b/cpp/autosar/src/rules/M18-2-1/MacroOffsetofUsed.ql index a572497418..cd347be44d 100644 --- a/cpp/autosar/src/rules/M18-2-1/MacroOffsetofUsed.ql +++ b/cpp/autosar/src/rules/M18-2-1/MacroOffsetofUsed.ql @@ -15,9 +15,8 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.macrooffsetofused.MacroOffsetofUsed -from MacroInvocation mi -where - not isExcluded(mi, BannedFunctionsPackage::macroOffsetofUsedQuery()) and - mi.getMacroName() = "offsetof" -select mi, "Use of banned macro " + mi.getMacroName() + "." +class MacroOffsetofUsedQuery extends MacroOffsetofUsedSharedQuery { + MacroOffsetofUsedQuery() { this = BannedFunctionsPackage::macroOffsetofUsedQuery() } +} diff --git a/cpp/autosar/src/rules/M18-7-1/CsignalFunctionsUsed.ql b/cpp/autosar/src/rules/M18-7-1/CsignalFunctionsUsed.ql index ff264baffc..4df4715848 100644 --- a/cpp/autosar/src/rules/M18-7-1/CsignalFunctionsUsed.ql +++ b/cpp/autosar/src/rules/M18-7-1/CsignalFunctionsUsed.ql @@ -16,10 +16,8 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.csignalfunctionsused.CsignalFunctionsUsed -from FunctionCall fc, Function f -where - not isExcluded(fc, BannedLibrariesPackage::csignalFunctionsUsedQuery()) and - f = fc.getTarget() and - f.hasGlobalOrStdName(["signal", "raise"]) -select fc, "Use of function '" + f.getQualifiedName() + "'." +class CsignalFunctionsUsedQuery extends CsignalFunctionsUsedSharedQuery { + CsignalFunctionsUsedQuery() { this = BannedLibrariesPackage::csignalFunctionsUsedQuery() } +} diff --git a/cpp/autosar/src/rules/M18-7-1/CsignalTypesUsed.ql b/cpp/autosar/src/rules/M18-7-1/CsignalTypesUsed.ql index c91d56c572..89e9ca169a 100644 --- a/cpp/autosar/src/rules/M18-7-1/CsignalTypesUsed.ql +++ b/cpp/autosar/src/rules/M18-7-1/CsignalTypesUsed.ql @@ -16,10 +16,8 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.csignaltypesused.CsignalTypesUsed -from TypeMention tm, UserType ut -where - not isExcluded(tm, BannedLibrariesPackage::csignalTypesUsedQuery()) and - ut = tm.getMentionedType() and - ut.hasGlobalOrStdName("sig_atomic_t") -select tm, "Use of type '" + ut.getQualifiedName() + "'." +class CsignalTypesUsedQuery extends CsignalTypesUsedSharedQuery { + CsignalTypesUsedQuery() { this = BannedLibrariesPackage::csignalTypesUsedQuery() } +} diff --git a/cpp/autosar/src/rules/M2-13-2/UseOfNonZeroOctalLiteral.ql b/cpp/autosar/src/rules/M2-13-2/UseOfNonZeroOctalLiteral.ql index 2bd35e2484..b689edab6b 100644 --- a/cpp/autosar/src/rules/M2-13-2/UseOfNonZeroOctalLiteral.ql +++ b/cpp/autosar/src/rules/M2-13-2/UseOfNonZeroOctalLiteral.ql @@ -16,10 +16,8 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.Cpp14Literal +import codingstandards.cpp.rules.useofnonzerooctalliteral.UseOfNonZeroOctalLiteral -from Cpp14Literal::OctalLiteral octalLiteral -where - not isExcluded(octalLiteral, LiteralsPackage::useOfNonZeroOctalLiteralQuery()) and - not octalLiteral.getValue() = "0" -select octalLiteral, "Non zero octal literal " + octalLiteral.getValueText() + "." +class UseOfNonZeroOctalLiteralQuery extends UseOfNonZeroOctalLiteralSharedQuery { + UseOfNonZeroOctalLiteralQuery() { this = LiteralsPackage::useOfNonZeroOctalLiteralQuery() } +} diff --git a/cpp/autosar/src/rules/M2-13-3/MissingUSuffix.ql b/cpp/autosar/src/rules/M2-13-3/MissingUSuffix.ql index 25cae1e03f..5bfa338864 100644 --- a/cpp/autosar/src/rules/M2-13-3/MissingUSuffix.ql +++ b/cpp/autosar/src/rules/M2-13-3/MissingUSuffix.ql @@ -18,18 +18,8 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.Cpp14Literal +import codingstandards.cpp.rules.unsignedintegerliteralsnotappropriatelysuffixed.UnsignedIntegerLiteralsNotAppropriatelySuffixed -from Cpp14Literal::NumericLiteral nl, string literalKind -where - not isExcluded(nl, LiteralsPackage::missingUSuffixQuery()) and - ( - nl instanceof Cpp14Literal::OctalLiteral and literalKind = "Octal" - or - nl instanceof Cpp14Literal::HexLiteral and literalKind = "Hex" - ) and - // This either directly has an unsigned integer type, or it is converted to an unsigned integer type - nl.getType().getUnspecifiedType().(IntegralType).isUnsigned() and - // The literal already has a `u` or `U` suffix. - not nl.getValueText().regexpMatch(".*[lL]*[uU][lL]*") -select nl, literalKind + " literal is an unsigned integer but does not include a 'U' suffix." +class MissingUSuffixQuery extends UnsignedIntegerLiteralsNotAppropriatelySuffixedSharedQuery { + MissingUSuffixQuery() { this = LiteralsPackage::missingUSuffixQuery() } +} diff --git a/cpp/autosar/src/rules/M2-7-1/SlashStarUsedWithinACStyleComment.ql b/cpp/autosar/src/rules/M2-7-1/SlashStarUsedWithinACStyleComment.ql index 768acb0532..356a361cb1 100644 --- a/cpp/autosar/src/rules/M2-7-1/SlashStarUsedWithinACStyleComment.ql +++ b/cpp/autosar/src/rules/M2-7-1/SlashStarUsedWithinACStyleComment.ql @@ -16,9 +16,11 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.charactersequenceusedwithinacstylecomment.CharacterSequenceUsedWithinACStyleComment -from CStyleComment c -where - not isExcluded(c, CommentsPackage::slashStarUsedWithinACStyleCommentQuery()) and - exists(c.getContents().regexpFind("./\\*", _, _)) -select c, "C-style /* comment includes nested /*." +class SlashStarUsedWithinACStyleCommentQuery extends CharacterSequenceUsedWithinACStyleCommentSharedQuery +{ + SlashStarUsedWithinACStyleCommentQuery() { + this = CommentsPackage::slashStarUsedWithinACStyleCommentQuery() + } +} diff --git a/cpp/autosar/src/rules/M27-0-1/CstdioFunctionsUsed.ql b/cpp/autosar/src/rules/M27-0-1/CstdioFunctionsUsed.ql index 55254581a6..5656fc2edf 100644 --- a/cpp/autosar/src/rules/M27-0-1/CstdioFunctionsUsed.ql +++ b/cpp/autosar/src/rules/M27-0-1/CstdioFunctionsUsed.ql @@ -17,26 +17,8 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.cstdiofunctionsused.CstdioFunctionsUsed -from FunctionCall fc, Function f -where - not isExcluded(fc, BannedLibrariesPackage::cstdioFunctionsUsedQuery()) and - f = fc.getTarget() and - f.hasGlobalOrStdName([ - "remove", "rename", "tmpfile", "tmpnam", - // File access - "fclose", "fflush", "fopen", "freopen", "setbuf", "setvbuf", - // Formatted input/output - "fprintf", "fscanf", "printf", "scanf", "snprintf", "sprintf", "sscanf", "vfprintf", - "vfscanf", "vprintf", "vscanf", "vsnprintf", "vsprintf", "vsscanf", - // Character input/output - "fgetc", "fgets", "fputc", "fputs", "getc", "getchar", "gets", "putc", "putchar", "puts", - "ungetc", - // Direct input/output - "fread", "fwrite", - // File positioning - "fgetpos", "fseek", "fsetpos", "ftell", "rewind", - // Error handling - "clearerr", "feof", "ferror", "perror" - ]) -select fc, "Use of function '" + f.getQualifiedName() + "'." +class CstdioFunctionsUsedQuery extends CstdioFunctionsUsedSharedQuery { + CstdioFunctionsUsedQuery() { this = BannedLibrariesPackage::cstdioFunctionsUsedQuery() } +} diff --git a/cpp/autosar/src/rules/M27-0-1/CstdioMacrosUsed.ql b/cpp/autosar/src/rules/M27-0-1/CstdioMacrosUsed.ql index ccf633488e..311baeb195 100644 --- a/cpp/autosar/src/rules/M27-0-1/CstdioMacrosUsed.ql +++ b/cpp/autosar/src/rules/M27-0-1/CstdioMacrosUsed.ql @@ -17,12 +17,8 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.cstdiomacrosused.CstdioMacrosUsed -from MacroInvocation mi -where - not isExcluded(mi, BannedLibrariesPackage::cstdioMacrosUsedQuery()) and - mi.getMacroName() in [ - "BUFSIZ", "EOF", "FILENAME_MAX", "FOPEN_MAX", "L_tmpnam", "TMP_MAX", "_IOFBF", "IOLBF", - "_IONBF", "SEEK_CUR", "SEEK_END", "SEEK_SET" - ] -select mi, "Use of macro '" + mi.getMacroName() + "'." +class CstdioMacrosUsedQuery extends CstdioMacrosUsedSharedQuery { + CstdioMacrosUsedQuery() { this = BannedLibrariesPackage::cstdioMacrosUsedQuery() } +} diff --git a/cpp/autosar/src/rules/M27-0-1/CstdioTypesUsed.ql b/cpp/autosar/src/rules/M27-0-1/CstdioTypesUsed.ql index 6fc2adaffb..3a1f647c22 100644 --- a/cpp/autosar/src/rules/M27-0-1/CstdioTypesUsed.ql +++ b/cpp/autosar/src/rules/M27-0-1/CstdioTypesUsed.ql @@ -17,10 +17,8 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.cstdiotypesused.CstdioTypesUsed -from TypeMention tm, UserType ut -where - not isExcluded(tm, BannedLibrariesPackage::cstdioTypesUsedQuery()) and - ut = tm.getMentionedType() and - ut.hasGlobalOrStdName(["FILE", "fpos_t"]) -select tm, "Use of type '" + ut.getQualifiedName() + "'." +class CstdioTypesUsedQuery extends CstdioTypesUsedSharedQuery { + CstdioTypesUsedQuery() { this = BannedLibrariesPackage::cstdioTypesUsedQuery() } +} diff --git a/cpp/autosar/src/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql b/cpp/autosar/src/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql index f7e6664269..279ad08f3c 100644 --- a/cpp/autosar/src/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql +++ b/cpp/autosar/src/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow predicate pointeeIsModified(PointerDereferenceExpr e, Expr m) { exists(Assignment a | a.getLValue() = e and m = a) diff --git a/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql b/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql index 3b6e436c56..8e48c05ada 100644 --- a/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql +++ b/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql @@ -16,23 +16,19 @@ import cpp import codingstandards.cpp.autosar -from Variable v, Expr aexp +from Conversion c where - not isExcluded(v, + not isExcluded(c, StringsPackage::signedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValuesQuery()) and - // We find cases where it is an explicitly signed char type with an assignment - // to a non-numeric type. NOTE: This rule addresses cases where the char type - // is used character data only, the rule does not explicitly cover this. - // Please see M5-0-11 for explicit handling of this case. Get types that are - // char, except for ones that are 'plain', meaning the sign is explicit. + /* 1. Focus on implicit conversions only (explicit conversions are acceptable). */ + c.isImplicit() and + /* 2. The target type is explicitly signed or unsigned char. */ ( - v.getUnspecifiedType() instanceof SignedCharType or - v.getUnspecifiedType() instanceof UnsignedCharType + c.getUnspecifiedType() instanceof SignedCharType or + c.getUnspecifiedType() instanceof UnsignedCharType ) and - // Identify places where these explicitly signed types are being assigned to a - // non-numeric type. - aexp = v.getAnAssignedValue() and - aexp.getUnspecifiedType() instanceof CharType -select aexp, - "Assignment of an non-integer type to variable $@ which is a variable with an explicitly signed char type", - v, v.getName() + /* 3. Check if the source expression is a plain char type, i.e. not explicitly signed / unsigned. */ + c.getExpr().getUnspecifiedType() instanceof PlainCharType +select c, + "This expression of plain char type is implicitly converted to '" + + c.getUnspecifiedType().getName() + "'." diff --git a/cpp/autosar/src/rules/M5-0-17/PointerSubtractionOnDifferentArrays.ql b/cpp/autosar/src/rules/M5-0-17/PointerSubtractionOnDifferentArrays.ql index ec432cea42..d6d4f6130a 100644 --- a/cpp/autosar/src/rules/M5-0-17/PointerSubtractionOnDifferentArrays.ql +++ b/cpp/autosar/src/rules/M5-0-17/PointerSubtractionOnDifferentArrays.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import ArrayToPointerDiffOperandFlow::PathGraph module ArrayToPointerDiffOperandConfig implements DataFlow::ConfigSig { diff --git a/cpp/autosar/src/rules/M5-0-20/BitwiseOperatorOperandsHaveDifferentUnderlyingType.ql b/cpp/autosar/src/rules/M5-0-20/BitwiseOperatorOperandsHaveDifferentUnderlyingType.ql index 9e85a15e50..6d0554bf11 100644 --- a/cpp/autosar/src/rules/M5-0-20/BitwiseOperatorOperandsHaveDifferentUnderlyingType.ql +++ b/cpp/autosar/src/rules/M5-0-20/BitwiseOperatorOperandsHaveDifferentUnderlyingType.ql @@ -16,7 +16,6 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.Bitwise import codingstandards.cpp.Conversion predicate isBinaryBitwiseOperation(Operation o, VariableAccess l, VariableAccess r) { @@ -24,7 +23,7 @@ predicate isBinaryBitwiseOperation(Operation o, VariableAccess l, VariableAccess l = bbo.getLeftOperand() and r = bbo.getRightOperand() ) or - exists(Bitwise::AssignBitwiseOperation abo | abo = o | + exists(AssignBitwiseOperation abo | abo = o | l = abo.getLValue() and r = abo.getRValue() ) diff --git a/cpp/autosar/src/rules/M5-0-21/BitwiseOperatorAppliedToSignedTypes.ql b/cpp/autosar/src/rules/M5-0-21/BitwiseOperatorAppliedToSignedTypes.ql index d000155189..02bb5314cd 100644 --- a/cpp/autosar/src/rules/M5-0-21/BitwiseOperatorAppliedToSignedTypes.ql +++ b/cpp/autosar/src/rules/M5-0-21/BitwiseOperatorAppliedToSignedTypes.ql @@ -17,7 +17,6 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.Bitwise from Operation o, VariableAccess va where @@ -25,7 +24,7 @@ where ( o instanceof UnaryBitwiseOperation or o instanceof BinaryBitwiseOperation or - o instanceof Bitwise::AssignBitwiseOperation + o instanceof AssignBitwiseOperation ) and o.getAnOperand() = va and va.getTarget().getUnderlyingType().(IntegralType).isSigned() diff --git a/cpp/autosar/src/rules/M5-2-12/IdentifierWithArrayTypePassedAsFunctionArgumentDecayToAPointer.ql b/cpp/autosar/src/rules/M5-2-12/IdentifierWithArrayTypePassedAsFunctionArgumentDecayToAPointer.ql index 4207b4d56c..943fc026e8 100644 --- a/cpp/autosar/src/rules/M5-2-12/IdentifierWithArrayTypePassedAsFunctionArgumentDecayToAPointer.ql +++ b/cpp/autosar/src/rules/M5-2-12/IdentifierWithArrayTypePassedAsFunctionArgumentDecayToAPointer.ql @@ -15,33 +15,11 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.arraypassedasfunctionargumentdecaytoapointer.ArrayPassedAsFunctionArgumentDecayToAPointer -predicate arrayToPointerDecay(Access ae, Parameter p) { - ( - p.getType() instanceof PointerType and - // exclude parameters of void* because then it assumed the caller can pass in dimensions through other means. - // examples are uses in `memset` or `memcpy` - not p.getType() instanceof VoidPointerType - or - p.getType() instanceof ArrayType - ) and - ae.getType() instanceof ArrayType and - // exclude char[] arrays because we assume that we can determine its dimension by looking for a NULL byte. - not ae.getType().(ArrayType).getBaseType() instanceof CharType +class IdentifierWithArrayTypePassedAsFunctionArgumentDecayToAPointerQuery extends ArrayPassedAsFunctionArgumentDecayToAPointerSharedQuery +{ + IdentifierWithArrayTypePassedAsFunctionArgumentDecayToAPointerQuery() { + this = PointersPackage::identifierWithArrayTypePassedAsFunctionArgumentDecayToAPointerQuery() + } } - -from - FunctionCall fc, Function f, Parameter decayedArray, Variable array, VariableAccess arrayAccess, - int i -where - not isExcluded(fc, - PointersPackage::identifierWithArrayTypePassedAsFunctionArgumentDecayToAPointerQuery()) and - arrayAccess = array.getAnAccess() and - f = fc.getTarget() and - arrayAccess = fc.getArgument(i) and - decayedArray = f.getParameter(i) and - arrayToPointerDecay(arrayAccess, decayedArray) and - not arrayAccess.isAffectedByMacro() -select fc.getArgument(i), - "The array $@ decays to the pointer $@ when passed as an argument to the function $@.", array, - array.getName(), decayedArray, decayedArray.getName(), f, f.getName() diff --git a/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql b/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql index 8f20bf808e..ad49d9e151 100644 --- a/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql +++ b/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql @@ -15,15 +15,11 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow +import codingstandards.cpp.rules.pointertoavirtualbaseclasscasttoapointer.PointerToAVirtualBaseClassCastToAPointer -from Cast cast, VirtualBaseClass castFrom, Class castTo -where - not isExcluded(cast, PointersPackage::pointerToAVirtualBaseClassCastToAPointerQuery()) and - not cast instanceof DynamicCast and - castFrom = cast.getExpr().getType().(PointerType).getBaseType() and - cast.getType().(PointerType).getBaseType() = castTo and - castTo = castFrom.getADerivedClass+() -select cast, - "A pointer to virtual base class $@ is not cast to a pointer of derived class $@ using a dynamic_cast.", - castFrom, castFrom.getName(), castTo, castTo.getName() +class PointerToAVirtualBaseClassCastToAPointerQuery extends PointerToAVirtualBaseClassCastToAPointerSharedQuery +{ + PointerToAVirtualBaseClassCastToAPointerQuery() { + this = PointersPackage::pointerToAVirtualBaseClassCastToAPointerQuery() + } +} diff --git a/cpp/autosar/src/rules/M5-2-6/CastNotConvertPointerToFunction.ql b/cpp/autosar/src/rules/M5-2-6/CastNotConvertPointerToFunction.ql index b6a51dc0ab..5a8df45ab1 100644 --- a/cpp/autosar/src/rules/M5-2-6/CastNotConvertPointerToFunction.ql +++ b/cpp/autosar/src/rules/M5-2-6/CastNotConvertPointerToFunction.ql @@ -15,11 +15,11 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.castsbetweenapointertofunctionandanyothertype.CastsBetweenAPointerToFunctionAndAnyOtherType -from Cast c -where - not isExcluded(c, PointersPackage::castNotConvertPointerToFunctionQuery()) and - not c.isImplicit() and - not c.isAffectedByMacro() and - c.getExpr().getType() instanceof FunctionPointerType -select c, "Cast converting a pointer to function." +class CastNotConvertPointerToFunctionQuery extends CastsBetweenAPointerToFunctionAndAnyOtherTypeSharedQuery +{ + CastNotConvertPointerToFunctionQuery() { + this = PointersPackage::castNotConvertPointerToFunctionQuery() + } +} diff --git a/cpp/autosar/src/rules/M5-3-1/EachOperandOfTheOperatorTheLogicalAndOrTheLogicalOperatorsShallHaveTypeBool.ql b/cpp/autosar/src/rules/M5-3-1/EachOperandOfTheOperatorTheLogicalAndOrTheLogicalOperatorsShallHaveTypeBool.ql index 03b4ae7f1c..e4589a364a 100644 --- a/cpp/autosar/src/rules/M5-3-1/EachOperandOfTheOperatorTheLogicalAndOrTheLogicalOperatorsShallHaveTypeBool.ql +++ b/cpp/autosar/src/rules/M5-3-1/EachOperandOfTheOperatorTheLogicalAndOrTheLogicalOperatorsShallHaveTypeBool.ql @@ -25,6 +25,11 @@ where ) and t = operand.getType() and not t.getUnderlyingType().getUnspecifiedType() instanceof BoolType and + // Ignore cases where the type is unknown - this will typically be in unevaluated contexts + // within uninstantiated templates. It's necessary to check for this explicitly because + // not all unevaluated contexts are considered to be `isFromUninstantiatedTemplate(_)`, + // e.g. `noexcept` specifiers + not t instanceof UnknownType and not exists(ReferenceType rt | rt = t.getUnderlyingType().getUnspecifiedType() and rt.getBaseType() instanceof BoolType ) and diff --git a/cpp/autosar/src/rules/M5-3-2/UnaryMinusOperatorAppliedToAnExpressionWhoseUnderlyingTypeIsUnsigned.ql b/cpp/autosar/src/rules/M5-3-2/UnaryMinusOperatorAppliedToAnExpressionWhoseUnderlyingTypeIsUnsigned.ql index 0367f0aebe..7017d5e7de 100644 --- a/cpp/autosar/src/rules/M5-3-2/UnaryMinusOperatorAppliedToAnExpressionWhoseUnderlyingTypeIsUnsigned.ql +++ b/cpp/autosar/src/rules/M5-3-2/UnaryMinusOperatorAppliedToAnExpressionWhoseUnderlyingTypeIsUnsigned.ql @@ -14,13 +14,12 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.builtinunaryoperatorappliedtounsignedexpression.BuiltInUnaryOperatorAppliedToUnsignedExpression -from UnaryMinusExpr e, IntegralType t -where - not isExcluded(e, - OperatorsPackage::unaryMinusOperatorAppliedToAnExpressionWhoseUnderlyingTypeIsUnsignedQuery()) and - t = e.getOperand().getExplicitlyConverted().getType().getUnderlyingType() and - t.isUnsigned() and - not e.isAffectedByMacro() -select e.getOperand(), - "The unary minus operator shall not be applied to an expression whose underlying type is unsigned." +class UnaryMinusOperatorAppliedToAnExpressionWhoseUnderlyingTypeIsUnsignedQuery extends BuiltInUnaryOperatorAppliedToUnsignedExpressionSharedQuery +{ + UnaryMinusOperatorAppliedToAnExpressionWhoseUnderlyingTypeIsUnsignedQuery() { + this = + OperatorsPackage::unaryMinusOperatorAppliedToAnExpressionWhoseUnderlyingTypeIsUnsignedQuery() + } +} diff --git a/cpp/autosar/src/rules/M5-3-3/UnaryOperatorOverloaded.ql b/cpp/autosar/src/rules/M5-3-3/UnaryOperatorOverloaded.ql index 7e9511cf7e..94f0bc6062 100644 --- a/cpp/autosar/src/rules/M5-3-3/UnaryOperatorOverloaded.ql +++ b/cpp/autosar/src/rules/M5-3-3/UnaryOperatorOverloaded.ql @@ -13,8 +13,8 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.Operator +import codingstandards.cpp.rules.addressofoperatoroverloaded.AddressOfOperatorOverloaded -from UnaryAddressOfOperator o -where not isExcluded(o, OperatorsPackage::unaryOperatorOverloadedQuery()) -select o, "The unary & operator overloaded." +class UnaryOperatorOverloadedQuery extends AddressOfOperatorOverloadedSharedQuery { + UnaryOperatorOverloadedQuery() { this = OperatorsPackage::unaryOperatorOverloadedQuery() } +} diff --git a/cpp/autosar/src/rules/M5-8-1/RightBitShiftOperandIsNegativeOrTooWide.ql b/cpp/autosar/src/rules/M5-8-1/RightBitShiftOperandIsNegativeOrTooWide.ql index 38da7115f3..b94d76fd94 100644 --- a/cpp/autosar/src/rules/M5-8-1/RightBitShiftOperandIsNegativeOrTooWide.ql +++ b/cpp/autosar/src/rules/M5-8-1/RightBitShiftOperandIsNegativeOrTooWide.ql @@ -17,7 +17,6 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.Bitwise class ShiftOperation extends Operation { Expr leftOperand; @@ -34,7 +33,7 @@ class ShiftOperation extends Operation { rightOperand = o.getRightOperand() ) or - exists(Bitwise::AssignBitwiseOperation o | this = o | + exists(AssignBitwiseOperation o | this = o | ( o instanceof AssignLShiftExpr or diff --git a/cpp/autosar/src/rules/M6-3-1/LoopCompoundCondition.ql b/cpp/autosar/src/rules/M6-3-1/LoopCompoundCondition.ql index 1c6c0b980e..b3566a1e27 100644 --- a/cpp/autosar/src/rules/M6-3-1/LoopCompoundCondition.ql +++ b/cpp/autosar/src/rules/M6-3-1/LoopCompoundCondition.ql @@ -16,9 +16,8 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.loopcompoundcondition.LoopCompoundCondition -from Loop loop -where - not isExcluded(loop, ConditionalsPackage::loopCompoundConditionQuery()) and - not loop.getStmt() instanceof BlockStmt -select loop, "Loop body not enclosed within braces." +class LoopCompoundConditionQuery extends LoopCompoundConditionSharedQuery { + LoopCompoundConditionQuery() { this = ConditionalsPackage::loopCompoundConditionQuery() } +} diff --git a/cpp/autosar/src/rules/M6-3-1/SwitchCompoundCondition.ql b/cpp/autosar/src/rules/M6-3-1/SwitchCompoundCondition.ql index ee83f44ccf..f550a456dc 100644 --- a/cpp/autosar/src/rules/M6-3-1/SwitchCompoundCondition.ql +++ b/cpp/autosar/src/rules/M6-3-1/SwitchCompoundCondition.ql @@ -16,36 +16,8 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.switchcompoundcondition.SwitchCompoundCondition -/** - * Class to differentiate between extractor generated blockstmt and actual blockstmt. The extractor - * will generate an artificial blockstmt when there is a single case and statement, e.g. - * ``` - * switch(x) - * case 1: - * f(); - * ``` - * This is because our AST model considers the `case` to be a statement in its own right, so the - * extractor needs an aritifical block to hold both the case and the statement. - */ -class ArtificialBlock extends BlockStmt { - ArtificialBlock() { - exists(Location block, Location firstStatement | - block = getLocation() and firstStatement = getStmt(0).getLocation() - | - // We can identify artificial blocks as those where the start of the statement is at the same - // location as the start of the first statement in the block i.e. there was no opening brace. - block.getStartLine() = firstStatement.getStartLine() and - block.getStartColumn() = firstStatement.getStartColumn() - ) - } +class SwitchCompoundConditionQuery extends SwitchCompoundConditionSharedQuery { + SwitchCompoundConditionQuery() { this = ConditionalsPackage::switchCompoundConditionQuery() } } - -from SwitchStmt switch -where - not isExcluded(switch, ConditionalsPackage::switchCompoundConditionQuery()) and - ( - switch.getStmt() instanceof ArtificialBlock or - not switch.getStmt() instanceof BlockStmt - ) -select switch, "Switch body not enclosed within braces." diff --git a/cpp/autosar/src/rules/M7-3-1/GlobalNamespaceMembershipViolation.ql b/cpp/autosar/src/rules/M7-3-1/GlobalNamespaceMembershipViolation.ql index cb714a65f2..e359880027 100644 --- a/cpp/autosar/src/rules/M7-3-1/GlobalNamespaceMembershipViolation.ql +++ b/cpp/autosar/src/rules/M7-3-1/GlobalNamespaceMembershipViolation.ql @@ -16,13 +16,10 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.globalnamespacedeclarations.GlobalNamespaceDeclarations -from DeclarationEntry de -where - not isExcluded(de, ScopePackage::globalNamespaceMembershipViolationQuery()) and - de.getDeclaration().getNamespace() instanceof GlobalNamespace and - de.getDeclaration().isTopLevel() and - not exists(Function f | f = de.getDeclaration() | f.hasGlobalName("main") or f.hasCLinkage()) -select de, - "Declaration " + de.getName() + - " is in the global namespace and is not a main, a namespace, or an extern \"C\" declaration." +class GlobalNamespaceMembershipViolationQuery extends GlobalNamespaceDeclarationsSharedQuery { + GlobalNamespaceMembershipViolationQuery() { + this = ScopePackage::globalNamespaceMembershipViolationQuery() + } +} diff --git a/cpp/autosar/src/rules/M7-3-2/IdentifierMainUsedForAFunctionOtherThanTheGlobalFunctionMain.ql b/cpp/autosar/src/rules/M7-3-2/IdentifierMainUsedForAFunctionOtherThanTheGlobalFunctionMain.ql index 9d86bd3637..25a01c66f8 100644 --- a/cpp/autosar/src/rules/M7-3-2/IdentifierMainUsedForAFunctionOtherThanTheGlobalFunctionMain.ql +++ b/cpp/autosar/src/rules/M7-3-2/IdentifierMainUsedForAFunctionOtherThanTheGlobalFunctionMain.ql @@ -15,11 +15,11 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.nonglobalfunctionmain.NonGlobalFunctionMain -from Function f -where - not isExcluded(f, - NamingPackage::identifierMainUsedForAFunctionOtherThanTheGlobalFunctionMainQuery()) and - f.hasName("main") and - not f.hasGlobalName("main") -select f, "Identifier main used for a function other than the global function main." +class IdentifierMainUsedForAFunctionOtherThanTheGlobalFunctionMainQuery extends NonGlobalFunctionMainSharedQuery +{ + IdentifierMainUsedForAFunctionOtherThanTheGlobalFunctionMainQuery() { + this = NamingPackage::identifierMainUsedForAFunctionOtherThanTheGlobalFunctionMainQuery() + } +} diff --git a/cpp/autosar/src/rules/M7-5-1/FunctionReturnAutomaticVarCondition.ql b/cpp/autosar/src/rules/M7-5-1/FunctionReturnAutomaticVarCondition.ql index e35858f40b..cb5aa9d105 100644 --- a/cpp/autosar/src/rules/M7-5-1/FunctionReturnAutomaticVarCondition.ql +++ b/cpp/autosar/src/rules/M7-5-1/FunctionReturnAutomaticVarCondition.ql @@ -16,19 +16,11 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.returnreferenceorpointertoautomaticlocalvariable.ReturnReferenceOrPointerToAutomaticLocalVariable -from ReturnStmt rs, StackVariable auto, Function f, VariableAccess va, string returnType -where - f = rs.getEnclosingFunction() and - ( - f.getType() instanceof ReferenceType and va = rs.getExpr() and returnType = "reference" - or - f.getType() instanceof PointerType and - va = rs.getExpr().(AddressOfExpr).getOperand() and - returnType = "pointer" - ) and - auto = va.getTarget() and - not auto.isStatic() and - not f.isCompilerGenerated() and - not auto.getType() instanceof ReferenceType -select rs, "The $@ returns a " + returnType + "to an $@ variable", f, f.getName(), auto, "automatic" +class FunctionReturnAutomaticVarConditionQuery extends ReturnReferenceOrPointerToAutomaticLocalVariableSharedQuery +{ + FunctionReturnAutomaticVarConditionQuery() { + this = FunctionsPackage::functionReturnAutomaticVarConditionQuery() + } +} diff --git a/cpp/autosar/src/rules/M8-0-1/MultipleGlobalOrMemberDeclarators.ql b/cpp/autosar/src/rules/M8-0-1/MultipleGlobalOrMemberDeclarators.ql index 8d16fccd94..c152821ab2 100644 --- a/cpp/autosar/src/rules/M8-0-1/MultipleGlobalOrMemberDeclarators.ql +++ b/cpp/autosar/src/rules/M8-0-1/MultipleGlobalOrMemberDeclarators.ql @@ -16,57 +16,10 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.multipleglobalormemberdeclarators.MultipleGlobalOrMemberDeclarators -/* - * Unfortunately, we do not have an equivalent of `DeclStmt` for non-local declarations, so we - * cannot determine whether a declaration was declared with another declaration. - * - * However, we can use location trickery to figure out if the declaration occurs close enough to - * another declaration that it _must_ have been declared within the same declaration sequence. - * - * We do this by requiring that the end location of a previous declaration is within a certain - * number of characters of the start location of the current declaration. - */ - -/** - * A `Declaration` which is not in a local scope, and is written directly by the user. - * - * These act as "candidates" for declarations that could plausibly occur in a declaration sequence - * with other candidates. - */ -class NonLocalUserDeclaration extends Declaration { - NonLocalUserDeclaration() { - not this instanceof StackVariable and - not this instanceof TemplateParameter and - not this instanceof EnumConstant and - not this instanceof TypedefType and - not any(LambdaCapture lc).getField() = this and - not this.(Function).isCompilerGenerated() and - not this.(Variable).isCompilerGenerated() and - not this.(Parameter).getFunction().isCompilerGenerated() and - not this.isInMacroExpansion() and - not exists(Struct s, TypedefType t | - s.isAnonymous() and - t.getBaseType() = s and - this = s.getAMemberVariable() - ) +class MultipleGlobalOrMemberDeclaratorsQuery extends MultipleGlobalOrMemberDeclaratorsSharedQuery { + MultipleGlobalOrMemberDeclaratorsQuery() { + this = InitializationPackage::multipleGlobalOrMemberDeclaratorsQuery() } } - -/** - * Holds if `d1` is followed directly by `d2`. - */ -predicate isFollowingDeclaration(NonLocalUserDeclaration d1, NonLocalUserDeclaration d2) { - exists(string filepath, int startline, int startcolumn, int endline, int endcolumn | - d1.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and - d2.getLocation().hasLocationInfo(filepath, startline, endcolumn + [2 .. 3], endline, _) - ) and - not d1.(UserType).stripType() = d2.(Variable).getType().stripType() -} - -from NonLocalUserDeclaration d1 -where - not isExcluded(d1, InitializationPackage::multipleGlobalOrMemberDeclaratorsQuery()) and - isFollowingDeclaration(d1, _) and - not isFollowingDeclaration(_, d1) -select d1, "Multiple declarations after " + d1.getName() + " in this declaration sequence." diff --git a/cpp/autosar/src/rules/M8-0-1/MultipleLocalDeclarators.ql b/cpp/autosar/src/rules/M8-0-1/MultipleLocalDeclarators.ql index 7545315b7e..6198ab7a5a 100644 --- a/cpp/autosar/src/rules/M8-0-1/MultipleLocalDeclarators.ql +++ b/cpp/autosar/src/rules/M8-0-1/MultipleLocalDeclarators.ql @@ -16,11 +16,8 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.multiplelocaldeclarators.MultipleLocalDeclarators -from DeclStmt ds -where - not isExcluded(ds, InitializationPackage::multipleLocalDeclaratorsQuery()) and - count(Declaration d | d = ds.getADeclaration()) > 1 and - // Not a compiler generated `DeclStmt`, such as in the range-based for loop - not ds.isCompilerGenerated() -select ds, "Declaration list contains more than one declaration." +class MultipleLocalDeclaratorsQuery extends MultipleLocalDeclaratorsSharedQuery { + MultipleLocalDeclaratorsQuery() { this = InitializationPackage::multipleLocalDeclaratorsQuery() } +} diff --git a/cpp/autosar/src/rules/M8-3-1/VirtualFunctionParametersUseTheSameDefaultArguments.ql b/cpp/autosar/src/rules/M8-3-1/VirtualFunctionParametersUseTheSameDefaultArguments.ql index 9d2b2d2006..a0ef5143e9 100644 --- a/cpp/autosar/src/rules/M8-3-1/VirtualFunctionParametersUseTheSameDefaultArguments.ql +++ b/cpp/autosar/src/rules/M8-3-1/VirtualFunctionParametersUseTheSameDefaultArguments.ql @@ -16,29 +16,11 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.overridingshallspecifydifferentdefaultarguments.OverridingShallSpecifyDifferentDefaultArguments -from VirtualFunction f1, VirtualFunction f2 -where - not isExcluded(f1, - VirtualFunctionsPackage::virtualFunctionParametersUseTheSameDefaultArgumentsQuery()) and - not isExcluded(f2, - VirtualFunctionsPackage::virtualFunctionParametersUseTheSameDefaultArgumentsQuery()) and - f2 = f1.getAnOverridingFunction() and - exists(Parameter p1, Parameter p2 | - p1 = f1.getAParameter() and - p2 = f2.getParameter(p1.getIndex()) - | - if p1.hasInitializer() - then - // if there is no initializer - not p2.hasInitializer() - or - // if there is one and it doesn't match - not p1.getInitializer().getExpr().getValueText() = - p2.getInitializer().getExpr().getValueText() - else - // if p1 doesn't have an initializer p2 shouldn't either - p2.hasInitializer() - ) -select f2, "$@ does not have the same default parameters as $@", f2, "overriding function", f1, - "overridden function" +class VirtualFunctionParametersUseTheSameDefaultArgumentsQuery extends OverridingShallSpecifyDifferentDefaultArgumentsSharedQuery +{ + VirtualFunctionParametersUseTheSameDefaultArgumentsQuery() { + this = VirtualFunctionsPackage::virtualFunctionParametersUseTheSameDefaultArgumentsQuery() + } +} diff --git a/cpp/autosar/src/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.ql b/cpp/autosar/src/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.ql index 98207a62a3..559b41527c 100644 --- a/cpp/autosar/src/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.ql +++ b/cpp/autosar/src/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.ql @@ -18,7 +18,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow class ReferenceTypeWithNonConstBaseType extends ReferenceType { ReferenceTypeWithNonConstBaseType() { not this.getBaseType().isConst() } diff --git a/cpp/autosar/src/rules/M9-6-4/NamedBitFieldsWithSignedIntegerTypeShallHaveALengthOfMoreThanOneBit.ql b/cpp/autosar/src/rules/M9-6-4/NamedBitFieldsWithSignedIntegerTypeShallHaveALengthOfMoreThanOneBit.ql index 7748f26ec1..96e434633e 100644 --- a/cpp/autosar/src/rules/M9-6-4/NamedBitFieldsWithSignedIntegerTypeShallHaveALengthOfMoreThanOneBit.ql +++ b/cpp/autosar/src/rules/M9-6-4/NamedBitFieldsWithSignedIntegerTypeShallHaveALengthOfMoreThanOneBit.ql @@ -22,4 +22,4 @@ where bf.getType().getUnderlyingType().(IntegralType).isSigned() and bf.getNumBits() < 2 and bf.getName() != "(unnamed bitfield)" -select bf, "A named bit-field with signed integral type should have at least 2 bits of storage " +select bf, "A named bit-field with signed integral type should have at least 2 bits of storage." diff --git a/cpp/autosar/test/codeql-pack.lock.yml b/cpp/autosar/test/codeql-pack.lock.yml index 514e6963d0..a45ea8f438 100644 --- a/cpp/autosar/test/codeql-pack.lock.yml +++ b/cpp/autosar/test/codeql-pack.lock.yml @@ -2,13 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.9.3 + version: 4.0.3 codeql/dataflow: - version: 0.0.4 + version: 2.0.3 + codeql/mad: + version: 1.0.19 + codeql/rangeanalysis: + version: 1.0.19 codeql/ssa: - version: 0.1.5 + version: 1.0.19 codeql/tutorial: - version: 0.1.5 + version: 1.0.19 + codeql/typeflow: + version: 1.0.19 + codeql/typetracking: + version: 2.0.3 codeql/util: - version: 0.1.5 + version: 2.0.6 + codeql/xml: + version: 1.0.19 compiled: false diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index baf5a22a15..040c140538 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.32.0-dev +version: 2.52.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/autosar/test/rules/A0-1-1/UselessAssignment.expected b/cpp/autosar/test/rules/A0-1-1/UselessAssignment.expected index bdd73be2eb..a38f3afddf 100644 --- a/cpp/autosar/test/rules/A0-1-1/UselessAssignment.expected +++ b/cpp/autosar/test/rules/A0-1-1/UselessAssignment.expected @@ -12,3 +12,5 @@ | test.cpp:94:11:94:17 | new | Definition of $@ is unused. | test.cpp:94:6:94:7 | b4 | b4 | | test.cpp:95:11:95:17 | 0 | Definition of $@ is unused. | test.cpp:95:6:95:7 | b5 | b5 | | test.cpp:103:11:103:17 | 0 | Definition of $@ is unused. | test.cpp:103:6:103:7 | c5 | c5 | +| test.cpp:132:43:132:45 | {...} | Definition of $@ is unused. | test.cpp:132:7:132:18 | unused_array | unused_array | +| test.cpp:134:29:134:31 | 0 | Definition of $@ is unused. | test.cpp:134:17:134:26 | unused_int | unused_int | diff --git a/cpp/autosar/test/rules/A0-1-1/test.cpp b/cpp/autosar/test/rules/A0-1-1/test.cpp index 021b1bf792..694396406a 100644 --- a/cpp/autosar/test/rules/A0-1-1/test.cpp +++ b/cpp/autosar/test/rules/A0-1-1/test.cpp @@ -123,4 +123,16 @@ template void test_range_based_for_loop_template() { // template elem; } -} \ No newline at end of file +} + +#include + +std::int32_t test_constexpr_array_size() { + constexpr int constexpr_array_size = 7; // COMPLIANT + int unused_array[constexpr_array_size] = {}; // NON_COMPLIANT + + constexpr int unused_int = {}; // NON_COMPLIANT + + std::int32_t used_array[] = {-1, 0, 1}; // COMPLIANT + return used_array[1]; +} diff --git a/cpp/autosar/test/rules/A1-1-2.2/CompilerWarningLevelNotInCompliance.expected b/cpp/autosar/test/rules/A1-1-2.2/CompilerWarningLevelNotInCompliance.expected index e69de29bb2..81a5c4327e 100644 --- a/cpp/autosar/test/rules/A1-1-2.2/CompilerWarningLevelNotInCompliance.expected +++ b/cpp/autosar/test/rules/A1-1-2.2/CompilerWarningLevelNotInCompliance.expected @@ -0,0 +1 @@ +| Wcast-function-type.cpp:0:0:0:0 | Wcast-function-type.cpp | No warning-level options were used in the compilation of 'Wcast-function-type.cpp'. | diff --git a/cpp/autosar/test/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.expected b/cpp/autosar/test/rules/A1-1-2.2/CompilerWarningLevelNotInCompliance.expected.clang similarity index 100% rename from cpp/autosar/test/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.expected rename to cpp/autosar/test/rules/A1-1-2.2/CompilerWarningLevelNotInCompliance.expected.clang diff --git a/cpp/autosar/test/rules/A1-1-2.2/CompilerWarningLevelNotInCompliance.expected.gcc b/cpp/autosar/test/rules/A1-1-2.2/CompilerWarningLevelNotInCompliance.expected.gcc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/autosar/test/rules/A1-1-2.2/CompilerWarningLevelNotInCompliance.expected.qcc b/cpp/autosar/test/rules/A1-1-2.2/CompilerWarningLevelNotInCompliance.expected.qcc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/autosar/test/rules/A1-1-2.2/Wcast-function-type.cpp b/cpp/autosar/test/rules/A1-1-2.2/Wcast-function-type.cpp index f405349bbb..bc48268931 100644 --- a/cpp/autosar/test/rules/A1-1-2.2/Wcast-function-type.cpp +++ b/cpp/autosar/test/rules/A1-1-2.2/Wcast-function-type.cpp @@ -1,2 +1,14 @@ // semmle-extractor-options: --clang -std=c++14 -Wcast-function-type -// COMPLIANT \ No newline at end of file +// COMPLIANT + +// NOTE: When tested with `codeql test run`, the test extractor provides `-w` +// which overrides `-Wcast-function-type` and causes this test case to be +// non-compliant. +// +// However, when tested with our compiler matrix tests, this test db is built +// via `codeql database create --command="..."`, and the `-w` flag will NOT be +// used. This means the `-Wcast-function-type` flag is active and the test case +// is compliant. +// +// Therefore, the .expected file for this test expects non-compliance, and the +// .expected.gcc and .expected.clang files expect this test to be compliant. diff --git a/cpp/autosar/test/rules/A1-1-2.4/CompilerWarningLevelNotInCompliance.expected b/cpp/autosar/test/rules/A1-1-2.4/CompilerWarningLevelNotInCompliance.expected new file mode 100644 index 0000000000..dd7f320be2 --- /dev/null +++ b/cpp/autosar/test/rules/A1-1-2.4/CompilerWarningLevelNotInCompliance.expected @@ -0,0 +1 @@ +| Wformat=0-Wno-format-security.cpp:0:0:0:0 | Wformat=0-Wno-format-security.cpp | No warning-level options were used in the compilation of 'Wformat=0-Wno-format-security.cpp'. | diff --git a/cpp/autosar/test/rules/A1-1-2.4/CompilerWarningLevelNotInCompliance.qlref b/cpp/autosar/test/rules/A1-1-2.4/CompilerWarningLevelNotInCompliance.qlref new file mode 100644 index 0000000000..30fb98b639 --- /dev/null +++ b/cpp/autosar/test/rules/A1-1-2.4/CompilerWarningLevelNotInCompliance.qlref @@ -0,0 +1 @@ +rules/A1-1-2/CompilerWarningLevelNotInCompliance.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A1-1-2.4/Wformat=0-Wno-format-security.cpp b/cpp/autosar/test/rules/A1-1-2.4/Wformat=0-Wno-format-security.cpp new file mode 100644 index 0000000000..29523ad24e --- /dev/null +++ b/cpp/autosar/test/rules/A1-1-2.4/Wformat=0-Wno-format-security.cpp @@ -0,0 +1,2 @@ +// semmle-extractor-options: --clang -std=c++14 -Wformat=0 -Wno-format-security +// NON_COMPLIANT \ No newline at end of file diff --git a/cpp/autosar/test/rules/A1-1-2.4/options.clang b/cpp/autosar/test/rules/A1-1-2.4/options.clang new file mode 100644 index 0000000000..4544f91ecb --- /dev/null +++ b/cpp/autosar/test/rules/A1-1-2.4/options.clang @@ -0,0 +1 @@ +-Wformat=0 -Wno-format-security \ No newline at end of file diff --git a/cpp/autosar/test/rules/A1-1-2.4/options.gcc b/cpp/autosar/test/rules/A1-1-2.4/options.gcc new file mode 100644 index 0000000000..4544f91ecb --- /dev/null +++ b/cpp/autosar/test/rules/A1-1-2.4/options.gcc @@ -0,0 +1 @@ +-Wformat=0 -Wno-format-security \ No newline at end of file diff --git a/cpp/autosar/test/rules/A1-1-2.4/options.qcc b/cpp/autosar/test/rules/A1-1-2.4/options.qcc new file mode 100644 index 0000000000..e28a2c3ac5 --- /dev/null +++ b/cpp/autosar/test/rules/A1-1-2.4/options.qcc @@ -0,0 +1 @@ +-Wno-format -Wno-format-security \ No newline at end of file diff --git a/cpp/autosar/test/rules/A1-1-2.5/CompilerWarningLevelNotInCompliance.expected b/cpp/autosar/test/rules/A1-1-2.5/CompilerWarningLevelNotInCompliance.expected new file mode 100644 index 0000000000..df69d21d5a --- /dev/null +++ b/cpp/autosar/test/rules/A1-1-2.5/CompilerWarningLevelNotInCompliance.expected @@ -0,0 +1 @@ +| Wall-Wno-format.cpp:0:0:0:0 | Wall-Wno-format.cpp | No warning-level options were used in the compilation of 'Wall-Wno-format.cpp'. | \ No newline at end of file diff --git a/cpp/autosar/test/rules/A1-1-2.5/CompilerWarningLevelNotInCompliance.expected.clang b/cpp/autosar/test/rules/A1-1-2.5/CompilerWarningLevelNotInCompliance.expected.clang new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/autosar/test/rules/A1-1-2.5/CompilerWarningLevelNotInCompliance.expected.gcc b/cpp/autosar/test/rules/A1-1-2.5/CompilerWarningLevelNotInCompliance.expected.gcc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/autosar/test/rules/A1-1-2.5/CompilerWarningLevelNotInCompliance.expected.qcc b/cpp/autosar/test/rules/A1-1-2.5/CompilerWarningLevelNotInCompliance.expected.qcc new file mode 100644 index 0000000000..c6354c2475 --- /dev/null +++ b/cpp/autosar/test/rules/A1-1-2.5/CompilerWarningLevelNotInCompliance.expected.qcc @@ -0,0 +1 @@ +| Wall-Wno-format.cpp:0:0:0:0 | Wall-Wno-format.cpp | No warning-level options were used in the compilation of 'Wall-Wno-format.cpp'. | diff --git a/cpp/autosar/test/rules/A1-1-2.5/CompilerWarningLevelNotInCompliance.qlref b/cpp/autosar/test/rules/A1-1-2.5/CompilerWarningLevelNotInCompliance.qlref new file mode 100644 index 0000000000..30fb98b639 --- /dev/null +++ b/cpp/autosar/test/rules/A1-1-2.5/CompilerWarningLevelNotInCompliance.qlref @@ -0,0 +1 @@ +rules/A1-1-2/CompilerWarningLevelNotInCompliance.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A1-1-2.5/Wall-Wno-format.cpp b/cpp/autosar/test/rules/A1-1-2.5/Wall-Wno-format.cpp new file mode 100644 index 0000000000..93c4b98248 --- /dev/null +++ b/cpp/autosar/test/rules/A1-1-2.5/Wall-Wno-format.cpp @@ -0,0 +1,14 @@ +// semmle-extractor-options: --clang -std=c++14 -Wall -Wno-format +// COMPLIANT + +// NOTE: When tested with `codeql test run`, the test extractor provides `-w` +// which overrides `-Wcast-function-type` and causes this test case to be +// non-compliant. +// +// However, when tested with our compiler matrix tests, this test db is built +// via `codeql database create --command="..."`, and the `-w` flag will NOT be +// used. This means the `-Wcast-function-type` flag is active and the test case +// is compliant. +// +// Therefore, the .expected file for this test expects non-compliance, and the +// .expected.gcc and .expected.clang files expect this test to be compliant. diff --git a/cpp/autosar/test/rules/A1-1-2.5/options.clang b/cpp/autosar/test/rules/A1-1-2.5/options.clang new file mode 100644 index 0000000000..735817b680 --- /dev/null +++ b/cpp/autosar/test/rules/A1-1-2.5/options.clang @@ -0,0 +1 @@ +-Wall -Wno-format \ No newline at end of file diff --git a/cpp/autosar/test/rules/A1-1-2.5/options.gcc b/cpp/autosar/test/rules/A1-1-2.5/options.gcc new file mode 100644 index 0000000000..735817b680 --- /dev/null +++ b/cpp/autosar/test/rules/A1-1-2.5/options.gcc @@ -0,0 +1 @@ +-Wall -Wno-format \ No newline at end of file diff --git a/cpp/autosar/test/rules/A1-1-2.5/options.qcc b/cpp/autosar/test/rules/A1-1-2.5/options.qcc new file mode 100644 index 0000000000..735817b680 --- /dev/null +++ b/cpp/autosar/test/rules/A1-1-2.5/options.qcc @@ -0,0 +1 @@ +-Wall -Wno-format \ No newline at end of file diff --git a/cpp/autosar/test/rules/A1-1-2/CompilerWarningLevelNotInCompliance.expected b/cpp/autosar/test/rules/A1-1-2/CompilerWarningLevelNotInCompliance.expected index e69de29bb2..ddc4e03f62 100644 --- a/cpp/autosar/test/rules/A1-1-2/CompilerWarningLevelNotInCompliance.expected +++ b/cpp/autosar/test/rules/A1-1-2/CompilerWarningLevelNotInCompliance.expected @@ -0,0 +1 @@ +| Wall.cpp:0:0:0:0 | Wall.cpp | No warning-level options were used in the compilation of 'Wall.cpp'. | diff --git a/cpp/autosar/test/rules/A1-1-2/CompilerWarningLevelNotInCompliance.expected.clang b/cpp/autosar/test/rules/A1-1-2/CompilerWarningLevelNotInCompliance.expected.clang new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/autosar/test/rules/A1-1-2/CompilerWarningLevelNotInCompliance.expected.gcc b/cpp/autosar/test/rules/A1-1-2/CompilerWarningLevelNotInCompliance.expected.gcc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/autosar/test/rules/A1-1-2/CompilerWarningLevelNotInCompliance.expected.qcc b/cpp/autosar/test/rules/A1-1-2/CompilerWarningLevelNotInCompliance.expected.qcc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/autosar/test/rules/A1-1-2/Wall.cpp b/cpp/autosar/test/rules/A1-1-2/Wall.cpp index cb21e0601e..b42189a8d1 100644 --- a/cpp/autosar/test/rules/A1-1-2/Wall.cpp +++ b/cpp/autosar/test/rules/A1-1-2/Wall.cpp @@ -1,2 +1,12 @@ // semmle-extractor-options: --clang -std=c++14 -Wall -// COMPLIANT \ No newline at end of file +// COMPLIANT + +// NOTE: When tested with `codeql test run`, the test extractor provides `-w` +// which overrides `-Wall` and causes this test case to be non-compliant. +// +// However, when tested with our compiler matrix tests, this test db is built +// via `codeql database create --command="..."`, and the `-w` flag will NOT be +// used. This means the `-Wall` flag is active and the test case is compliant. +// +// Therefore, the .expected file for this test expects non-compliance, and the +// .expected.gcc and .expected.clang files expect this test to be compliant. \ No newline at end of file diff --git a/cpp/autosar/test/rules/A12-0-1/MissingSpecialMemberFunction.expected b/cpp/autosar/test/rules/A12-0-1/MissingSpecialMemberFunction.expected index 9e1cd591c6..ced97cced2 100644 --- a/cpp/autosar/test/rules/A12-0-1/MissingSpecialMemberFunction.expected +++ b/cpp/autosar/test/rules/A12-0-1/MissingSpecialMemberFunction.expected @@ -1,2 +1,8 @@ | test.cpp:12:7:12:8 | C3 | Class $@ has provided at least one user-defined special member function but is missing definitions for all five special member functions. | test.cpp:12:7:12:8 | C3 | C3 | | test.cpp:28:7:28:8 | C5 | Class $@ has provided at least one user-defined special member function but is missing definitions for all five special member functions. | test.cpp:28:7:28:8 | C5 | C5 | +| test.cpp:51:7:51:9 | C10 | Class $@ has provided at least one user-defined special member function but is missing definitions for all five special member functions. | test.cpp:51:7:51:9 | C10 | C10 | +| test.cpp:55:7:55:9 | C11 | Class $@ has provided at least one user-defined special member function but is missing definitions for all five special member functions. | test.cpp:55:7:55:9 | C11 | C11 | +| test.cpp:59:7:59:9 | C12 | Class $@ has provided at least one user-defined special member function but is missing definitions for all five special member functions. | test.cpp:59:7:59:9 | C12 | C12 | +| test.cpp:63:7:63:9 | C13 | Class $@ has provided at least one user-defined special member function but is missing definitions for all five special member functions. | test.cpp:63:7:63:9 | C13 | C13 | +| test.cpp:67:7:67:9 | C14 | Class $@ has provided at least one user-defined special member function but is missing definitions for all five special member functions. | test.cpp:67:7:67:9 | C14 | C14 | +| test.cpp:71:7:71:9 | C15 | Class $@ has provided at least one user-defined special member function but is missing definitions for all five special member functions. | test.cpp:71:7:71:9 | C15 | C15 | diff --git a/cpp/autosar/test/rules/A12-0-1/test.cpp b/cpp/autosar/test/rules/A12-0-1/test.cpp index 71652633b4..9a38204641 100644 --- a/cpp/autosar/test/rules/A12-0-1/test.cpp +++ b/cpp/autosar/test/rules/A12-0-1/test.cpp @@ -46,4 +46,63 @@ struct C7::C8 { // COMPLIANT struct C9 { // COMPLIANT C9() {} C9(int x) {} +}; + +class C10 { + ~C10() = default; // NON_COMPLIANT +}; + +class C11 { + ~C11() = delete; // NON_COMPLIANT +}; + +class C12 { + C12(C12 const &); // NON_COMPLIANT +}; + +class C13 { + C13(C13 const &) = default; // NON_COMPLIANT +}; + +class C14 { + C14(C14 const &) = delete; // NON_COMPLIANT +}; + +class C15 { + C15 &operator=(C15 const &); // NON_COMPLIANT +}; + +template class C16 { // COMPLIANT + C16() = default; +}; + +template class C17 { // COMPLIANT + C17() = default; + C17(C17 const &) = default; + C17(C17 &&) = default; + virtual ~C17() = default; + C17 &operator=(C17 const &) = default; + C17 &operator=(C17 &&) = default; +}; + +template class C18 { // COMPLIANT + C18() = default; + C18(C18 const &) = delete; + C18(C18 &&) = delete; + virtual ~C18() = default; + C18 &operator=(C18 const &) = delete; + C18 &operator=(C18 &&) = delete; +}; + +template class C19 { // COMPLIANT +public: + explicit C19(T i) : i(i) {} + C19(C19 const &) = delete; + C19(C19 &&) = delete; + virtual ~C19() = default; + C19 &operator=(C19 const &) = delete; + C19 &operator=(C19 &&) = delete; + +private: + T i; }; \ No newline at end of file diff --git a/cpp/autosar/test/rules/A12-1-1/ExplicitConstructorBaseClassInitialization.qlref b/cpp/autosar/test/rules/A12-1-1/ExplicitConstructorBaseClassInitialization.qlref deleted file mode 100644 index 9d356add77..0000000000 --- a/cpp/autosar/test/rules/A12-1-1/ExplicitConstructorBaseClassInitialization.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A12-1-1/ExplicitConstructorBaseClassInitialization.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A12-1-1/ExplicitConstructorBaseClassInitialization.testref b/cpp/autosar/test/rules/A12-1-1/ExplicitConstructorBaseClassInitialization.testref new file mode 100644 index 0000000000..ac8c5e1a83 --- /dev/null +++ b/cpp/autosar/test/rules/A12-1-1/ExplicitConstructorBaseClassInitialization.testref @@ -0,0 +1 @@ +cpp/common/test/rules/initializeallvirtualbaseclasses/InitializeAllVirtualBaseClasses.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A12-1-1/test.cpp b/cpp/autosar/test/rules/A12-1-1/test.cpp deleted file mode 100644 index 7721da8b01..0000000000 --- a/cpp/autosar/test/rules/A12-1-1/test.cpp +++ /dev/null @@ -1,64 +0,0 @@ -class Base {}; -class Derived : public Base { -public: - Derived() {} // NON_COMPLIANT - does not call Base() - Derived(int i) : Base() {} // COMPLIANT - Derived(int i, int j); // IGNORED - not defined, so we don't know -}; - -class Derived1 : public Base { -public: - Derived1() = default; // COMPLIANT - `default` does not have explicit - // initializers -}; - -class VirtualBase {}; - -class Derived2 : virtual public VirtualBase {}; - -class Derived3 : virtual public VirtualBase {}; - -class Derived4 : public Derived2, public Derived3 { -public: - Derived4() {} // NON_COMPLIANT - does not call Derived2(), Derived3() or - // VirtualBase() - Derived4(int i) // NON_COMPLIANT - does not call VirtualBase() - : Derived2(), Derived3() {} - Derived4(int i, int j) // COMPLIANT - calls VirtualBase() - : Derived2(), Derived3(), VirtualBase() {} -}; - -class NonTrivialBase { -public: - NonTrivialBase() = default; - NonTrivialBase(int i){}; - NonTrivialBase(int i, int j){}; -}; - -class Derived5 : public NonTrivialBase { -public: - Derived5() {} // NON_COMPLIANT - does not call NonTrivialBase() - Derived5(int i) : NonTrivialBase(i) {} // COMPLIANT - Derived5(int i, int j) : NonTrivialBase(i, j) {} // COMPLIANT -}; - -class MultipleInheritenceBase {}; - -class Child1 : public MultipleInheritenceBase {}; - -class Child2 : public MultipleInheritenceBase {}; - -class GrandChild : public Child1, public Child2 { - // no need to initialize MultipleInheritenceBase - GrandChild() : Child1(), Child2() {} // COMPLIANT -}; - -class Base2 {}; - -class Derived6 : public Base2 { -public: - Derived6() : b() {} // NON_COMPLIANT - -private: - Base2 b; -}; \ No newline at end of file diff --git a/cpp/autosar/test/rules/A12-8-5/CopyAssignmentAndAMoveHandleSelfAssignment.qlref b/cpp/autosar/test/rules/A12-8-5/CopyAssignmentAndAMoveHandleSelfAssignment.qlref deleted file mode 100644 index 686462e15f..0000000000 --- a/cpp/autosar/test/rules/A12-8-5/CopyAssignmentAndAMoveHandleSelfAssignment.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A12-8-5/CopyAssignmentAndAMoveHandleSelfAssignment.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A12-8-5/CopyAssignmentAndAMoveHandleSelfAssignment.testref b/cpp/autosar/test/rules/A12-8-5/CopyAssignmentAndAMoveHandleSelfAssignment.testref new file mode 100644 index 0000000000..65fc614121 --- /dev/null +++ b/cpp/autosar/test/rules/A12-8-5/CopyAssignmentAndAMoveHandleSelfAssignment.testref @@ -0,0 +1 @@ +cpp/common/test/rules/copyandmoveassignmentsshallhandleselfassignment/CopyAndMoveAssignmentsShallHandleSelfAssignment.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A12-8-6/CopyAndMoveNotDeclaredProtected.expected b/cpp/autosar/test/rules/A12-8-6/CopyAndMoveNotDeclaredProtected.expected index 9f85da12d6..74ed472a52 100644 --- a/cpp/autosar/test/rules/A12-8-6/CopyAndMoveNotDeclaredProtected.expected +++ b/cpp/autosar/test/rules/A12-8-6/CopyAndMoveNotDeclaredProtected.expected @@ -20,7 +20,3 @@ | test.cpp:109:3:109:12 | declaration of BaseClass8 | Move constructor for base class 'BaseClass8' is not declared protected. | | test.cpp:110:15:110:23 | declaration of operator= | Copy assignment operator for base class 'BaseClass8' is not declared protected. | | test.cpp:111:15:111:23 | declaration of operator= | Move assignment operator for base class 'BaseClass8' is not declared protected. | -| test.cpp:124:26:124:26 | declaration of BaseClass9 | Implicit copy constructor for base class 'BaseClass9' is not declared deleted. | -| test.cpp:124:26:124:26 | declaration of BaseClass9 | Implicit move constructor for base class 'BaseClass9' is not declared deleted. | -| test.cpp:124:26:124:26 | declaration of operator= | Implicit copy assignment operator for base class 'BaseClass9' is not declared deleted. | -| test.cpp:124:26:124:26 | declaration of operator= | Implicit move assignment operator for base class 'BaseClass9' is not declared deleted. | diff --git a/cpp/autosar/test/rules/A12-8-6/test.cpp b/cpp/autosar/test/rules/A12-8-6/test.cpp index 6a31ca60ae..d197fc18fb 100644 --- a/cpp/autosar/test/rules/A12-8-6/test.cpp +++ b/cpp/autosar/test/rules/A12-8-6/test.cpp @@ -12,8 +12,8 @@ class DerivedClass1 // COMPLIANT - not a base class itself // Base class with compiler generated move/copy is not compliant, because they // are public by default -class BaseClass2 {}; // NON_COMPLIANT - compiler generated move and assignment - // are in contravention +class BaseClass2 {}; // NON_COMPLIANT[FALSE_NEGATIVE] - compiler generated move + // and assignment are in contravention class DerivedClass2 // COMPLIANT - not a base class itself : public BaseClass2 {}; @@ -87,7 +87,7 @@ template class BaseClass7 { BaseClass7 &operator=(BaseClass7 const &) = default; // NON_COMPLIANT BaseClass7 &operator=(BaseClass7 &&) = default; // NON_COMPLIANT int operator=(int i); // COMPLIANT - not an assignment operator -}; // COMPLIANT +}; template class DerivedClass7 // COMPLIANT - not a base class itself @@ -121,7 +121,7 @@ class DerivedClass9 // COMPLIANT - not a base class itself T t; }; -template class BaseClass9 { // NON_COMPLIANT +template class BaseClass9 { // NON_COMPLIANT[FALSE_NEGATIVE] public: BaseClass9() {} diff --git a/cpp/autosar/test/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.expected b/cpp/autosar/test/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.expected index 53dc884023..5d1d6022b5 100644 --- a/cpp/autosar/test/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.expected +++ b/cpp/autosar/test/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.expected @@ -1 +1,4 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql:27,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql:28,5-13) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql:27,7-20) | test.cpp:47:8:47:23 | operator ""_uds5 | User defined literal operator returns $@, which is not converted from a passed parameter | test.cpp:48:10:48:12 | 0.0 | expression | diff --git a/cpp/autosar/test/rules/A13-2-1/AssignmentOperatorReturnThis.expected b/cpp/autosar/test/rules/A13-2-1/AssignmentOperatorReturnThis.expected index e9929173b0..9c0d50ca86 100644 --- a/cpp/autosar/test/rules/A13-2-1/AssignmentOperatorReturnThis.expected +++ b/cpp/autosar/test/rules/A13-2-1/AssignmentOperatorReturnThis.expected @@ -1,3 +1,4 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AssignmentOperatorReturnThis.ql:25,5-13) | test.cpp:10:12:10:20 | operator= | User-defined assignment operator $@ does not return *this | test.cpp:10:12:10:20 | operator= | user defined assignment operator | | test.cpp:17:11:17:19 | operator= | User-defined assignment operator $@ does not return *this | test.cpp:17:11:17:19 | operator= | user defined assignment operator | | test.cpp:24:12:24:20 | operator= | User-defined assignment operator $@ does not return *this | test.cpp:24:12:24:20 | operator= | user defined assignment operator | diff --git a/cpp/autosar/test/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.expected b/cpp/autosar/test/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.expected index 6e79cb00a4..cb71b56b51 100644 --- a/cpp/autosar/test/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.expected +++ b/cpp/autosar/test/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.expected @@ -1,7 +1,3 @@ | test.cpp:24:6:24:7 | F1 | Function overloads a $@. | test.cpp:27:25:27:26 | F1 | function with a forwarding reference parameter | | test.cpp:50:3:50:3 | A | Function overloads a $@. | test.cpp:48:3:48:3 | A | function with a forwarding reference parameter | | test.cpp:51:3:51:3 | A | Function overloads a $@. | test.cpp:48:3:48:3 | A | function with a forwarding reference parameter | -| test.cpp:69:3:69:3 | B | Function with a forwarding reference parameter overloads a $@. | test.cpp:64:8:64:8 | B | implicit copy constructor | -| test.cpp:69:3:69:3 | B | Function with a forwarding reference parameter overloads a $@. | test.cpp:64:8:64:8 | B | implicit move constructor | -| test.cpp:77:25:77:25 | C | Function with a forwarding reference parameter overloads a $@. | test.cpp:74:7:74:7 | C | implicit copy constructor | -| test.cpp:77:25:77:25 | C | Function with a forwarding reference parameter overloads a $@. | test.cpp:74:7:74:7 | C | implicit move constructor | diff --git a/cpp/autosar/test/rules/A13-3-1/test.cpp b/cpp/autosar/test/rules/A13-3-1/test.cpp index 82fe866a0a..8ed4e4d609 100644 --- a/cpp/autosar/test/rules/A13-3-1/test.cpp +++ b/cpp/autosar/test/rules/A13-3-1/test.cpp @@ -40,7 +40,7 @@ template void F1(T &&x) {} // class A { public: // COMPLIANT[FALSE_POSITIVE] - by exception, constrained to not match - // copy/move ctors + // explicit copy/move ctors template < typename T, std::enable_if_t>, A>::value> * = nullptr> - B(T &&value) {} // COMPLIANT[FALSE_POSITIVE] - by exception + B(T &&value) {} // COMPLIANT - by exception }; int main() {} @@ -74,5 +74,6 @@ int main() {} class C { public: C() {} - template C(T &&) {} // NON_COMPLIANT + template + C(T &&) {} // COMPLIANT - ignore overloads of implicit copy/move ctors }; \ No newline at end of file diff --git a/cpp/autosar/test/rules/A13-5-3/UserDefinedConversionOperatorsShouldNotBeUsed.expected b/cpp/autosar/test/rules/A13-5-3/UserDefinedConversionOperatorsShouldNotBeUsed.expected index e757cdf984..14e68ab4a9 100644 --- a/cpp/autosar/test/rules/A13-5-3/UserDefinedConversionOperatorsShouldNotBeUsed.expected +++ b/cpp/autosar/test/rules/A13-5-3/UserDefinedConversionOperatorsShouldNotBeUsed.expected @@ -1,4 +1,4 @@ | test.cpp:33:7:33:7 | call to operator A | User-defined conversion operators should not be used. | | test.cpp:35:24:35:24 | call to operator A * | User-defined conversion operators should not be used. | -| test.cpp:37:15:37:15 | call to operator B::array_A * | User-defined conversion operators should not be used. | +| test.cpp:37:15:37:15 | call to operator A (*)[3] | User-defined conversion operators should not be used. | | test.cpp:41:7:41:7 | call to operator A * | User-defined conversion operators should not be used. | diff --git a/cpp/autosar/test/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.expected b/cpp/autosar/test/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.expected index d45a3c6871..f0c78e2af1 100644 --- a/cpp/autosar/test/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.expected +++ b/cpp/autosar/test/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.expected @@ -1,4 +1,3 @@ -| test.cpp:10:9:10:10 | T1 | Member T1 template class does not use any of template arguments of its $@. | test.cpp:6:29:6:30 | C1 | declaring type | | test.cpp:11:9:11:10 | T2 | Member T2 template class does not use any of template arguments of its $@. | test.cpp:6:29:6:30 | C1 | declaring type | | test.cpp:28:31:28:33 | C12 | Member C12 template class does not use any of template arguments of its $@. | test.cpp:6:29:6:30 | C1 | declaring type | | test.cpp:45:7:45:8 | a1 | Member a1 template class does not use any of template arguments of its $@. | test.cpp:37:31:37:33 | C22 | declaring type | diff --git a/cpp/autosar/test/rules/A14-5-2/test.cpp b/cpp/autosar/test/rules/A14-5-2/test.cpp index e60a955c68..260ff5b4b2 100644 --- a/cpp/autosar/test/rules/A14-5-2/test.cpp +++ b/cpp/autosar/test/rules/A14-5-2/test.cpp @@ -7,7 +7,7 @@ template class C1 { public: enum E1 : T { e1, e2 }; // COMPLIANT - using T1 = typename template_base::type; // COMPLIANT[FALSE_POSITIVE] + using T1 = typename template_base::type; // COMPLIANT using T2 = typename template_base::type; // NON_COMPLIANT class C11 { // COMPLIANT @@ -156,4 +156,4 @@ template class V { void f4() { V v; v.type(); -} \ No newline at end of file +} diff --git a/cpp/autosar/test/rules/A14-8-2/ExplicitSpecializationsOfFunctionTemplatesUsed.qlref b/cpp/autosar/test/rules/A14-8-2/ExplicitSpecializationsOfFunctionTemplatesUsed.qlref deleted file mode 100644 index b2f19b3af3..0000000000 --- a/cpp/autosar/test/rules/A14-8-2/ExplicitSpecializationsOfFunctionTemplatesUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A14-8-2/ExplicitSpecializationsOfFunctionTemplatesUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A14-8-2/ExplicitSpecializationsOfFunctionTemplatesUsed.testref b/cpp/autosar/test/rules/A14-8-2/ExplicitSpecializationsOfFunctionTemplatesUsed.testref new file mode 100644 index 0000000000..6a284e2cbb --- /dev/null +++ b/cpp/autosar/test/rules/A14-8-2/ExplicitSpecializationsOfFunctionTemplatesUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/functiontemplatesexplicitlyspecialized/FunctionTemplatesExplicitlySpecialized.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A15-1-2/PointerExceptionObject.qlref b/cpp/autosar/test/rules/A15-1-2/PointerExceptionObject.qlref deleted file mode 100644 index 68c8e7af9a..0000000000 --- a/cpp/autosar/test/rules/A15-1-2/PointerExceptionObject.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A15-1-2/PointerExceptionObject.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A15-1-2/PointerExceptionObject.testref b/cpp/autosar/test/rules/A15-1-2/PointerExceptionObject.testref new file mode 100644 index 0000000000..24d4229225 --- /dev/null +++ b/cpp/autosar/test/rules/A15-1-2/PointerExceptionObject.testref @@ -0,0 +1 @@ +cpp/common/test/rules/exceptionobjecthavepointertype/ExceptionObjectHavePointerType.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A15-1-3/ThrownExceptionsShouldBeUnique.expected b/cpp/autosar/test/rules/A15-1-3/ThrownExceptionsShouldBeUnique.expected index b085736659..5db0f83985 100644 --- a/cpp/autosar/test/rules/A15-1-3/ThrownExceptionsShouldBeUnique.expected +++ b/cpp/autosar/test/rules/A15-1-3/ThrownExceptionsShouldBeUnique.expected @@ -1,3 +1,4 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThrownExceptionsShouldBeUnique.ql:24,3-11) | test.cpp:6:5:6:26 | throw ... | The $@ thrown here is a possible duplicate of the $@ thrown $@. | test.cpp:6:5:6:26 | call to exception | std::exception exception | test.cpp:14:5:14:26 | call to exception | exception | test.cpp:14:5:14:26 | throw ... | here | | test.cpp:8:5:8:53 | throw ... | The $@ thrown here is a possible duplicate of the $@ thrown $@. | test.cpp:8:5:8:53 | call to runtime_error | std::runtime_error exception | test.cpp:16:5:16:53 | call to runtime_error | exception | test.cpp:16:5:16:53 | throw ... | here | | test.cpp:14:5:14:26 | throw ... | The $@ thrown here is a possible duplicate of the $@ thrown $@. | test.cpp:14:5:14:26 | call to exception | std::exception exception | test.cpp:6:5:6:26 | call to exception | exception | test.cpp:6:5:6:26 | throw ... | here | diff --git a/cpp/autosar/test/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.expected b/cpp/autosar/test/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.expected index 941771dada..529a7ccf99 100644 --- a/cpp/autosar/test/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.expected +++ b/cpp/autosar/test/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.expected @@ -1,3 +1,12 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:47,12-20) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:48,30-38) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:48,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:74,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:74,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:75,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:130,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:130,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:130,54-62) edges | test.cpp:12:16:12:27 | new [bad_alloc] | test.cpp:14:33:16:5 | { ... } [bad_alloc] | | test.cpp:13:7:13:28 | throw ... [exception] | test.cpp:14:33:16:5 | { ... } [exception] | diff --git a/cpp/autosar/test/rules/A15-4-2/NoExceptFunctionThrows.expected b/cpp/autosar/test/rules/A15-4-2/NoExceptFunctionThrows.expected deleted file mode 100644 index b2f8391b15..0000000000 --- a/cpp/autosar/test/rules/A15-4-2/NoExceptFunctionThrows.expected +++ /dev/null @@ -1,19 +0,0 @@ -edges -| test.cpp:5:3:5:20 | throw ... [ExceptionA] | test.cpp:4:6:4:15 | test_throw [ExceptionA] | -| test.cpp:8:6:8:11 | throwA [ExceptionA] | test.cpp:9:25:9:30 | call to throwA [ExceptionA] | -| test.cpp:8:6:8:11 | throwA [ExceptionA] | test.cpp:10:42:10:47 | call to throwA [ExceptionA] | -| test.cpp:8:6:8:11 | throwA [ExceptionA] | test.cpp:13:3:13:8 | call to throwA [ExceptionA] | -| test.cpp:8:6:8:11 | throwA [ExceptionA] | test.cpp:17:3:17:8 | call to throwA [ExceptionA] | -| test.cpp:8:17:8:34 | throw ... [ExceptionA] | test.cpp:8:6:8:11 | throwA [ExceptionA] | -| test.cpp:9:6:9:19 | indirectThrowA [ExceptionA] | test.cpp:34:3:34:16 | call to indirectThrowA [ExceptionA] | -| test.cpp:9:25:9:30 | call to throwA [ExceptionA] | test.cpp:9:6:9:19 | indirectThrowA [ExceptionA] | -| test.cpp:10:42:10:47 | call to throwA [ExceptionA] | test.cpp:10:6:10:27 | noexceptIndirectThrowA [ExceptionA] | -| test.cpp:13:3:13:8 | call to throwA [ExceptionA] | test.cpp:12:6:12:24 | test_indirect_throw [ExceptionA] | -| test.cpp:17:3:17:8 | call to throwA [ExceptionA] | test.cpp:16:6:16:26 | test_indirect_throw_2 [ExceptionA] | -| test.cpp:34:3:34:16 | call to indirectThrowA [ExceptionA] | test.cpp:33:6:33:26 | test_indirect_throw_6 [ExceptionA] | -#select -| test.cpp:4:6:4:15 | test_throw | test.cpp:5:3:5:20 | throw ... [ExceptionA] | test.cpp:4:6:4:15 | test_throw [ExceptionA] | Function test_throw is declared noexcept(true) but can throw exceptions of type ExceptionA. | -| test.cpp:10:6:10:27 | noexceptIndirectThrowA | test.cpp:8:17:8:34 | throw ... [ExceptionA] | test.cpp:10:6:10:27 | noexceptIndirectThrowA [ExceptionA] | Function noexceptIndirectThrowA is declared noexcept(true) but can throw exceptions of type ExceptionA. | -| test.cpp:12:6:12:24 | test_indirect_throw | test.cpp:8:17:8:34 | throw ... [ExceptionA] | test.cpp:12:6:12:24 | test_indirect_throw [ExceptionA] | Function test_indirect_throw is declared noexcept(true) but can throw exceptions of type ExceptionA. | -| test.cpp:16:6:16:26 | test_indirect_throw_2 | test.cpp:8:17:8:34 | throw ... [ExceptionA] | test.cpp:16:6:16:26 | test_indirect_throw_2 [ExceptionA] | Function test_indirect_throw_2 is declared noexcept(true) but can throw exceptions of type ExceptionA. | -| test.cpp:33:6:33:26 | test_indirect_throw_6 | test.cpp:8:17:8:34 | throw ... [ExceptionA] | test.cpp:33:6:33:26 | test_indirect_throw_6 [ExceptionA] | Function test_indirect_throw_6 is declared noexcept(true) but can throw exceptions of type ExceptionA. | diff --git a/cpp/autosar/test/rules/A15-4-2/NoExceptFunctionThrows.qlref b/cpp/autosar/test/rules/A15-4-2/NoExceptFunctionThrows.qlref deleted file mode 100644 index 80fbc7365c..0000000000 --- a/cpp/autosar/test/rules/A15-4-2/NoExceptFunctionThrows.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A15-4-2/NoExceptFunctionThrows.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A15-4-2/NoExceptFunctionThrows.testref b/cpp/autosar/test/rules/A15-4-2/NoExceptFunctionThrows.testref new file mode 100644 index 0000000000..76dc55827f --- /dev/null +++ b/cpp/autosar/test/rules/A15-4-2/NoExceptFunctionThrows.testref @@ -0,0 +1 @@ +cpp/common/test/rules/noexceptfunctionshouldnotpropagatetothecaller/NoexceptFunctionShouldNotPropagateToTheCaller.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A15-4-4/coding-standards.xml b/cpp/autosar/test/rules/A15-4-4/coding-standards.xml new file mode 100644 index 0000000000..6ae9c299fa --- /dev/null +++ b/cpp/autosar/test/rules/A15-4-4/coding-standards.xml @@ -0,0 +1,11 @@ + + + + + + A15-4-4 + Suppress entry. + a-15-4-4-deviation + + + diff --git a/cpp/autosar/test/rules/A15-4-4/test.cpp b/cpp/autosar/test/rules/A15-4-4/test.cpp index 1f9d0d5a85..faae76ca8e 100644 --- a/cpp/autosar/test/rules/A15-4-4/test.cpp +++ b/cpp/autosar/test/rules/A15-4-4/test.cpp @@ -56,4 +56,12 @@ std::string test_fp_reported_in_424( s3.append(s1.c_str(), s1.size()); s3.append(s2.c_str(), s2.size()); return s3; -} \ No newline at end of file +} + +void test_no_except_deviated_decl(); // a-15-4-4-deviation + +void test_no_except_deviated_decl() {} + +void test_no_except_deviated_defn(); + +void test_no_except_deviated_defn() {} // a-15-4-4-deviation \ No newline at end of file diff --git a/cpp/autosar/test/rules/A18-1-1/test.cpp b/cpp/autosar/test/rules/A18-1-1/test.cpp index 90596780d9..0e9bffa3d7 100644 --- a/cpp/autosar/test/rules/A18-1-1/test.cpp +++ b/cpp/autosar/test/rules/A18-1-1/test.cpp @@ -11,6 +11,6 @@ int test_c_arrays() { int x[100]; // NON_COMPLIANT constexpr int a[]{0, 1, 2}; // NON_COMPLIANT - __func__; // COMPLAINT + __func__; // COMPLIANT return 0; -} \ No newline at end of file +} diff --git a/cpp/autosar/test/rules/A18-1-2/VectorboolSpecializationUsed.qlref b/cpp/autosar/test/rules/A18-1-2/VectorboolSpecializationUsed.qlref deleted file mode 100644 index 9f78cda4c6..0000000000 --- a/cpp/autosar/test/rules/A18-1-2/VectorboolSpecializationUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A18-1-2/VectorboolSpecializationUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A18-1-2/VectorboolSpecializationUsed.testref b/cpp/autosar/test/rules/A18-1-2/VectorboolSpecializationUsed.testref new file mode 100644 index 0000000000..a934690acb --- /dev/null +++ b/cpp/autosar/test/rules/A18-1-2/VectorboolSpecializationUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/vectorshouldnotbespecializedwithbool/VectorShouldNotBeSpecializedWithBool.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected b/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected index dcf263fc54..bd46224da6 100644 --- a/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected +++ b/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected @@ -1,10 +1,18 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:26,67-75) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:27,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:39,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:50,34-42) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:50,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:58,25-33) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:70,3-16) edges -| test.cpp:3:36:3:45 | new[] | test.cpp:19:27:19:44 | call to allocate_int_array | -| test.cpp:3:36:3:45 | new[] | test.cpp:23:12:23:29 | call to allocate_int_array | -| test.cpp:3:36:3:45 | new[] | test.cpp:27:20:27:37 | call to allocate_int_array | -| test.cpp:11:29:11:41 | call to unique_ptr | test.cpp:12:27:12:28 | v2 | -| test.cpp:12:27:12:28 | v2 | test.cpp:12:30:12:36 | call to release | -| test.cpp:27:20:27:37 | call to allocate_int_array | test.cpp:32:12:32:20 | int_array | +| test.cpp:3:36:3:45 | new[] | test.cpp:19:27:19:44 | call to allocate_int_array | provenance | | +| test.cpp:3:36:3:45 | new[] | test.cpp:23:12:23:29 | call to allocate_int_array | provenance | | +| test.cpp:3:36:3:45 | new[] | test.cpp:27:20:27:37 | call to allocate_int_array | provenance | | +| test.cpp:11:29:11:41 | call to unique_ptr | test.cpp:12:27:12:28 | v2 | provenance | | +| test.cpp:12:27:12:28 | v2 | test.cpp:12:30:12:36 | call to release | provenance | | +| test.cpp:12:27:12:28 | v2 | test.cpp:12:30:12:36 | call to release | provenance | Config | +| test.cpp:27:20:27:37 | call to allocate_int_array | test.cpp:32:12:32:20 | int_array | provenance | | nodes | test.cpp:3:36:3:45 | new[] | semmle.label | new[] | | test.cpp:11:29:11:41 | call to unique_ptr | semmle.label | call to unique_ptr | diff --git a/cpp/autosar/test/rules/A18-5-4/GlobalSizedOperatorDeleteNotDefined.qlref b/cpp/autosar/test/rules/A18-5-4/GlobalSizedOperatorDeleteNotDefined.qlref deleted file mode 100644 index 1f1e8258e4..0000000000 --- a/cpp/autosar/test/rules/A18-5-4/GlobalSizedOperatorDeleteNotDefined.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A18-5-4/GlobalSizedOperatorDeleteNotDefined.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A18-5-4/GlobalSizedOperatorDeleteNotDefined.testref b/cpp/autosar/test/rules/A18-5-4/GlobalSizedOperatorDeleteNotDefined.testref new file mode 100644 index 0000000000..4d1e21d4cb --- /dev/null +++ b/cpp/autosar/test/rules/A18-5-4/GlobalSizedOperatorDeleteNotDefined.testref @@ -0,0 +1 @@ +cpp/common/test/rules/globalsizedoperatordeletenotdefined/GlobalSizedOperatorDeleteNotDefined.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A18-5-4/GlobalUnsizedOperatorDeleteNotDefined.qlref b/cpp/autosar/test/rules/A18-5-4/GlobalUnsizedOperatorDeleteNotDefined.qlref deleted file mode 100644 index 04cc5622dd..0000000000 --- a/cpp/autosar/test/rules/A18-5-4/GlobalUnsizedOperatorDeleteNotDefined.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A18-5-4/GlobalUnsizedOperatorDeleteNotDefined.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A18-5-4/GlobalUnsizedOperatorDeleteNotDefined.testref b/cpp/autosar/test/rules/A18-5-4/GlobalUnsizedOperatorDeleteNotDefined.testref new file mode 100644 index 0000000000..f2fcc2eded --- /dev/null +++ b/cpp/autosar/test/rules/A18-5-4/GlobalUnsizedOperatorDeleteNotDefined.testref @@ -0,0 +1 @@ +cpp/common/test/rules/globalunsizedoperatordeletenotdefined/GlobalUnsizedOperatorDeleteNotDefined.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.expected b/cpp/autosar/test/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.expected index d9dd02c054..68cab835fa 100644 --- a/cpp/autosar/test/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.expected +++ b/cpp/autosar/test/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.expected @@ -1,3 +1,8 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:55,34-42) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:58,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:60,26-34) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:74,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:79,41-54) | test.cpp:17:17:17:29 | new | StructA object of size 8 bytes does not appear to outlive the function, but is created on the heap instead of the stack. | | test.cpp:21:17:21:32 | new[] | StructA[] object of size 800 bytes does not appear to outlive the function, but is created on the heap instead of the stack. | | test.cpp:35:20:35:44 | call to make_shared | StructA object of size 8 bytes does not appear to outlive the function, but is created on the heap instead of the stack. | diff --git a/cpp/autosar/test/rules/A18-9-2/ForwardingValuesToOtherFunctions.qlref b/cpp/autosar/test/rules/A18-9-2/ForwardingValuesToOtherFunctions.qlref deleted file mode 100644 index 05bcab607a..0000000000 --- a/cpp/autosar/test/rules/A18-9-2/ForwardingValuesToOtherFunctions.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A18-9-2/ForwardingValuesToOtherFunctions.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A18-9-2/ForwardingValuesToOtherFunctions.testref b/cpp/autosar/test/rules/A18-9-2/ForwardingValuesToOtherFunctions.testref new file mode 100644 index 0000000000..d56acb8415 --- /dev/null +++ b/cpp/autosar/test/rules/A18-9-2/ForwardingValuesToOtherFunctions.testref @@ -0,0 +1 @@ +cpp/common/test/rules/forwardingreferencesandforwardnotusedtogether/ForwardingReferencesAndForwardNotUsedTogether.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.expected b/cpp/autosar/test/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.expected index 1c72dd7bf3..9e1cf41d3d 100644 --- a/cpp/autosar/test/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.expected +++ b/cpp/autosar/test/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.expected @@ -1 +1,4 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArgumentToForwardSubsequentlyUsed.ql:22,10-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArgumentToForwardSubsequentlyUsed.ql:24,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArgumentToForwardSubsequentlyUsed.ql:24,30-38) | test.cpp:8:5:8:6 | t2 | The argument $@ of `std::forward` may be indeterminate when accessed at this location. | test.cpp:7:45:7:46 | t2 | t2 | diff --git a/cpp/autosar/test/rules/A2-10-5/IdentifierNameOfANonMemberObjectWithExternalOrInternalLinkageIsReused.expected b/cpp/autosar/test/rules/A2-10-5/IdentifierNameOfANonMemberObjectWithExternalOrInternalLinkageIsReused.expected index 66d2b38c57..d6f496a3c6 100644 --- a/cpp/autosar/test/rules/A2-10-5/IdentifierNameOfANonMemberObjectWithExternalOrInternalLinkageIsReused.expected +++ b/cpp/autosar/test/rules/A2-10-5/IdentifierNameOfANonMemberObjectWithExternalOrInternalLinkageIsReused.expected @@ -1,6 +1,6 @@ | test1a.cpp:2:12:2:13 | g1 | Identifier name of non-member object $@ reuses the identifier name of non-member object $@. | test1a.cpp:2:12:2:13 | g1 | g1 | test1b.cpp:2:12:2:13 | g1 | g1 | | test1a.cpp:6:12:6:13 | g3 | Identifier name of non-member object $@ reuses the identifier name of non-member object $@. | test1a.cpp:6:12:6:13 | g3 | g3 | test1b.cpp:6:12:6:13 | g3 | g3 | -| test1a.cpp:17:43:17:43 | number_two | Identifier name of non-member object $@ reuses the identifier name of non-member object $@. | test1a.cpp:17:43:17:43 | number_two | number_two | test1b.cpp:11:43:11:43 | number_two | number_two | +| test1a.cpp:17:50:17:50 | number_two | Identifier name of non-member object $@ reuses the identifier name of non-member object $@. | test1a.cpp:17:50:17:50 | number_two | number_two | test1b.cpp:11:50:11:50 | number_two | number_two | | test1b.cpp:2:12:2:13 | g1 | Identifier name of non-member object $@ reuses the identifier name of non-member object $@. | test1b.cpp:2:12:2:13 | g1 | g1 | test1a.cpp:2:12:2:13 | g1 | g1 | | test1b.cpp:6:12:6:13 | g3 | Identifier name of non-member object $@ reuses the identifier name of non-member object $@. | test1b.cpp:6:12:6:13 | g3 | g3 | test1a.cpp:6:12:6:13 | g3 | g3 | -| test1b.cpp:11:43:11:43 | number_two | Identifier name of non-member object $@ reuses the identifier name of non-member object $@. | test1b.cpp:11:43:11:43 | number_two | number_two | test1a.cpp:17:43:17:43 | number_two | number_two | +| test1b.cpp:11:50:11:50 | number_two | Identifier name of non-member object $@ reuses the identifier name of non-member object $@. | test1b.cpp:11:50:11:50 | number_two | number_two | test1a.cpp:17:50:17:50 | number_two | number_two | diff --git a/cpp/autosar/test/rules/A2-10-5/test1a.cpp b/cpp/autosar/test/rules/A2-10-5/test1a.cpp index 80f63c3c69..749ad38b0f 100644 --- a/cpp/autosar/test/rules/A2-10-5/test1a.cpp +++ b/cpp/autosar/test/rules/A2-10-5/test1a.cpp @@ -14,7 +14,7 @@ int test() { return number_one; } long test2() { return number_one; } -template constexpr T number_two = T(1); // NON_COMPLIANT +template static constexpr T number_two = T(1); // NON_COMPLIANT int test3() { return number_two; } diff --git a/cpp/autosar/test/rules/A2-10-5/test1b.cpp b/cpp/autosar/test/rules/A2-10-5/test1b.cpp index 132588d5dd..342d739c4d 100644 --- a/cpp/autosar/test/rules/A2-10-5/test1b.cpp +++ b/cpp/autosar/test/rules/A2-10-5/test1b.cpp @@ -8,8 +8,8 @@ static int g3 = 0; // NON_COMPLIANT static void f1() {} // NON_COMPLIANT -template constexpr T number_two = T(1); // NON_COMPLIANT +template static constexpr T number_two = T(1); // NON_COMPLIANT -int test3() { return number_two; } +int test5() { return number_two; } -long test4() { return number_two; } \ No newline at end of file +long test6() { return number_two; } \ No newline at end of file diff --git a/cpp/autosar/test/rules/A2-13-1/EscapeSequenceOutsideISO.qlref b/cpp/autosar/test/rules/A2-13-1/EscapeSequenceOutsideISO.qlref deleted file mode 100644 index ce6347c955..0000000000 --- a/cpp/autosar/test/rules/A2-13-1/EscapeSequenceOutsideISO.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A2-13-1/EscapeSequenceOutsideISO.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A2-13-1/EscapeSequenceOutsideISO.testref b/cpp/autosar/test/rules/A2-13-1/EscapeSequenceOutsideISO.testref new file mode 100644 index 0000000000..924122e38e --- /dev/null +++ b/cpp/autosar/test/rules/A2-13-1/EscapeSequenceOutsideISO.testref @@ -0,0 +1 @@ +cpp/common/test/rules/backslashcharactermisuse/BackslashCharacterMisuse.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A2-7-1/SingleLineCommentEndsWithSlash.qlref b/cpp/autosar/test/rules/A2-7-1/SingleLineCommentEndsWithSlash.qlref deleted file mode 100644 index 876f24be61..0000000000 --- a/cpp/autosar/test/rules/A2-7-1/SingleLineCommentEndsWithSlash.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A2-7-1/SingleLineCommentEndsWithSlash.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A2-7-1/SingleLineCommentEndsWithSlash.testref b/cpp/autosar/test/rules/A2-7-1/SingleLineCommentEndsWithSlash.testref new file mode 100644 index 0000000000..7874a476a0 --- /dev/null +++ b/cpp/autosar/test/rules/A2-7-1/SingleLineCommentEndsWithSlash.testref @@ -0,0 +1 @@ +cpp/common/test/rules/linesplicingusedincomments/LineSplicingUsedInComments.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A2-7-3/UndocumentedUserDefinedType.expected b/cpp/autosar/test/rules/A2-7-3/UndocumentedUserDefinedType.expected index 0ae42152f7..d14f6e21f7 100644 --- a/cpp/autosar/test/rules/A2-7-3/UndocumentedUserDefinedType.expected +++ b/cpp/autosar/test/rules/A2-7-3/UndocumentedUserDefinedType.expected @@ -1,9 +1,12 @@ -| test.cpp:70:7:70:12 | definition of ClassD | Declaration entry for user-defined type ClassD is missing documentation. | -| test.cpp:72:7:72:7 | definition of a | Declaration entry for member variable a is missing documentation. | -| test.cpp:73:14:73:14 | declaration of b | Declaration entry for member variable b is missing documentation. | -| test.cpp:74:8:74:8 | declaration of f | Declaration entry for function f is missing documentation. | -| test.cpp:76:7:76:7 | definition of c | Declaration entry for member variable c is missing documentation. | -| test.cpp:78:6:78:6 | declaration of d | Declaration entry for function d is missing documentation. | -| test.cpp:81:6:81:6 | definition of e | Declaration entry for function e is missing documentation. | -| test.cpp:88:1:88:30 | definition of message_to_string_undocumented | Declaration entry for function message_to_string_undocumented is missing documentation. | -| test.cpp:160:21:160:24 | definition of kBar | Declaration entry for member variable kBar is missing documentation. | +| test.cpp:74:8:74:8 | declaration of j | Declaration entry for function j is missing documentation. | +| test.cpp:75:8:75:8 | declaration of k | Declaration entry for function k is missing documentation. | +| test.cpp:90:7:90:12 | definition of ClassD | Declaration entry for user-defined type ClassD is missing documentation. | +| test.cpp:92:7:92:7 | definition of a | Declaration entry for member variable a is missing documentation. | +| test.cpp:93:14:93:14 | declaration of b | Declaration entry for member variable b is missing documentation. | +| test.cpp:94:8:94:8 | declaration of f | Declaration entry for function f is missing documentation. | +| test.cpp:96:7:96:7 | definition of c | Declaration entry for member variable c is missing documentation. | +| test.cpp:98:6:98:6 | declaration of d | Declaration entry for function d is missing documentation. | +| test.cpp:101:6:101:6 | definition of e | Declaration entry for function e is missing documentation. | +| test.cpp:108:1:108:30 | definition of message_to_string_undocumented | Declaration entry for function message_to_string_undocumented is missing documentation. | +| test.cpp:180:21:180:24 | definition of kBar | Declaration entry for member variable kBar is missing documentation. | +| test.cpp:227:14:227:17 | definition of foo3 | Declaration entry for function foo3 is missing documentation. | diff --git a/cpp/autosar/test/rules/A2-7-3/test.cpp b/cpp/autosar/test/rules/A2-7-3/test.cpp index 8e9e180458..c062da4ee9 100644 --- a/cpp/autosar/test/rules/A2-7-3/test.cpp +++ b/cpp/autosar/test/rules/A2-7-3/test.cpp @@ -60,10 +60,30 @@ class ClassC { // COMPLIANT /// @param i an integer. /// @throw std::runtime_error void f(int i); // COMPLIANT + + /** Same documentation for all members + * This is a multiline comment. + */ + ///@{ + void g(); // COMPLIANT + void h(); // COMPLIANT + void i(); // COMPLIANT + ///@} + + ///@{ + void j(); // NON_COMPLIANT + void k(); // NON_COMPLIANT + /** Member-specific documentation */ + void l(); // COMPLIANT + ///@} + private: /// @brief A Doxygen comment. int c; // COMPLIANT }; +void ClassC::i() { // not flagged, as we will only flag the non-definition + // declaration +} /// A Doxygen comment. void c(); // COMPLIANT @@ -175,4 +195,44 @@ void testFunctionScope() { void fNestedTest(); // COMPLIANT - in function scope }; }; -} \ No newline at end of file +} + +/// Test documentation +template class ClassG { // COMPLIANT +private: + /// Test documentation + int x; // COMPLIANT + +public: + /// Test documentation + friend int foo(ClassG g) { return g.x; } // COMPLIANT +}; + +/// Test documentation +void test() { // COMPLIANT + ClassG g; + foo(g); +} + +/// Test documentation +class ClassG2 { // COMPLIANT +public: + /// Test documentation + friend int foo2() { return 1; } // COMPLIANT +}; + +/// Test documentation +class ClassG3 { // COMPLIANT +public: + friend int foo3() { return 1; } // NON_COMPLIANT +}; + +/// @brief A Doxygen comment. +class ClassH { // COMPLIANT +public: + /// @brief Group with comment at the end. + ///@{ + void m(); // COMPLIANT + void n(); // COMPLIANT + ///@} End of group +}; \ No newline at end of file diff --git a/cpp/autosar/test/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.expected b/cpp/autosar/test/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.expected index f15f142b3b..5b770a1925 100644 --- a/cpp/autosar/test/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.expected +++ b/cpp/autosar/test/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.expected @@ -1,3 +1,4 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (SharedPointerUsedWithNoOwnershipSharing.ql:47,7-15) | test.cpp:14:24:14:26 | sp3 | The ownership of shared_ptr $@ is not shared within or passed out of the local scope of function $@. | test.cpp:14:24:14:26 | sp3 | sp3 | test.cpp:11:22:11:23 | f1 | f1 | | test.cpp:16:24:16:26 | sp5 | The ownership of shared_ptr $@ is not shared within or passed out of the local scope of function $@. | test.cpp:16:24:16:26 | sp5 | sp5 | test.cpp:11:22:11:23 | f1 | f1 | | test.cpp:17:24:17:26 | sp6 | The ownership of shared_ptr $@ is not shared within or passed out of the local scope of function $@. | test.cpp:17:24:17:26 | sp6 | sp6 | test.cpp:11:22:11:23 | f1 | f1 | diff --git a/cpp/autosar/test/rules/A27-0-4/CStyleStringsUsed.expected b/cpp/autosar/test/rules/A27-0-4/CStyleStringsUsed.expected index 6184aad74e..555cb412b8 100644 --- a/cpp/autosar/test/rules/A27-0-4/CStyleStringsUsed.expected +++ b/cpp/autosar/test/rules/A27-0-4/CStyleStringsUsed.expected @@ -1,3 +1,6 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CStyleStringsUsed.ql:39,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CStyleStringsUsed.ql:39,23-31) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CStyleStringsUsed.ql:39,47-55) | test.cpp:7:20:7:27 | CodeQL | Usage of C-style string in $@. | test.cpp:7:20:7:27 | CodeQL | expression | | test.cpp:7:20:7:27 | CodeQL | Usage of C-style string in $@. | test.cpp:16:16:16:17 | a1 | expression | | test.cpp:8:22:8:26 | call to c_str | Usage of C-style string in $@. | test.cpp:8:22:8:26 | call to c_str | expression | diff --git a/cpp/autosar/test/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.expected b/cpp/autosar/test/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.expected deleted file mode 100644 index dc0e220a94..0000000000 --- a/cpp/autosar/test/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.expected +++ /dev/null @@ -1,7 +0,0 @@ -| test.cpp:65:5:65:11 | getB | The trivial member function getB is not defined in the class body of $@. | test.cpp:2:7:2:7 | A | A | -| test.cpp:67:25:67:28 | d | The template member function d is not defined in the class body of $@. | test.cpp:2:7:2:7 | A | A | -| test.cpp:69:5:69:8 | b | The trivial member function b is not defined in the class body of $@. | test.cpp:2:7:2:7 | A | A | -| test.cpp:88:34:88:57 | complexCalculation | The template member function complexCalculation is not defined in the class body of $@. | test.cpp:71:29:71:29 | B | B | -| test.cpp:104:47:104:53 | d | The template member function d is not defined in the class body of $@. | test.cpp:71:29:71:29 | B | B | -| test.cpp:108:27:108:33 | b | The template member function b is not defined in the class body of $@. | test.cpp:71:29:71:29 | B | B | -| test.cpp:113:27:113:36 | getB | The template member function getB is not defined in the class body of $@. | test.cpp:71:29:71:29 | B | B | diff --git a/cpp/autosar/test/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.qlref b/cpp/autosar/test/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.qlref deleted file mode 100644 index c644147bb4..0000000000 --- a/cpp/autosar/test/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A3-1-5/test.cpp b/cpp/autosar/test/rules/A3-1-5/test.cpp index eb1de61b51..e6db0d1190 100644 --- a/cpp/autosar/test/rules/A3-1-5/test.cpp +++ b/cpp/autosar/test/rules/A3-1-5/test.cpp @@ -23,7 +23,7 @@ class A { int complexCalculation(); - int gcd(int a, int b) { + int gcd(int a, int b) { // NON_COMPLIANT if (b == 0) return a; int result = gcd(b, (a % b)); @@ -62,11 +62,11 @@ inline int A::complexCalculation() { // COMPLIANT return 1; } -int A::getB() { return 1; } // NON_COMPLIANT +int A::getB() { return 1; } // COMPLIANT -template T A::d(T t) { return t; } // NON_COMPLIANT +template T A::d(T t) { return t; } // COMPLIANT -int A::b() { return 3; } // NON_COMPLIANT +int A::b() { return 3; } // COMPLIANT template class B { public: @@ -83,9 +83,30 @@ template class B { template T d(T t); int complexCalculation(); + + int complexCalculation2() { // COMPLIANT - template + ; + ; + ; + ; + ; + ; + ; + ; + ; + ; + ; + ; + return 1; + } }; -template inline int B::complexCalculation() { // NON_COMPLIANT +void test_B() { + B b; + b.complexCalculation2(); +} + +template inline int B::complexCalculation() { // COMPLIANT ; ; ; @@ -101,16 +122,16 @@ template inline int B::complexCalculation() { // NON_COMPLIANT return 1; } -template template T B::d(T t) { // NON_COMPLIANT +template template T B::d(T t) { // COMPLIANT return t; } -template int B::b() { // NON_COMPLIANT +template int B::b() { // COMPLIANT C c; return 3; } -template int B::getB() { return 3; } // NON_COMPLIANT +template int B::getB() { return 3; } // COMPLIANT template class Foo { public: @@ -128,8 +149,29 @@ class FooBar { public: ~FooBar(); int f1(int a, int b); + + template int complexCalculation() { // COMPLIANT - template + ; + ; + ; + ; + ; + ; + ; + ; + ; + ; + ; + ; + return 1; + } }; +void test_FooBar() { + FooBar foobar; + foobar.complexCalculation(); +} + FooBar::~FooBar() {} // COMPLIANT want to ignore pImpl uses of destructors int FooBar::f1(int a, int b) { // COMPLIANT not a trivial function @@ -146,4 +188,4 @@ int FooBar::f1(int a, int b) { // COMPLIANT not a trivial function ; ; } -} +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.expected b/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.expected deleted file mode 100644 index 7609c76101..0000000000 --- a/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.expected +++ /dev/null @@ -1,39 +0,0 @@ -| test.cpp:5:17:5:18 | uc | Variable 'uc' has variable-width type. | -| test.cpp:6:15:6:16 | sc | Variable 'sc' has variable-width type. | -| test.cpp:8:7:8:7 | i | Variable 'i' has variable-width type. | -| test.cpp:9:16:9:17 | ui | Variable 'ui' has variable-width type. | -| test.cpp:10:12:10:12 | u | Variable 'u' has variable-width type. | -| test.cpp:11:14:11:15 | si | Variable 'si' has variable-width type. | -| test.cpp:12:10:12:10 | s | Variable 's' has variable-width type. | -| test.cpp:14:9:14:10 | sh | Variable 'sh' has variable-width type. | -| test.cpp:15:18:15:20 | ush | Variable 'ush' has variable-width type. | -| test.cpp:16:16:16:18 | ssh | Variable 'ssh' has variable-width type. | -| test.cpp:18:8:18:8 | l | Variable 'l' has variable-width type. | -| test.cpp:19:17:19:18 | ul | Variable 'ul' has variable-width type. | -| test.cpp:20:15:20:16 | sl | Variable 'sl' has variable-width type. | -| test.cpp:39:23:39:25 | uc1 | Variable 'uc1' has variable-width type. | -| test.cpp:40:21:40:23 | sc1 | Variable 'sc1' has variable-width type. | -| test.cpp:42:13:42:14 | i1 | Variable 'i1' has variable-width type. | -| test.cpp:43:22:43:24 | ui1 | Variable 'ui1' has variable-width type. | -| test.cpp:44:18:44:19 | u1 | Variable 'u1' has variable-width type. | -| test.cpp:45:20:45:22 | si1 | Variable 'si1' has variable-width type. | -| test.cpp:46:16:46:17 | s1 | Variable 's1' has variable-width type. | -| test.cpp:48:15:48:17 | sh1 | Variable 'sh1' has variable-width type. | -| test.cpp:49:24:49:27 | ush1 | Variable 'ush1' has variable-width type. | -| test.cpp:50:22:50:25 | ssh1 | Variable 'ssh1' has variable-width type. | -| test.cpp:52:14:52:15 | l1 | Variable 'l1' has variable-width type. | -| test.cpp:53:23:53:25 | ul1 | Variable 'ul1' has variable-width type. | -| test.cpp:54:21:54:23 | sl1 | Variable 'sl1' has variable-width type. | -| test.cpp:57:26:57:28 | uc2 | Variable 'uc2' has variable-width type. | -| test.cpp:58:24:58:26 | sc2 | Variable 'sc2' has variable-width type. | -| test.cpp:60:16:60:17 | i2 | Variable 'i2' has variable-width type. | -| test.cpp:61:25:61:27 | ui2 | Variable 'ui2' has variable-width type. | -| test.cpp:62:21:62:22 | u2 | Variable 'u2' has variable-width type. | -| test.cpp:63:23:63:25 | si2 | Variable 'si2' has variable-width type. | -| test.cpp:64:19:64:20 | s2 | Variable 's2' has variable-width type. | -| test.cpp:66:18:66:20 | sh2 | Variable 'sh2' has variable-width type. | -| test.cpp:67:27:67:30 | ush2 | Variable 'ush2' has variable-width type. | -| test.cpp:68:25:68:28 | ssh2 | Variable 'ssh2' has variable-width type. | -| test.cpp:70:17:70:18 | l2 | Variable 'l2' has variable-width type. | -| test.cpp:71:26:71:28 | ul2 | Variable 'ul2' has variable-width type. | -| test.cpp:72:24:72:26 | sl2 | Variable 'sl2' has variable-width type. | diff --git a/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.qlref b/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.qlref deleted file mode 100644 index 797bbacc94..0000000000 --- a/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A3-9-1/VariableWidthIntegerTypesUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.testref b/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.testref new file mode 100644 index 0000000000..bb41437be6 --- /dev/null +++ b/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A3-9-1/VariableWidthPlainCharTypeUsed.expected b/cpp/autosar/test/rules/A3-9-1/VariableWidthPlainCharTypeUsed.expected index 6631606cbf..8602920f1e 100644 --- a/cpp/autosar/test/rules/A3-9-1/VariableWidthPlainCharTypeUsed.expected +++ b/cpp/autosar/test/rules/A3-9-1/VariableWidthPlainCharTypeUsed.expected @@ -1,3 +1,3 @@ | test.cpp:4:8:4:8 | c | Variable 'c' has variable-width char type. | -| test.cpp:38:14:38:15 | c1 | Variable 'c1' has variable-width char type. | -| test.cpp:56:17:56:18 | c2 | Variable 'c2' has variable-width char type. | +| test.cpp:10:14:10:15 | c1 | Variable 'c1' has variable-width char type. | +| test.cpp:14:17:14:18 | c2 | Variable 'c2' has variable-width char type. | diff --git a/cpp/autosar/test/rules/A3-9-1/test.cpp b/cpp/autosar/test/rules/A3-9-1/test.cpp index 882738eea1..96ef45142f 100644 --- a/cpp/autosar/test/rules/A3-9-1/test.cpp +++ b/cpp/autosar/test/rules/A3-9-1/test.cpp @@ -2,77 +2,16 @@ void test_variable_width_type_variables() { char c; // NON_COMPLIANT - unsigned char uc; // NON_COMPLIANT - signed char sc; // NON_COMPLIANT - - int i; // NON_COMPLIANT - unsigned int ui; // NON_COMPLIANT - unsigned u; // NON_COMPLIANT - signed int si; // NON_COMPLIANT - signed s; // NON_COMPLIANT - - short sh; // NON_COMPLIANT - unsigned short ush; // NON_COMPLIANT - signed short ssh; // NON_COMPLIANT - - long l; // NON_COMPLIANT - unsigned long ul; // NON_COMPLIANT - signed long sl; // NON_COMPLIANT - - std::int8_t i8; // COMPLIANT - std::int16_t i16; // COMPLIANT - std::int32_t i32; // COMPLIANT - std::int64_t i64; // COMPLIANT - - std::uint8_t u8; // COMPLIANT - std::uint16_t u16; // COMPLIANT - std::uint32_t u32; // COMPLIANT - std::uint64_t u64; // COMPLIANT -} - -int main(int argc, char *argv[]) { // COMPLIANT - // main as an exception + unsigned char uc; // COMPLIANT - covered by VariableWidthIntegerTypesUsed + signed char sc; // COMPLIANT - covered by VariableWidthIntegerTypesUsed } void test_variable_width_type_qualified_variables() { const char c1 = 0; // NON_COMPLIANT - const unsigned char uc1 = 0; // NON_COMPLIANT - const signed char sc1 = 0; // NON_COMPLIANt - - const int i1 = 0; // NON_COMPLIANT - const unsigned int ui1 = 0; // NON_COMPLIANT - const unsigned u1 = 0; // NON_COMPLIANT - const signed int si1 = 0; // NON_COMPLIANT - const signed s1 = 0; // NON_COMPLIANT - - const short sh1 = 0; // NON_COMPLIANT - const unsigned short ush1 = 0; // NON_COMPLIANT - const signed short ssh1 = 0; // NON_COMPLIANT - - const long l1 = 0; // NON_COMPLIANT - const unsigned long ul1 = 0; // NON_COMPLIANT - const signed long sl1 = 0; // NON_COMPLIANT + const unsigned char uc1 = 0; // COMPLIANT - (VariableWidthIntegerTypesUsed) + const signed char sc1 = 0; // COMPLIANT - (VariableWidthIntegerTypesUsed) volatile char c2; // NON_COMPLIANT - volatile unsigned char uc2; // NON_COMPLIANT - volatile signed char sc2; // NON_COMPLIANt - - volatile int i2; // NON_COMPLIANT - volatile unsigned int ui2; // NON_COMPLIANT - volatile unsigned u2; // NON_COMPLIANT - volatile signed int si2; // NON_COMPLIANT - volatile signed s2; // NON_COMPLIANT - - volatile short sh2; // NON_COMPLIANT - volatile unsigned short ush2; // NON_COMPLIANT - volatile signed short ssh2; // NON_COMPLIANT - - volatile long l2; // NON_COMPLIANT - volatile unsigned long ul2; // NON_COMPLIANT - volatile signed long sl2; // NON_COMPLIANT -} - -struct test_fix_fp_614 { - test_fix_fp_614 operator++(int); // COMPLIANT - test_fix_fp_614 operator--(int); // COMPLIANT -}; \ No newline at end of file + volatile unsigned char uc2; // COMPLIANT - (VariableWidthIntegerTypesUsed) + volatile signed char sc2; // COMPLIANT - (VariableWidthIntegerTypesUsed) +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/A4-10-1/NullPointerConstantNotNullptr.qlref b/cpp/autosar/test/rules/A4-10-1/NullPointerConstantNotNullptr.qlref deleted file mode 100644 index d836b834b3..0000000000 --- a/cpp/autosar/test/rules/A4-10-1/NullPointerConstantNotNullptr.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A4-10-1/NullPointerConstantNotNullptr.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A4-10-1/NullPointerConstantNotNullptr.testref b/cpp/autosar/test/rules/A4-10-1/NullPointerConstantNotNullptr.testref new file mode 100644 index 0000000000..aeb655a341 --- /dev/null +++ b/cpp/autosar/test/rules/A4-10-1/NullPointerConstantNotNullptr.testref @@ -0,0 +1 @@ +cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/NullptrNotTheOnlyFormOfTheNullPointerConstant.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.expected b/cpp/autosar/test/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.expected index 4234d93b32..e2b51e5fb9 100644 --- a/cpp/autosar/test/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.expected +++ b/cpp/autosar/test/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.expected @@ -1,15 +1,19 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerArithmeticUsedWithPointersToNonFinalClasses.ql:45,62-70) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerArithmeticUsedWithPointersToNonFinalClasses.ql:46,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerArithmeticUsedWithPointersToNonFinalClasses.ql:55,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerArithmeticUsedWithPointersToNonFinalClasses.ql:61,3-11) edges -| test.cpp:10:18:10:20 | foo | test.cpp:11:23:11:25 | foo | -| test.cpp:10:18:10:20 | foo | test.cpp:11:50:11:52 | foo | -| test.cpp:22:18:22:20 | foo | test.cpp:24:18:24:20 | foo | -| test.cpp:35:11:35:17 | new | test.cpp:38:6:38:7 | l1 | -| test.cpp:35:11:35:17 | new | test.cpp:39:6:39:7 | l1 | -| test.cpp:37:11:37:13 | & ... | test.cpp:40:6:40:7 | l3 | -| test.cpp:37:11:37:13 | & ... | test.cpp:41:6:41:7 | l3 | -| test.cpp:38:6:38:7 | l1 | test.cpp:10:18:10:20 | foo | -| test.cpp:39:6:39:7 | l1 | test.cpp:22:18:22:20 | foo | -| test.cpp:40:6:40:7 | l3 | test.cpp:10:18:10:20 | foo | -| test.cpp:41:6:41:7 | l3 | test.cpp:22:18:22:20 | foo | +| test.cpp:10:18:10:20 | foo | test.cpp:11:23:11:25 | foo | provenance | | +| test.cpp:10:18:10:20 | foo | test.cpp:11:50:11:52 | foo | provenance | | +| test.cpp:22:18:22:20 | foo | test.cpp:24:18:24:20 | foo | provenance | | +| test.cpp:35:11:35:17 | new | test.cpp:38:6:38:7 | l1 | provenance | | +| test.cpp:35:11:35:17 | new | test.cpp:39:6:39:7 | l1 | provenance | | +| test.cpp:37:11:37:13 | & ... | test.cpp:40:6:40:7 | l3 | provenance | | +| test.cpp:37:11:37:13 | & ... | test.cpp:41:6:41:7 | l3 | provenance | | +| test.cpp:38:6:38:7 | l1 | test.cpp:10:18:10:20 | foo | provenance | | +| test.cpp:39:6:39:7 | l1 | test.cpp:22:18:22:20 | foo | provenance | | +| test.cpp:40:6:40:7 | l3 | test.cpp:10:18:10:20 | foo | provenance | | +| test.cpp:41:6:41:7 | l3 | test.cpp:22:18:22:20 | foo | provenance | | nodes | test.cpp:10:18:10:20 | foo | semmle.label | foo | | test.cpp:11:23:11:25 | foo | semmle.label | foo | diff --git a/cpp/autosar/test/rules/A5-1-7/LambdaPassedToDecltype.expected b/cpp/autosar/test/rules/A5-1-7/LambdaPassedToDecltype.expected index 8f6447a96b..56896d69fd 100644 --- a/cpp/autosar/test/rules/A5-1-7/LambdaPassedToDecltype.expected +++ b/cpp/autosar/test/rules/A5-1-7/LambdaPassedToDecltype.expected @@ -1 +1,7 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:20,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:21,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:23,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:28,44-52) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:39,47-55) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:40,9-17) | test.cpp:14:23:14:24 | decltype(...) | Lambda $@ passed as operand to decltype. | test.cpp:5:13:5:30 | [...](...){...} | expression | diff --git a/cpp/autosar/test/rules/A5-1-7/LambdaPassedToTypeid.expected b/cpp/autosar/test/rules/A5-1-7/LambdaPassedToTypeid.expected index 4b19073ded..8f86a87616 100644 --- a/cpp/autosar/test/rules/A5-1-7/LambdaPassedToTypeid.expected +++ b/cpp/autosar/test/rules/A5-1-7/LambdaPassedToTypeid.expected @@ -1,6 +1,10 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToTypeid.ql:21,50-58) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToTypeid.ql:22,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToTypeid.ql:24,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToTypeid.ql:27,39-47) edges -| test.cpp:5:13:5:30 | [...](...){...} | test.cpp:8:38:8:39 | l1 | -| test.cpp:6:13:6:30 | [...](...){...} | test.cpp:9:38:9:39 | l2 | +| test.cpp:5:13:5:30 | [...](...){...} | test.cpp:8:38:8:39 | l1 | provenance | | +| test.cpp:6:13:6:30 | [...](...){...} | test.cpp:9:38:9:39 | l2 | provenance | | nodes | test.cpp:5:13:5:30 | [...](...){...} | semmle.label | [...](...){...} | | test.cpp:6:13:6:30 | [...](...){...} | semmle.label | [...](...){...} | diff --git a/cpp/autosar/test/rules/A5-1-9/test.cpp b/cpp/autosar/test/rules/A5-1-9/test.cpp index 466cf14dfa..511be302a0 100644 --- a/cpp/autosar/test/rules/A5-1-9/test.cpp +++ b/cpp/autosar/test/rules/A5-1-9/test.cpp @@ -104,4 +104,10 @@ class Test_issue468 { LogError("Error"); LogFatal("Fatal"); } -}; \ No newline at end of file +}; + +#define MACRO() [](int i) -> int { return i + 3; } +void test_macros() { + MACRO(); // COMPLIANT + MACRO(); // COMPLIANT - no duplication +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/A5-10-1/PointerToMemberVirtualFunctionWithNullPointerConstant.expected b/cpp/autosar/test/rules/A5-10-1/PointerToMemberVirtualFunctionWithNullPointerConstant.expected deleted file mode 100644 index 81f26e5130..0000000000 --- a/cpp/autosar/test/rules/A5-10-1/PointerToMemberVirtualFunctionWithNullPointerConstant.expected +++ /dev/null @@ -1,2 +0,0 @@ -| test.cpp:14:14:14:29 | ... == ... | A pointer to member virtual function $@ is tested for equality with non-null-pointer-constant $@. | test.cpp:6:16:6:17 | F3 | F3 | test.cpp:14:24:14:29 | F1 | F1 | -| test.cpp:15:14:15:29 | ... == ... | A pointer to member virtual function $@ is tested for equality with non-null-pointer-constant $@. | test.cpp:6:16:6:17 | F3 | F3 | test.cpp:15:24:15:29 | F2 | F2 | diff --git a/cpp/autosar/test/rules/A5-10-1/PointerToMemberVirtualFunctionWithNullPointerConstant.qlref b/cpp/autosar/test/rules/A5-10-1/PointerToMemberVirtualFunctionWithNullPointerConstant.qlref deleted file mode 100644 index 5f588b44ab..0000000000 --- a/cpp/autosar/test/rules/A5-10-1/PointerToMemberVirtualFunctionWithNullPointerConstant.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A5-10-1/PointerToMemberVirtualFunctionWithNullPointerConstant.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A5-10-1/PointerToMemberVirtualFunctionWithNullPointerConstant.testref b/cpp/autosar/test/rules/A5-10-1/PointerToMemberVirtualFunctionWithNullPointerConstant.testref new file mode 100644 index 0000000000..ca8eab9681 --- /dev/null +++ b/cpp/autosar/test/rules/A5-10-1/PointerToMemberVirtualFunctionWithNullPointerConstant.testref @@ -0,0 +1 @@ +cpp/common/test/rules/potentiallyvirtualpointeronlycomparestonullptr/PotentiallyVirtualPointerOnlyComparesToNullptr.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A5-10-1/PotentiallyVirtualPointerOnlyComparesToNullptr.testref b/cpp/autosar/test/rules/A5-10-1/PotentiallyVirtualPointerOnlyComparesToNullptr.testref new file mode 100644 index 0000000000..ca8eab9681 --- /dev/null +++ b/cpp/autosar/test/rules/A5-10-1/PotentiallyVirtualPointerOnlyComparesToNullptr.testref @@ -0,0 +1 @@ +cpp/common/test/rules/potentiallyvirtualpointeronlycomparestonullptr/PotentiallyVirtualPointerOnlyComparesToNullptr.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A5-2-2/test.cpp b/cpp/autosar/test/rules/A5-2-2/test.cpp index fb39868560..d585efc37b 100644 --- a/cpp/autosar/test/rules/A5-2-2/test.cpp +++ b/cpp/autosar/test/rules/A5-2-2/test.cpp @@ -2,7 +2,7 @@ #include #include int foo() { return 1; } - +// A copy of 8.2,2 test.cpp, but with different cases compliant/non-compliant void test_c_style_cast() { double f = 3.14; std::uint32_t n1 = (std::uint32_t)f; // NON_COMPLIANT - C-style cast diff --git a/cpp/autosar/test/rules/A5-2-4/ReinterpretCastUsed.qlref b/cpp/autosar/test/rules/A5-2-4/ReinterpretCastUsed.qlref deleted file mode 100644 index 3cfb0444cc..0000000000 --- a/cpp/autosar/test/rules/A5-2-4/ReinterpretCastUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A5-2-4/ReinterpretCastUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A5-2-4/ReinterpretCastUsed.testref b/cpp/autosar/test/rules/A5-2-4/ReinterpretCastUsed.testref new file mode 100644 index 0000000000..81f18c2d9c --- /dev/null +++ b/cpp/autosar/test/rules/A5-2-4/ReinterpretCastUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/reinterpretcastused/ReinterpretCastUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A5-2-6/OperandsOfALogicalAndOrNotParenthesized.expected b/cpp/autosar/test/rules/A5-2-6/OperandsOfALogicalAndOrNotParenthesized.expected index 90516e6d96..34dbb0db4d 100644 --- a/cpp/autosar/test/rules/A5-2-6/OperandsOfALogicalAndOrNotParenthesized.expected +++ b/cpp/autosar/test/rules/A5-2-6/OperandsOfALogicalAndOrNotParenthesized.expected @@ -1,3 +1,3 @@ -| test.cpp:3:7:3:23 | ... && ... | Binary $@ operand of logical operation is not parenthesized. | test.cpp:3:7:3:12 | ... > ... | operator | -| test.cpp:3:7:3:23 | ... && ... | Binary $@ operand of logical operation is not parenthesized. | test.cpp:3:17:3:23 | ... < ... | operator | -| test.cpp:7:7:7:24 | ... \|\| ... | Binary $@ operand of logical operation is not parenthesized. | test.cpp:7:19:7:24 | ... > ... | operator | +| test.cpp:3:7:3:23 | ... && ... | $@ of logical operation && is not parenthesized. | test.cpp:3:7:3:12 | ... > ... | Left operand > | +| test.cpp:3:7:3:23 | ... && ... | $@ of logical operation && is not parenthesized. | test.cpp:3:17:3:23 | ... < ... | Right operand < | +| test.cpp:7:7:7:24 | ... \|\| ... | $@ of logical operation \|\| is not parenthesized. | test.cpp:7:19:7:24 | ... > ... | Right operand > | diff --git a/cpp/autosar/test/rules/A5-2-6/test.cpp b/cpp/autosar/test/rules/A5-2-6/test.cpp index 0649f7dbc9..961eef3b36 100644 --- a/cpp/autosar/test/rules/A5-2-6/test.cpp +++ b/cpp/autosar/test/rules/A5-2-6/test.cpp @@ -25,6 +25,8 @@ void f2(int p1, int p2) { f1(); } + (p1 > 0) && (p2 > 0) && (p1 > p2); // COMPLIANT - no ambiguity + Sample *sample_ptr = &sample; if ((p1 > 0) || sample_ptr->x) { // COMPLIANT: struct member accessors with diff --git a/cpp/autosar/test/rules/A6-6-1/GotoStatementUsed.expected b/cpp/autosar/test/rules/A6-6-1/GotoStatementUsed.expected deleted file mode 100644 index 9f4343cf1c..0000000000 --- a/cpp/autosar/test/rules/A6-6-1/GotoStatementUsed.expected +++ /dev/null @@ -1 +0,0 @@ -| test.cpp:4:3:4:14 | goto ... | Use of goto. | diff --git a/cpp/autosar/test/rules/A6-6-1/GotoStatementUsed.qlref b/cpp/autosar/test/rules/A6-6-1/GotoStatementUsed.qlref deleted file mode 100644 index d3516aa03b..0000000000 --- a/cpp/autosar/test/rules/A6-6-1/GotoStatementUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A6-6-1/GotoStatementUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A6-6-1/GotoStatementUsed.testref b/cpp/autosar/test/rules/A6-6-1/GotoStatementUsed.testref new file mode 100644 index 0000000000..44d306f80c --- /dev/null +++ b/cpp/autosar/test/rules/A6-6-1/GotoStatementUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/gotostatementshouldnotbeused/GotoStatementShouldNotBeUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A6-6-1/test.cpp b/cpp/autosar/test/rules/A6-6-1/test.cpp deleted file mode 100644 index d13f01961c..0000000000 --- a/cpp/autosar/test/rules/A6-6-1/test.cpp +++ /dev/null @@ -1,9 +0,0 @@ -void test_goto() { - int x = 1; - - goto label1; // NON_COMPLIANT - -label1: - - x = 2; -} \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-1-1/test.cpp b/cpp/autosar/test/rules/A7-1-1/test.cpp index 7895fd950f..1fdc0d66eb 100644 --- a/cpp/autosar/test/rules/A7-1-1/test.cpp +++ b/cpp/autosar/test/rules/A7-1-1/test.cpp @@ -83,4 +83,16 @@ template extern constexpr bool recurse_var = true; // COMPLIANT template extern constexpr bool recurse_var = B1 &&recurse_var; -void fp_621() { recurse_var; } \ No newline at end of file +void fp_621() { recurse_var; } + +#include + +void variadic_forwarding() {} + +template +void variadic_forwarding(T &&first, Args &&...rest) { + first; + variadic_forwarding(std::forward(rest)...); +} + +int test_variadic_forwarding() { variadic_forwarding(1, 1.1, "a"); } diff --git a/cpp/autosar/test/rules/A7-1-2/FunctionMissingConstexpr.expected b/cpp/autosar/test/rules/A7-1-2/FunctionMissingConstexpr.expected deleted file mode 100644 index a6de3fd724..0000000000 --- a/cpp/autosar/test/rules/A7-1-2/FunctionMissingConstexpr.expected +++ /dev/null @@ -1,16 +0,0 @@ -| test.cpp:30:3:30:17 | NonLiteralClass | NonLiteralClass function could be marked as 'constexpr'. | -| test.cpp:59:5:59:6 | h1 | h1 function could be marked as 'constexpr'. | -| test.cpp:67:5:67:6 | h2 | h2 function could be marked as 'constexpr'. | -| test.cpp:100:5:100:6 | h8 | h8 function could be marked as 'constexpr'. | -| test.cpp:117:7:117:9 | mf1 | mf1 function could be marked as 'constexpr'. | -| test.cpp:126:3:126:23 | MissingConstexprClass | MissingConstexprClass function could be marked as 'constexpr'. | -| test.cpp:127:3:127:23 | MissingConstexprClass | MissingConstexprClass function could be marked as 'constexpr'. | -| test.cpp:128:3:128:23 | MissingConstexprClass | MissingConstexprClass function could be marked as 'constexpr'. | -| test.cpp:161:3:161:26 | VariantMemberInitialized | VariantMemberInitialized function could be marked as 'constexpr'. | -| test.cpp:162:3:162:26 | VariantMemberInitialized | VariantMemberInitialized function could be marked as 'constexpr'. | -| test.cpp:163:3:163:26 | VariantMemberInitialized | VariantMemberInitialized function could be marked as 'constexpr'. | -| test.cpp:190:3:190:22 | VariantMemberNotInit | VariantMemberNotInit function could be marked as 'constexpr'. | -| test.cpp:269:26:269:26 | init | init function could be marked as 'constexpr'. | -| test.cpp:269:26:269:29 | init | init function could be marked as 'constexpr'. | -| test.cpp:271:26:271:26 | init | init function could be marked as 'constexpr'. | -| test.cpp:277:6:277:32 | test_template_instantiation | test_template_instantiation function could be marked as 'constexpr'. | diff --git a/cpp/autosar/test/rules/A7-1-2/FunctionMissingConstexpr.qlref b/cpp/autosar/test/rules/A7-1-2/FunctionMissingConstexpr.qlref deleted file mode 100644 index 723a910948..0000000000 --- a/cpp/autosar/test/rules/A7-1-2/FunctionMissingConstexpr.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A7-1-2/FunctionMissingConstexpr.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected b/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected index f86faf1a7b..5feec712b8 100644 --- a/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected +++ b/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected @@ -7,17 +7,18 @@ | test.cpp:41:14:41:15 | l2 | Variable 'l2' could be marked 'constexpr'. | | test.cpp:44:16:44:17 | lc | Variable 'lc' could be marked 'constexpr'. | | test.cpp:45:17:45:19 | lc2 | Variable 'lc2' could be marked 'constexpr'. | -| test.cpp:55:7:55:8 | m2 | Variable 'm2' could be marked 'constexpr'. | -| test.cpp:130:7:130:8 | m1 | Variable 'm1' could be marked 'constexpr'. | -| test.cpp:141:7:141:8 | m1 | Variable 'm1' could be marked 'constexpr'. | -| test.cpp:221:7:221:8 | l1 | Variable 'l1' could be marked 'constexpr'. | -| test.cpp:235:7:235:8 | l6 | Variable 'l6' could be marked 'constexpr'. | -| test.cpp:237:7:237:8 | l8 | Variable 'l8' could be marked 'constexpr'. | -| test.cpp:240:7:240:9 | l10 | Variable 'l10' could be marked 'constexpr'. | -| test.cpp:243:7:243:9 | l12 | Variable 'l12' could be marked 'constexpr'. | -| test.cpp:248:7:248:9 | l15 | Variable 'l15' could be marked 'constexpr'. | -| test.cpp:250:7:250:9 | l16 | Variable 'l16' could be marked 'constexpr'. | -| test.cpp:251:7:251:9 | l17 | Variable 'l17' could be marked 'constexpr'. | -| test.cpp:257:7:257:9 | l21 | Variable 'l21' could be marked 'constexpr'. | -| test.cpp:262:7:262:9 | l24 | Variable 'l24' could be marked 'constexpr'. | -| test.cpp:263:7:263:9 | l25 | Variable 'l25' could be marked 'constexpr'. | +| test.cpp:55:7:55:8 | m2 | Variable 'm2' could be marked 'constexpr' and static. | +| test.cpp:65:7:65:8 | x2 | Variable 'x2' could be marked 'constexpr'. | +| test.cpp:66:13:66:14 | x3 | Variable 'x3' could be marked 'constexpr'. | +| test.cpp:76:7:76:8 | m1 | Variable 'm1' could be marked 'constexpr' and static. | +| test.cpp:91:7:91:8 | l1 | Variable 'l1' could be marked 'constexpr'. | +| test.cpp:105:7:105:8 | l6 | Variable 'l6' could be marked 'constexpr'. | +| test.cpp:107:7:107:8 | l8 | Variable 'l8' could be marked 'constexpr'. | +| test.cpp:110:7:110:9 | l10 | Variable 'l10' could be marked 'constexpr'. | +| test.cpp:113:7:113:9 | l12 | Variable 'l12' could be marked 'constexpr'. | +| test.cpp:118:7:118:9 | l15 | Variable 'l15' could be marked 'constexpr'. | +| test.cpp:120:7:120:9 | l16 | Variable 'l16' could be marked 'constexpr'. | +| test.cpp:121:7:121:9 | l17 | Variable 'l17' could be marked 'constexpr'. | +| test.cpp:127:7:127:9 | l21 | Variable 'l21' could be marked 'constexpr'. | +| test.cpp:132:7:132:9 | l24 | Variable 'l24' could be marked 'constexpr'. | +| test.cpp:133:7:133:9 | l25 | Variable 'l25' could be marked 'constexpr'. | diff --git a/cpp/autosar/test/rules/A7-1-2/test.cpp b/cpp/autosar/test/rules/A7-1-2/test.cpp index 8395f60ff3..5366a59f95 100644 --- a/cpp/autosar/test/rules/A7-1-2/test.cpp +++ b/cpp/autosar/test/rules/A7-1-2/test.cpp @@ -56,154 +56,24 @@ class MemberConstExpr { int m3 = 0; // COMPLIANT - can be set by constructor }; -int h1(int x, int y) { // NON_COMPLIANT - return x + y; -} - -constexpr int h1_correct(int x, int y) { // COMPLIANT - return x + y; -} - -int h2(int x) { return h1(x, 1) + 1; } // NON_COMPLIANT -constexpr int h2_correct(int x) { return h1_correct(x, 1) + 1; } // COMPLIANT - -int h3(int x) { // COMPLIANT - uses goto, so can't be constexpr - if (x) { - goto l1; - } else { - return 10; - } -l1: - return 1; -} - -int h4(int x) { // COMPLIANT - uses try, so can't be constexpr - try { - return 1; - } catch (...) { - } -} +int h1(int x, int y) { return x + y; } -int h5(int x) { // COMPLIANT - declares non literal local var - NonLiteralClass nlc; -} - -int h6(int x) { // COMPLIANT - declares static variable - static int i = x; - return x; -} +constexpr int h1_const(int x, int y) { return x + y; } -int h7(int x) { // COMPLIANT - declares no init variable - int i; +int h2() { + int x1 = h1(1, 1); // COMPLIANT + int x2 = h1_const(1, 1); // NON_COMPLIANT + const int x3 = h1_const(1, 1); // NON_COMPLIANT + constexpr int x4 = h1_const(1, 1); // COMPLIANT } -int h8(int x) { // NON_COMPLIANT - could be constexpr - int i = x; - return i; -} - -constexpr int h8_correct(int x) { // COMPLIANT - int i = x; - return i; -} - -int h9(int x) { // COMPLIANT - declares thread local variable - thread_local int i = x; - return x; -} - -class ConstexprFunctionClass { -public: - int mf1(int x) { return m1 + x; } // NON_COMPLIANT - constexpr int mf1_correct(int x) { return m1 + x; } // COMPLIANT - -private: - int m1; -}; - class MissingConstexprClass { public: MissingConstexprClass() = default; // NON_COMPLIANT MissingConstexprClass(int i) = delete; // NON_COMPLIANT MissingConstexprClass(int i, LiteralClass lc) {} // NON_COMPLIANT private: - int m1 = 0; -}; - -class VirtualBaseClass {}; - -class DerivedClass : public virtual VirtualBaseClass { -public: - DerivedClass() = default; // COMPLIANT - DerivedClass(int i) = delete; // COMPLIANT - DerivedClass(int i, LiteralClass lc) {} // COMPLIANT -private: - int m1 = 0; -}; - -class NotAllMembersInitializedClass { -public: - NotAllMembersInitializedClass() = default; // COMPLIANT - NotAllMembersInitializedClass(int i) = delete; // COMPLIANT - NotAllMembersInitializedClass(int i, LiteralClass lc) {} // COMPLIANT -private: - int m1; -}; - -class NonLiteralParamsClass { -public: - NonLiteralParamsClass(int i, NonLiteralClass lc) {} // COMPLIANT -}; - -// Variant members are always initialized, so this can be marked constexpr -class VariantMemberInitialized { -public: - VariantMemberInitialized() = default; // NON_COMPLIANT - VariantMemberInitialized(int i) = delete; // NON_COMPLIANT - VariantMemberInitialized(int i, LiteralClass lc) {} // NON_COMPLIANT -private: - union { - int i = 0; - short s; - }; -}; - -class VariantMemberInitConstexpr { -public: - constexpr VariantMemberInitConstexpr() = default; // COMPLIANT - constexpr VariantMemberInitConstexpr(int i) = delete; // COMPLIANT - constexpr VariantMemberInitConstexpr(int i, LiteralClass lc) {} // COMPLIANT -private: - union { - int i = 0; - short s; - }; -}; - -// Variant members are not initialized at declaration, so we can only mark the -// constructors as constexpr if we explicitly initialize the variant member -class VariantMemberNotInit { -public: - VariantMemberNotInit() = default; // COMPLIANT - VariantMemberNotInit(int pi) = delete; // COMPLIANT - VariantMemberNotInit(int pi, LiteralClass lc) {} // COMPLIANT - VariantMemberNotInit(LiteralClass lc, int pi) : i(pi) {} // NON_COMPLIANT - constexpr VariantMemberNotInit(LiteralClass lc, short pi) // COMPLIANT - : i(pi) {} - -private: - union { - int i; - short s; - }; -}; - -class ExcludedCases { -public: - ~ExcludedCases() {} // COMPLIANT - - void operator=(ExcludedCases &) {} // COMPLIANT - void operator=(ExcludedCases &&) {} // COMPLIANT + int m1 = 0; // NON_COMPLIANT }; extern int random(); @@ -274,4 +144,4 @@ template T *init() { return t; } -void test_template_instantiation() { int *t = init(); } \ No newline at end of file +void test_template_instantiation() { int *t = init(); } diff --git a/cpp/autosar/test/rules/A7-1-3/CvQualifiersNotPlacedOnTheRightHandSide.expected b/cpp/autosar/test/rules/A7-1-3/CvQualifiersNotPlacedOnTheRightHandSide.expected index 9d6a710449..d845df142d 100644 --- a/cpp/autosar/test/rules/A7-1-3/CvQualifiersNotPlacedOnTheRightHandSide.expected +++ b/cpp/autosar/test/rules/A7-1-3/CvQualifiersNotPlacedOnTheRightHandSide.expected @@ -1,3 +1,4 @@ | test.cpp:9:16:9:19 | definition of ptr1 | There is possibly a const or volatile specifier on the left hand side of typedef name $@. | test.cpp:1:7:1:12 | intptr | intptr | | test.cpp:10:19:10:22 | definition of ptr2 | There is possibly a const or volatile specifier on the left hand side of typedef name $@. | test.cpp:1:7:1:12 | intptr | intptr | | test.cpp:19:21:19:24 | definition of ptr8 | There is possibly a const or volatile specifier on the left hand side of typedef name $@. | test.cpp:3:7:3:17 | constintptr | constintptr | +| test.cpp:32:23:32:26 | definition of u32d | There is possibly a const or volatile specifier on the left hand side of typedef name uint32_t. | test.cpp:32:23:32:26 | definition of u32d | | diff --git a/cpp/autosar/test/rules/A7-1-3/test.cpp b/cpp/autosar/test/rules/A7-1-3/test.cpp index 621a64115d..39f53b8623 100644 --- a/cpp/autosar/test/rules/A7-1-3/test.cpp +++ b/cpp/autosar/test/rules/A7-1-3/test.cpp @@ -18,4 +18,16 @@ void f() { constintptr const ptr7 = &l; // COMPLIANT const constintptr ptr8 = &l; // NON_COMPLIANT inttypedef ptr9 = l; // COMPLIANT +} + +#include + +void false_positive() { + std::uint8_t u8{0}; + + auto const u32 = static_cast(u8); // COMPLIANT - auto ignored + std::uint32_t const u32b = static_cast(u8); // COMPLIANT + + const auto u32c = static_cast(u8); // COMPLIANT - auto ignored + const std::uint32_t u32d = static_cast(u8); // NON_COMPLIANT } \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-1-7/test.cpp b/cpp/autosar/test/rules/A7-1-7/test.cpp index 7c5a6263cf..80f6542b11 100644 --- a/cpp/autosar/test/rules/A7-1-7/test.cpp +++ b/cpp/autosar/test/rules/A7-1-7/test.cpp @@ -152,4 +152,14 @@ void example_function() { f1(); } // COMPLIANT // clang-format off typedef struct x { int y; } z; //COMPLIANT - for struct typedef and struct var //NON_COMPLIANT - for struct all on one line -// clang-format on \ No newline at end of file +// clang-format on + +#define foo(x, y) \ + x++; \ + y++; + +void test_foo() { + int a = 1; + int b = 1; + foo(a, b); // COMPLIANT +} diff --git a/cpp/autosar/test/rules/A7-2-1/NonEnumeratorEnumValue.expected b/cpp/autosar/test/rules/A7-2-1/NonEnumeratorEnumValue.expected index 9c99c44897..6ac5cfca86 100644 --- a/cpp/autosar/test/rules/A7-2-1/NonEnumeratorEnumValue.expected +++ b/cpp/autosar/test/rules/A7-2-1/NonEnumeratorEnumValue.expected @@ -7,4 +7,4 @@ | test.cpp:27:12:27:25 | (Foo)... | Cast to enum $@ with from expression with range 0...3 which may not be one of the enumerator values in function test_bitwise_or. | test.cpp:2:6:2:8 | Foo | Foo | | test.cpp:28:12:28:25 | (Foo)... | Cast to enum $@ with from expression with range 0...7 which may not be one of the enumerator values in function test_bitwise_or. | test.cpp:2:6:2:8 | Foo | Foo | | test.cpp:39:12:39:17 | (Bar)... | Cast to enum $@ with from expression with range 1...1 which may not be one of the enumerator values in function test_constant. | test.cpp:5:6:5:8 | Bar | Bar | -| test.cpp:41:12:41:17 | (Bar)... | Cast to enum $@ with from expression with value 1_+ which is not one of the enumerator values in function test_constant. | test.cpp:5:6:5:8 | Bar | Bar | +| test.cpp:41:12:41:17 | (Bar)... | Cast to enum $@ with from expression with value 1 which is not one of the enumerator values in function test_constant. | test.cpp:5:6:5:8 | Bar | Bar | diff --git a/cpp/autosar/test/rules/A7-2-2/EnumerationUnderlyingBaseTypeNotExplicitlyDefined.qlref b/cpp/autosar/test/rules/A7-2-2/EnumerationUnderlyingBaseTypeNotExplicitlyDefined.qlref deleted file mode 100644 index 1ed510a506..0000000000 --- a/cpp/autosar/test/rules/A7-2-2/EnumerationUnderlyingBaseTypeNotExplicitlyDefined.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A7-2-2/EnumerationUnderlyingBaseTypeNotExplicitlyDefined.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-2-2/EnumerationUnderlyingBaseTypeNotExplicitlyDefined.testref b/cpp/autosar/test/rules/A7-2-2/EnumerationUnderlyingBaseTypeNotExplicitlyDefined.testref new file mode 100644 index 0000000000..d7a73fd488 --- /dev/null +++ b/cpp/autosar/test/rules/A7-2-2/EnumerationUnderlyingBaseTypeNotExplicitlyDefined.testref @@ -0,0 +1 @@ +cpp/common/test/rules/enumerationnotdefinedwithanexplicitunderlyingtype/EnumerationNotDefinedWithAnExplicitUnderlyingType.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-3-1/DefinitionNotConsideredForUnqualifiedLookup.qlref b/cpp/autosar/test/rules/A7-3-1/DefinitionNotConsideredForUnqualifiedLookup.qlref deleted file mode 100644 index 0fe94e847c..0000000000 --- a/cpp/autosar/test/rules/A7-3-1/DefinitionNotConsideredForUnqualifiedLookup.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A7-3-1/DefinitionNotConsideredForUnqualifiedLookup.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-3-1/DefinitionNotConsideredForUnqualifiedLookup.testref b/cpp/autosar/test/rules/A7-3-1/DefinitionNotConsideredForUnqualifiedLookup.testref new file mode 100644 index 0000000000..7a5ae74d2e --- /dev/null +++ b/cpp/autosar/test/rules/A7-3-1/DefinitionNotConsideredForUnqualifiedLookup.testref @@ -0,0 +1 @@ +cpp/common/test/rules/definitionnotconsideredforunqualifiedlookup/DefinitionNotConsideredForUnqualifiedLookup.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-3-1/HiddenInheritedNonOverridableMemberFunction.qlref b/cpp/autosar/test/rules/A7-3-1/HiddenInheritedNonOverridableMemberFunction.qlref deleted file mode 100644 index d94c3c0b0a..0000000000 --- a/cpp/autosar/test/rules/A7-3-1/HiddenInheritedNonOverridableMemberFunction.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A7-3-1/HiddenInheritedNonOverridableMemberFunction.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-3-1/HiddenInheritedNonOverridableMemberFunction.testref b/cpp/autosar/test/rules/A7-3-1/HiddenInheritedNonOverridableMemberFunction.testref new file mode 100644 index 0000000000..2fb9608ee8 --- /dev/null +++ b/cpp/autosar/test/rules/A7-3-1/HiddenInheritedNonOverridableMemberFunction.testref @@ -0,0 +1 @@ +cpp/common/test/rules/hiddeninheritednonoverridablememberfunction/HiddenInheritedNonOverridableMemberFunction.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-3-1/HiddenInheritedOverridableMemberFunction.qlref b/cpp/autosar/test/rules/A7-3-1/HiddenInheritedOverridableMemberFunction.qlref deleted file mode 100644 index 57d16c4e90..0000000000 --- a/cpp/autosar/test/rules/A7-3-1/HiddenInheritedOverridableMemberFunction.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A7-3-1/HiddenInheritedOverridableMemberFunction.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-3-1/HiddenInheritedOverridableMemberFunction.testref b/cpp/autosar/test/rules/A7-3-1/HiddenInheritedOverridableMemberFunction.testref new file mode 100644 index 0000000000..e768ced8d3 --- /dev/null +++ b/cpp/autosar/test/rules/A7-3-1/HiddenInheritedOverridableMemberFunction.testref @@ -0,0 +1 @@ +cpp/common/test/rules/hiddeninheritedoverridablememberfunction/HiddenInheritedOverridableMemberFunction.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-4-1/AsmDeclarationUsed.qlref b/cpp/autosar/test/rules/A7-4-1/AsmDeclarationUsed.qlref deleted file mode 100644 index 286e62bd18..0000000000 --- a/cpp/autosar/test/rules/A7-4-1/AsmDeclarationUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A7-4-1/AsmDeclarationUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-4-1/AsmDeclarationUsed.testref b/cpp/autosar/test/rules/A7-4-1/AsmDeclarationUsed.testref new file mode 100644 index 0000000000..f643f6a9c7 --- /dev/null +++ b/cpp/autosar/test/rules/A7-4-1/AsmDeclarationUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/asmdeclarationused/AsmDeclarationUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-5-1/InvalidFunctionReturnType.expected b/cpp/autosar/test/rules/A7-5-1/InvalidFunctionReturnType.expected index b6d9490803..3287ba88d1 100644 --- a/cpp/autosar/test/rules/A7-5-1/InvalidFunctionReturnType.expected +++ b/cpp/autosar/test/rules/A7-5-1/InvalidFunctionReturnType.expected @@ -1,2 +1,5 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (InvalidFunctionReturnType.ql:27,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (InvalidFunctionReturnType.ql:27,23-31) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (InvalidFunctionReturnType.ql:27,51-59) | test.cpp:5:3:5:11 | return ... | Function test_refconst_return returns a reference or a pointer to $@ that is passed by reference to const. | test.cpp:4:44:4:44 | x | parameter | | test.cpp:8:3:8:14 | return ... | Function test_ptrconst_return returns a reference or a pointer to $@ that is passed by reference to const. | test.cpp:7:44:7:44 | x | parameter | diff --git a/cpp/autosar/test/rules/A7-5-2/RecursiveFunctions.qlref b/cpp/autosar/test/rules/A7-5-2/RecursiveFunctions.qlref deleted file mode 100644 index 10fccea7f7..0000000000 --- a/cpp/autosar/test/rules/A7-5-2/RecursiveFunctions.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A7-5-2/RecursiveFunctions.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-5-2/RecursiveFunctions.testref b/cpp/autosar/test/rules/A7-5-2/RecursiveFunctions.testref new file mode 100644 index 0000000000..f459a29bf1 --- /dev/null +++ b/cpp/autosar/test/rules/A7-5-2/RecursiveFunctions.testref @@ -0,0 +1 @@ +cpp/common/test/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.expected b/cpp/autosar/test/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.expected index b751d81835..2ce56fdce9 100644 --- a/cpp/autosar/test/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.expected +++ b/cpp/autosar/test/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.expected @@ -1,3 +1,5 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (SmartPointerAsParameterWithoutLifetimeSemantics.ql:47,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (SmartPointerAsParameterWithoutLifetimeSemantics.ql:56,5-13) | test.cpp:7:41:7:43 | up1 | Function $@ takes smart pointer parameter 'up1' but does not implement any lifetime-affecting operations. | test.cpp:7:6:7:18 | smart_ptr_get | smart_ptr_get | | test.cpp:16:53:16:55 | sp1 | Function $@ takes smart pointer parameter 'sp1' but does not implement any lifetime-affecting operations. | test.cpp:16:6:16:29 | smart_ptr_ref_assign_ref | smart_ptr_ref_assign_ref | | test.cpp:28:55:28:57 | sp1 | Function $@ takes smart pointer parameter 'sp1' but does not implement any lifetime-affecting operations. | test.cpp:28:6:28:31 | smart_ptr_ref_noncompliant | smart_ptr_ref_noncompliant | diff --git a/cpp/autosar/test/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.expected b/cpp/autosar/test/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.expected index a01b93335d..0a8ead4af8 100644 --- a/cpp/autosar/test/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.expected +++ b/cpp/autosar/test/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.expected @@ -1,3 +1,5 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UniquePtrPassedToFunctionWithImproperSemantics.ql:41,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UniquePtrPassedToFunctionWithImproperSemantics.ql:51,5-13) | test.cpp:13:55:13:56 | v1 | Parameter of type std::unique_ptr passed as lvalue reference but not used to modify underlying object. | | test.cpp:17:47:17:48 | v1 | Parameter of type std::unique_ptr passed as lvalue reference but not used to modify underlying object. | | test.cpp:22:27:22:28 | v1 | Parameter of type std::unique_ptr passed as lvalue reference but not used to modify underlying object. | diff --git a/cpp/autosar/test/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.expected b/cpp/autosar/test/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.expected index e3cfa71bb7..25fe77d9a5 100644 --- a/cpp/autosar/test/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.expected +++ b/cpp/autosar/test/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.expected @@ -1,3 +1,5 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (InOutParametersDeclaredAsTNotModified.ql:50,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (InOutParametersDeclaredAsTNotModified.ql:64,7-15) | test.cpp:4:13:4:13 | i | In-out parameter i that is not written to. | | test.cpp:7:22:7:24 | str | In-out parameter str that is not read from. | | test.cpp:18:14:18:14 | i | In-out parameter i that is not read from. | diff --git a/cpp/autosar/test/rules/A8-5-4/ConfusingUseOfInitializerListConstructors.qlref b/cpp/autosar/test/rules/A8-5-4/ConfusingUseOfInitializerListConstructors.qlref deleted file mode 100644 index eb351d9e36..0000000000 --- a/cpp/autosar/test/rules/A8-5-4/ConfusingUseOfInitializerListConstructors.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A8-5-4/ConfusingUseOfInitializerListConstructors.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A8-5-4/ConfusingUseOfInitializerListConstructors.testref b/cpp/autosar/test/rules/A8-5-4/ConfusingUseOfInitializerListConstructors.testref new file mode 100644 index 0000000000..49b73d06a9 --- /dev/null +++ b/cpp/autosar/test/rules/A8-5-4/ConfusingUseOfInitializerListConstructors.testref @@ -0,0 +1 @@ +cpp/common/test/rules/initializerlistconstructoristheonlyconstructor/InitializerListConstructorIsTheOnlyConstructor.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.expected b/cpp/autosar/test/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.expected index 04c1f35a45..70892c12c8 100644 --- a/cpp/autosar/test/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.expected +++ b/cpp/autosar/test/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.expected @@ -1,3 +1,6 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql:73,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql:73,23-31) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql:73,46-54) | test.cpp:20:8:20:12 | getB2 | Member function A::getB2 $@ a non-const raw pointer or reference to a private or protected $@. | test.cpp:20:25:20:25 | b | returns | test.cpp:54:7:54:7 | b | field | | test.cpp:22:8:22:12 | getB3 | Member function A::getB3 $@ a non-const raw pointer or reference to a private or protected $@. | test.cpp:22:25:22:26 | & ... | returns | test.cpp:54:7:54:7 | b | field | | test.cpp:24:8:24:13 | getB33 | Member function A::getB33 $@ a non-const raw pointer or reference to a private or protected $@. | test.cpp:26:12:26:13 | bb | returns | test.cpp:54:7:54:7 | b | field | diff --git a/cpp/autosar/test/rules/M0-1-10.1/UnusedFunction.expected b/cpp/autosar/test/rules/M0-1-10.1/UnusedFunction.expected new file mode 100644 index 0000000000..3f58065520 --- /dev/null +++ b/cpp/autosar/test/rules/M0-1-10.1/UnusedFunction.expected @@ -0,0 +1 @@ +| test.cpp:23:14:23:26 | uncalled_func | Function uncalled_func is never called. | diff --git a/cpp/autosar/test/rules/M0-1-10.1/UnusedFunction.qlref b/cpp/autosar/test/rules/M0-1-10.1/UnusedFunction.qlref new file mode 100644 index 0000000000..519660f289 --- /dev/null +++ b/cpp/autosar/test/rules/M0-1-10.1/UnusedFunction.qlref @@ -0,0 +1 @@ +rules/M0-1-10/UnusedFunction.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M0-1-10.1/test.cpp b/cpp/autosar/test/rules/M0-1-10.1/test.cpp new file mode 100644 index 0000000000..5b9c68a827 --- /dev/null +++ b/cpp/autosar/test/rules/M0-1-10.1/test.cpp @@ -0,0 +1,39 @@ +#include + +namespace mains { +static std::int32_t var; + +// @brief namespace_func +static void +namespace_func(void) noexcept { // COMPLIANT: Called from "main" below. + mains::var = -1; + return; +} +} // namespace mains + +std::int32_t func2() // COMPLIANT: Called from func1 +{ + return mains::var + 20; +} + +std::int32_t func1() { // COMPLIANT: Called from main + return mains::var + func2(); // func2 called here. +} + +std::int32_t uncalled_func() // NON_COMPLIANT: Not called. +{ + return mains::var + func1(); // func1 called here. +} + +// @brief main +// @return exit code +std::int32_t main(void) { + std::int32_t ret{0}; + try { + ret = func1(); // func1 called here. + mains::var += ret; + } catch (...) { + mains::namespace_func(); // namespace_func called here. + } + return ret; +} diff --git a/cpp/autosar/test/rules/M0-1-10/UnusedFunction.expected b/cpp/autosar/test/rules/M0-1-10/UnusedFunction.expected index d9ab0d38ac..912e2104e8 100644 --- a/cpp/autosar/test/rules/M0-1-10/UnusedFunction.expected +++ b/cpp/autosar/test/rules/M0-1-10/UnusedFunction.expected @@ -10,4 +10,5 @@ | test.cpp:50:5:50:6 | i3 | Function C::i3 is never called. | | test.cpp:51:8:51:9 | i4 | Function C::i4 is never called. | | test.cpp:52:15:52:16 | i5 | Function C::i5 is never called. | -| test.cpp:69:17:69:18 | g4 | Function g4 is never called. | +| test.cpp:79:6:79:21 | anUnusedFunction | Function anUnusedFunction is never called. | +| test.cpp:113:17:113:18 | g4 | Function g4 is never called. | diff --git a/cpp/autosar/test/rules/M0-1-10/UnusedSplMemberFunction.expected b/cpp/autosar/test/rules/M0-1-10/UnusedSplMemberFunction.expected new file mode 100644 index 0000000000..e2bf0acc79 --- /dev/null +++ b/cpp/autosar/test/rules/M0-1-10/UnusedSplMemberFunction.expected @@ -0,0 +1,2 @@ +| test.cpp:71:5:71:16 | ANestedClass | Special member function ANestedClass is never called. | +| test.cpp:82:5:82:22 | AnotherNestedClass | Special member function AnotherNestedClass is never called from a main function or entry point. | diff --git a/cpp/autosar/test/rules/M0-1-10/UnusedSplMemberFunction.qlref b/cpp/autosar/test/rules/M0-1-10/UnusedSplMemberFunction.qlref new file mode 100644 index 0000000000..899f00fda1 --- /dev/null +++ b/cpp/autosar/test/rules/M0-1-10/UnusedSplMemberFunction.qlref @@ -0,0 +1 @@ +rules/M0-1-10/UnusedSplMemberFunction.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M0-1-10/test.cpp b/cpp/autosar/test/rules/M0-1-10/test.cpp index 748d2196ef..e1a19abf24 100644 --- a/cpp/autosar/test/rules/M0-1-10/test.cpp +++ b/cpp/autosar/test/rules/M0-1-10/test.cpp @@ -52,6 +52,50 @@ template class C { inline void i5() {} // NON_COMPLIANT - never used in any instantiation }; +#include "test.hpp" +#include + +template +constexpr bool aConstExprFunc() noexcept { // COMPLIANT + static_assert(std::is_trivially_copy_constructible() && + std::is_trivially_copy_constructible(), + "assert"); + return true; +} + +template class AClass { T anArr[val]; }; + +void aCalledFunc1() // COMPLIANT +{ + struct ANestedClass { + ANestedClass() noexcept(false) { // COMPLIANT: False Positive! + static_cast(0); + } + }; + static_assert(std::is_trivially_copy_constructible>(), + "Must be trivially copy constructible"); +} + +void anUnusedFunction() // NON_COMPLIANT +{ + struct AnotherNestedClass { + AnotherNestedClass() noexcept(false) { // NON_COMPLAINT + static_cast(0); + } + }; + AnotherNestedClass d; +} + +void aCalledFunc2() // COMPLIANT +{ + struct YetAnotherNestedClass { + YetAnotherNestedClass() noexcept(false) { + static_cast(0); + } // COMPLIANT + }; + YetAnotherNestedClass d; +}; + int main() { // COMPLIANT - this is a main like function which acts as an entry // point f3(); @@ -88,8 +132,37 @@ int main() { // COMPLIANT - this is a main like function which acts as an entry c1.getAT(); S s; c2.i1(s); + + int aVar; + aConstExprFunc(); + aCalledFunc1(); + aCalledFunc2(); } class M { public: M(const M &) = delete; // COMPLIANT - ignore if deleted -}; \ No newline at end of file +}; + +#include +int called_from_google_test_function( + int a_param) // COMPLIANT - called from TEST +{ + int something = a_param; + something++; + return something; +} + +TEST(sample_test, + called_from_google_test_function) // COMPLIANT - Google Test function +{ + bool pass = false; + if (called_from_google_test_function(0) >= 10) + pass = true; + struct a_nested_class_in_gtest { + a_nested_class_in_gtest() noexcept(false) { + static_cast(0); + } // COMPLIANT + }; + static_assert(std::is_trivially_copy_constructible(), + "assert"); +} diff --git a/cpp/autosar/test/rules/M0-1-10/test.hpp b/cpp/autosar/test/rules/M0-1-10/test.hpp new file mode 100644 index 0000000000..a2da990951 --- /dev/null +++ b/cpp/autosar/test/rules/M0-1-10/test.hpp @@ -0,0 +1,4 @@ +template +constexpr T aCalledFuncInHeader(T value) noexcept { // COMPLIANT + return static_cast(value); +} diff --git a/cpp/autosar/test/rules/M0-1-2/InfeasiblePath.expected b/cpp/autosar/test/rules/M0-1-2/InfeasiblePath.expected index 9cb237e8b3..b5528014d1 100644 --- a/cpp/autosar/test/rules/M0-1-2/InfeasiblePath.expected +++ b/cpp/autosar/test/rules/M0-1-2/InfeasiblePath.expected @@ -8,3 +8,4 @@ | test.cpp:86:9:86:14 | ... < ... | The true path is infeasible because 0 (max value: 0) is always less than or equal to a (minimum value: 0). | | test.cpp:117:7:117:7 | 0 | The path is unreachable in a template. | | test.cpp:123:7:123:8 | ! ... | The path is unreachable in a template. | +| test.cpp:137:7:137:12 | ... > ... | The path is unreachable in a template. | diff --git a/cpp/autosar/test/rules/M0-1-2/test.cpp b/cpp/autosar/test/rules/M0-1-2/test.cpp index 31c564d8a5..f36cbc790d 100644 --- a/cpp/autosar/test/rules/M0-1-2/test.cpp +++ b/cpp/autosar/test/rules/M0-1-2/test.cpp @@ -131,4 +131,15 @@ void test_infeasible_instantiates() { template_infeasible_true_path(); template_infeasible_false_path(); template_infeasible_false_path(); +} + +template int template_infeasible_relation() { + if (i > -1) { // NON_COMPLIANT - true path is infeasible in all circumstances + return 3; + } +} + +void test_infeasible_relation() { + template_infeasible_relation<0>(); + template_infeasible_relation<1>(); } \ No newline at end of file diff --git a/cpp/autosar/test/rules/M0-1-3/UnusedLocalVariable.expected b/cpp/autosar/test/rules/M0-1-3/UnusedLocalVariable.expected index d6f398369f..19317d1d0d 100644 --- a/cpp/autosar/test/rules/M0-1-3/UnusedLocalVariable.expected +++ b/cpp/autosar/test/rules/M0-1-3/UnusedLocalVariable.expected @@ -1,7 +1,6 @@ | test.cpp:7:7:7:7 | y | Local variable 'y' in 'test_simple' is not used. | -| test.cpp:14:13:14:13 | y | Local variable 'y' in 'test_const' is not used. | -| test.cpp:17:7:17:7 | z | Local variable 'z' in 'test_const' is not used. | -| test.cpp:23:5:23:5 | t | Local variable 't' in 'f1' is not used. | -| test.cpp:23:5:23:5 | t | Local variable 't' in 'f1' is not used. | -| test.cpp:44:6:44:6 | a | Local variable 'a' in 'test_side_effect_init' is not used. | -| test.cpp:91:5:91:5 | t | Local variable 't' in 'template_function' is not used. | +| test.cpp:15:7:15:7 | z | Local variable 'z' in 'test_const' is not used. | +| test.cpp:21:5:21:5 | t | Local variable 't' in 'f1' is not used. | +| test.cpp:21:5:21:5 | t | Local variable 't' in 'f1' is not used. | +| test.cpp:42:6:42:6 | a | Local variable 'a' in 'test_side_effect_init' is not used. | +| test.cpp:89:5:89:5 | t | Local variable 't' in 'template_function' is not used. | diff --git a/cpp/autosar/test/rules/M0-1-3/test.cpp b/cpp/autosar/test/rules/M0-1-3/test.cpp index a591c7e82b..5c9c4a3413 100644 --- a/cpp/autosar/test/rules/M0-1-3/test.cpp +++ b/cpp/autosar/test/rules/M0-1-3/test.cpp @@ -11,9 +11,7 @@ int test_simple() { int test_const() { const int x = 1; // COMPLIANT - used below - const int y = 2; // COMPLIANT[FALSE_POSITIVE] - used in array initialization, - // but the database does not contain sufficient information - // for this case + const int y = 2; // COMPLIANT - used in array initialization, int z[y]; // NON_COMPLIANT - never used return x; } @@ -98,4 +96,20 @@ class ClassT { void test() {} }; -void test_template_function() { template_function(); } \ No newline at end of file +void test_template_function() { template_function(); } + +int foo() { + constexpr int arrayDim = 10; // COMPLIANT - used in array size below + static int array[arrayDim]{}; + return array[4]; +} + +template static T another_templ_function() { return T(); } + +template +static T another_templ_function(const First &first, const Rest &...rest) { + return first + + another_templ_function(rest...); // COMPLIANT - 'rest' is used here +} + +static int templ_fnc2() { return another_templ_function(1, 2, 3, 4, 5); } diff --git a/cpp/autosar/test/rules/M0-2-1/DoNotPassAliasedPointerToParam.testref b/cpp/autosar/test/rules/M0-2-1/DoNotPassAliasedPointerToParam.testref new file mode 100644 index 0000000000..2c64dedd45 --- /dev/null +++ b/cpp/autosar/test/rules/M0-2-1/DoNotPassAliasedPointerToParam.testref @@ -0,0 +1 @@ +cpp/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M0-2-1/test.cpp b/cpp/autosar/test/rules/M0-2-1/test.cpp index e5848e2752..3329f12824 100644 --- a/cpp/autosar/test/rules/M0-2-1/test.cpp +++ b/cpp/autosar/test/rules/M0-2-1/test.cpp @@ -51,4 +51,4 @@ void internal_shift() { void separate_access() { UnionSecret_t hash1, hash2; hash2.diff.suffix = hash1.fnv.suffix; // COMPLIANT, different union. -} \ No newline at end of file +} diff --git a/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.expected b/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.expected deleted file mode 100644 index 76cbcebed0..0000000000 --- a/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.expected +++ /dev/null @@ -1 +0,0 @@ -| test.cpp:16:3:16:8 | call to remove | Return value is not tested for errors. | diff --git a/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.qlref b/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.qlref deleted file mode 100644 index 3cfea1dc31..0000000000 --- a/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M0-3-2/FunctionErroneousReturnValueNotTested.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.testref b/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.testref new file mode 100644 index 0000000000..50847523ce --- /dev/null +++ b/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.testref @@ -0,0 +1 @@ +cpp/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M10-1-3/AccessibleBaseClassBothVirtualAndNonVirtualInHierarchy.qlref b/cpp/autosar/test/rules/M10-1-3/AccessibleBaseClassBothVirtualAndNonVirtualInHierarchy.qlref deleted file mode 100644 index 208baa8d08..0000000000 --- a/cpp/autosar/test/rules/M10-1-3/AccessibleBaseClassBothVirtualAndNonVirtualInHierarchy.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M10-1-3/AccessibleBaseClassBothVirtualAndNonVirtualInHierarchy.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M10-1-3/AccessibleBaseClassBothVirtualAndNonVirtualInHierarchy.testref b/cpp/autosar/test/rules/M10-1-3/AccessibleBaseClassBothVirtualAndNonVirtualInHierarchy.testref new file mode 100644 index 0000000000..fe57c50fe3 --- /dev/null +++ b/cpp/autosar/test/rules/M10-1-3/AccessibleBaseClassBothVirtualAndNonVirtualInHierarchy.testref @@ -0,0 +1 @@ +cpp/common/test/rules/virtualandnonvirtualclassinthehierarchy/VirtualAndNonVirtualClassInTheHierarchy.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M12-1-1/DynamicTypeOfThisUsedFromConstructorOrDestructor.qlref b/cpp/autosar/test/rules/M12-1-1/DynamicTypeOfThisUsedFromConstructorOrDestructor.qlref deleted file mode 100644 index 4235959d77..0000000000 --- a/cpp/autosar/test/rules/M12-1-1/DynamicTypeOfThisUsedFromConstructorOrDestructor.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M12-1-1/DynamicTypeOfThisUsedFromConstructorOrDestructor.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M12-1-1/DynamicTypeOfThisUsedFromConstructorOrDestructor.testref b/cpp/autosar/test/rules/M12-1-1/DynamicTypeOfThisUsedFromConstructorOrDestructor.testref new file mode 100644 index 0000000000..596f74b010 --- /dev/null +++ b/cpp/autosar/test/rules/M12-1-1/DynamicTypeOfThisUsedFromConstructorOrDestructor.testref @@ -0,0 +1 @@ +cpp/common/test/rules/objectsdynamictypeusedfromconstructorordestructor/ObjectsDynamicTypeUsedFromConstructorOrDestructor.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.qlref b/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.qlref deleted file mode 100644 index f0e2ebd711..0000000000 --- a/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.testref b/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.testref new file mode 100644 index 0000000000..ad5590bc1f --- /dev/null +++ b/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.testref @@ -0,0 +1 @@ +cpp/common/test/rules/namenotreferredusingaqualifiedidorthis/NameNotReferredUsingAQualifiedIdOrThis.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.qlref b/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.qlref deleted file mode 100644 index 442eb62675..0000000000 --- a/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.testref b/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.testref new file mode 100644 index 0000000000..f7ff9100a6 --- /dev/null +++ b/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.testref @@ -0,0 +1 @@ +cpp/common/test/rules/namenotreferredusingaqualifiedidorthisaudit/NameNotReferredUsingAQualifiedIdOrThisAudit.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M15-1-3/EmptyThrowOutsideCatch.qlref b/cpp/autosar/test/rules/M15-1-3/EmptyThrowOutsideCatch.qlref deleted file mode 100644 index 3643376e59..0000000000 --- a/cpp/autosar/test/rules/M15-1-3/EmptyThrowOutsideCatch.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M15-1-3/EmptyThrowOutsideCatch.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M15-1-3/EmptyThrowOutsideCatch.testref b/cpp/autosar/test/rules/M15-1-3/EmptyThrowOutsideCatch.testref new file mode 100644 index 0000000000..f3c961d8f1 --- /dev/null +++ b/cpp/autosar/test/rules/M15-1-3/EmptyThrowOutsideCatch.testref @@ -0,0 +1 @@ +cpp/common/test/rules/emptythrowonlywithinacatchhandler/EmptyThrowOnlyWithinACatchHandler.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M18-2-1/MacroOffsetofUsed.expected.gcc b/cpp/autosar/test/rules/M18-2-1/MacroOffsetofUsed.expected.gcc deleted file mode 100644 index f09fafd410..0000000000 --- a/cpp/autosar/test/rules/M18-2-1/MacroOffsetofUsed.expected.gcc +++ /dev/null @@ -1 +0,0 @@ -| test.cpp:9:32:9:51 | offsetof(__typ,__id) | Use of banned macro offsetof. | diff --git a/cpp/autosar/test/rules/M18-2-1/MacroOffsetofUsed.qlref b/cpp/autosar/test/rules/M18-2-1/MacroOffsetofUsed.qlref deleted file mode 100644 index a69e18549f..0000000000 --- a/cpp/autosar/test/rules/M18-2-1/MacroOffsetofUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M18-2-1/MacroOffsetofUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M18-2-1/MacroOffsetofUsed.testref b/cpp/autosar/test/rules/M18-2-1/MacroOffsetofUsed.testref new file mode 100644 index 0000000000..022fef6071 --- /dev/null +++ b/cpp/autosar/test/rules/M18-2-1/MacroOffsetofUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/macrooffsetofused/MacroOffsetofUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M18-7-1/CsignalFunctionsUsed.qlref b/cpp/autosar/test/rules/M18-7-1/CsignalFunctionsUsed.qlref deleted file mode 100644 index 445ccd5bd4..0000000000 --- a/cpp/autosar/test/rules/M18-7-1/CsignalFunctionsUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M18-7-1/CsignalFunctionsUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M18-7-1/CsignalFunctionsUsed.testref b/cpp/autosar/test/rules/M18-7-1/CsignalFunctionsUsed.testref new file mode 100644 index 0000000000..a09406a932 --- /dev/null +++ b/cpp/autosar/test/rules/M18-7-1/CsignalFunctionsUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/csignalfunctionsused/CsignalFunctionsUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M18-7-1/CsignalTypesUsed.qlref b/cpp/autosar/test/rules/M18-7-1/CsignalTypesUsed.qlref deleted file mode 100644 index 34c83d741a..0000000000 --- a/cpp/autosar/test/rules/M18-7-1/CsignalTypesUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M18-7-1/CsignalTypesUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M18-7-1/CsignalTypesUsed.testref b/cpp/autosar/test/rules/M18-7-1/CsignalTypesUsed.testref new file mode 100644 index 0000000000..3d398d799b --- /dev/null +++ b/cpp/autosar/test/rules/M18-7-1/CsignalTypesUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/csignaltypesused/CsignalTypesUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M2-13-2/UseOfNonZeroOctalEscape.expected b/cpp/autosar/test/rules/M2-13-2/UseOfNonZeroOctalEscape.expected index 17a0016fec..41ebcf7629 100644 --- a/cpp/autosar/test/rules/M2-13-2/UseOfNonZeroOctalEscape.expected +++ b/cpp/autosar/test/rules/M2-13-2/UseOfNonZeroOctalEscape.expected @@ -1,6 +1,6 @@ | test.cpp:3:3:3:8 | 10 | This literal contains the non-zero octal escape code \\012. | | test.cpp:4:3:4:8 | 44 | This literal contains the non-zero octal escape code \\054. | | test.cpp:5:3:5:9 | 3129 | This literal contains the non-zero octal escape code \\014. | -| test.cpp:10:3:10:8 | \n | This literal contains the non-zero octal escape code \\012. | -| test.cpp:11:3:11:8 | , | This literal contains the non-zero octal escape code \\054. | -| test.cpp:12:3:12:9 | \u000c9 | This literal contains the non-zero octal escape code \\014. | +| test.cpp:7:3:7:8 | \n | This literal contains the non-zero octal escape code \\012. | +| test.cpp:8:3:8:8 | , | This literal contains the non-zero octal escape code \\054. | +| test.cpp:9:3:9:9 | \u000c9 | This literal contains the non-zero octal escape code \\014. | diff --git a/cpp/autosar/test/rules/M2-13-2/UseOfNonZeroOctalLiteral.expected b/cpp/autosar/test/rules/M2-13-2/UseOfNonZeroOctalLiteral.expected deleted file mode 100644 index 8109c107a5..0000000000 --- a/cpp/autosar/test/rules/M2-13-2/UseOfNonZeroOctalLiteral.expected +++ /dev/null @@ -1,2 +0,0 @@ -| test.cpp:7:3:7:5 | 10 | Non zero octal literal 012. | -| test.cpp:8:3:8:5 | 44 | Non zero octal literal 054. | diff --git a/cpp/autosar/test/rules/M2-13-2/UseOfNonZeroOctalLiteral.qlref b/cpp/autosar/test/rules/M2-13-2/UseOfNonZeroOctalLiteral.qlref deleted file mode 100644 index 67900e54f7..0000000000 --- a/cpp/autosar/test/rules/M2-13-2/UseOfNonZeroOctalLiteral.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M2-13-2/UseOfNonZeroOctalLiteral.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M2-13-2/UseOfNonZeroOctalLiteral.testref b/cpp/autosar/test/rules/M2-13-2/UseOfNonZeroOctalLiteral.testref new file mode 100644 index 0000000000..97c466a866 --- /dev/null +++ b/cpp/autosar/test/rules/M2-13-2/UseOfNonZeroOctalLiteral.testref @@ -0,0 +1 @@ +cpp/common/test/rules/useofnonzerooctalliteral/UseOfNonZeroOctalLiteral.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M2-13-2/test.cpp b/cpp/autosar/test/rules/M2-13-2/test.cpp index a89809d68c..3c7fba30dd 100644 --- a/cpp/autosar/test/rules/M2-13-2/test.cpp +++ b/cpp/autosar/test/rules/M2-13-2/test.cpp @@ -3,9 +3,6 @@ void test_non_zero_octal() { '\012'; // NON_COMPLIANT '\054'; // NON_COMPLIANT '\0149'; // NON_COMPLIANT - 0; // COMPLIANT - octal literal zero permitted - 012; // NON_COMPLIANT - 054; // NON_COMPLIANT "\0"; // COMPLIANT - octal zero escape sequence permitted "\012"; // NON_COMPLIANT "\054"; // NON_COMPLIANT diff --git a/cpp/autosar/test/rules/M2-13-3/MissingUSuffix.expected b/cpp/autosar/test/rules/M2-13-3/MissingUSuffix.expected deleted file mode 100644 index 56dce901dd..0000000000 --- a/cpp/autosar/test/rules/M2-13-3/MissingUSuffix.expected +++ /dev/null @@ -1 +0,0 @@ -| test.cpp:3:3:3:12 | 4294967295 | Hex literal is an unsigned integer but does not include a 'U' suffix. | diff --git a/cpp/autosar/test/rules/M2-13-3/MissingUSuffix.qlref b/cpp/autosar/test/rules/M2-13-3/MissingUSuffix.qlref deleted file mode 100644 index ffb71066d5..0000000000 --- a/cpp/autosar/test/rules/M2-13-3/MissingUSuffix.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M2-13-3/MissingUSuffix.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M2-13-3/MissingUSuffix.testref b/cpp/autosar/test/rules/M2-13-3/MissingUSuffix.testref new file mode 100644 index 0000000000..9133a84ce4 --- /dev/null +++ b/cpp/autosar/test/rules/M2-13-3/MissingUSuffix.testref @@ -0,0 +1 @@ +cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M2-13-3/test.cpp b/cpp/autosar/test/rules/M2-13-3/test.cpp deleted file mode 100644 index e5b3abfa47..0000000000 --- a/cpp/autosar/test/rules/M2-13-3/test.cpp +++ /dev/null @@ -1,5 +0,0 @@ -void test_unsigned_literals_without_suffix() { - 0xFFFFFFFFU; // COMPLIANT - literal explicitly marked as unsigned - 0xFFFFFFFF; // NON_COMPLIANT - literal is too large for a signed int, so has - // type unsigned int -} \ No newline at end of file diff --git a/cpp/autosar/test/rules/M2-7-1/SlashStarUsedWithinACStyleComment.qlref b/cpp/autosar/test/rules/M2-7-1/SlashStarUsedWithinACStyleComment.qlref deleted file mode 100644 index 3f146ebeaf..0000000000 --- a/cpp/autosar/test/rules/M2-7-1/SlashStarUsedWithinACStyleComment.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M2-7-1/SlashStarUsedWithinACStyleComment.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M2-7-1/SlashStarUsedWithinACStyleComment.testref b/cpp/autosar/test/rules/M2-7-1/SlashStarUsedWithinACStyleComment.testref new file mode 100644 index 0000000000..971b1953f7 --- /dev/null +++ b/cpp/autosar/test/rules/M2-7-1/SlashStarUsedWithinACStyleComment.testref @@ -0,0 +1 @@ +cpp/common/test/rules/charactersequenceusedwithinacstylecomment/CharacterSequenceUsedWithinACStyleComment.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M27-0-1/CstdioFunctionsUsed.qlref b/cpp/autosar/test/rules/M27-0-1/CstdioFunctionsUsed.qlref deleted file mode 100644 index 7d97c146c9..0000000000 --- a/cpp/autosar/test/rules/M27-0-1/CstdioFunctionsUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M27-0-1/CstdioFunctionsUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M27-0-1/CstdioFunctionsUsed.testref b/cpp/autosar/test/rules/M27-0-1/CstdioFunctionsUsed.testref new file mode 100644 index 0000000000..5f8b3d8a9a --- /dev/null +++ b/cpp/autosar/test/rules/M27-0-1/CstdioFunctionsUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/cstdiofunctionsused/CstdioFunctionsUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M27-0-1/CstdioMacrosUsed.qlref b/cpp/autosar/test/rules/M27-0-1/CstdioMacrosUsed.qlref deleted file mode 100644 index 20bf876eba..0000000000 --- a/cpp/autosar/test/rules/M27-0-1/CstdioMacrosUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M27-0-1/CstdioMacrosUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M27-0-1/CstdioMacrosUsed.testref b/cpp/autosar/test/rules/M27-0-1/CstdioMacrosUsed.testref new file mode 100644 index 0000000000..a1ba376c3b --- /dev/null +++ b/cpp/autosar/test/rules/M27-0-1/CstdioMacrosUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/cstdiomacrosused/CstdioMacrosUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M27-0-1/CstdioTypesUsed.qlref b/cpp/autosar/test/rules/M27-0-1/CstdioTypesUsed.qlref deleted file mode 100644 index 10beab7eaa..0000000000 --- a/cpp/autosar/test/rules/M27-0-1/CstdioTypesUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M27-0-1/CstdioTypesUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M27-0-1/CstdioTypesUsed.testref b/cpp/autosar/test/rules/M27-0-1/CstdioTypesUsed.testref new file mode 100644 index 0000000000..4c08a75cfe --- /dev/null +++ b/cpp/autosar/test/rules/M27-0-1/CstdioTypesUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/cstdiotypesused/CstdioTypesUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.expected b/cpp/autosar/test/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.expected index 9aec2314da..d0fe6416ca 100644 --- a/cpp/autosar/test/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.expected +++ b/cpp/autosar/test/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.expected @@ -1,2 +1,5 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql:27,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql:36,10-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql:37,5-13) | test.cpp:5:3:5:20 | ... &= ... | Modification of bit-representation of float originated at $@ | test.cpp:4:24:4:60 | reinterpret_cast... | cast | | test.cpp:12:3:12:14 | ... &= ... | Modification of bit-representation of float originated at $@ | test.cpp:11:18:11:30 | (uint8_t *)... | cast | diff --git a/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected b/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected index 1be5b7b9fc..b23be388c6 100644 --- a/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected +++ b/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected @@ -1,4 +1,16 @@ -| test.cpp:4:22:4:24 | 99 | Assignment of an non-integer type to variable $@ which is a variable with an explicitly signed char type | test.cpp:4:17:4:18 | a1 | a1 | -| test.cpp:6:20:6:22 | 99 | Assignment of an non-integer type to variable $@ which is a variable with an explicitly signed char type | test.cpp:6:15:6:16 | a3 | a3 | -| test.cpp:9:20:9:22 | 99 | Assignment of an non-integer type to variable $@ which is a variable with an explicitly signed char type | test.cpp:9:15:9:16 | a5 | a5 | -| test.cpp:12:21:12:23 | 99 | Assignment of an non-integer type to variable $@ which is a variable with an explicitly signed char type | test.cpp:12:16:12:17 | a7 | a7 | +| test.cpp:58:7:58:8 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. | +| test.cpp:61:20:61:21 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. | +| test.cpp:71:21:71:22 | (uint8_t)... | This expression of plain char type is implicitly converted to 'unsigned char'. | +| test.cpp:74:20:74:21 | (int8_t)... | This expression of plain char type is implicitly converted to 'signed char'. | +| test.cpp:84:9:84:11 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. | +| test.cpp:87:9:87:11 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. | +| test.cpp:97:9:97:11 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. | +| test.cpp:100:9:100:11 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. | +| test.cpp:117:7:117:10 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. | +| test.cpp:122:7:122:10 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. | +| test.cpp:137:7:137:10 | (uint8_t)... | This expression of plain char type is implicitly converted to 'unsigned char'. | +| test.cpp:142:7:142:10 | (int8_t)... | This expression of plain char type is implicitly converted to 'signed char'. | +| test.cpp:153:6:153:7 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. | +| test.cpp:156:6:156:7 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. | +| test.cpp:166:6:166:7 | (uint8_t)... | This expression of plain char type is implicitly converted to 'unsigned char'. | +| test.cpp:169:7:169:8 | (int8_t)... | This expression of plain char type is implicitly converted to 'signed char'. | diff --git a/cpp/autosar/test/rules/M5-0-12/test.cpp b/cpp/autosar/test/rules/M5-0-12/test.cpp index 453c37bf1e..036db12b04 100644 --- a/cpp/autosar/test/rules/M5-0-12/test.cpp +++ b/cpp/autosar/test/rules/M5-0-12/test.cpp @@ -1,16 +1,170 @@ #include -void f1() { - unsigned char a1 = 'c'; // NON_COMPLIANT - unsigned char a2 = 10; - signed char a3 = 'c'; // NON_COMPLIANT - signed char a4 = 10; +class C1 { +public: + C1(unsigned char y) : x(y) {} - std::int8_t a5 = 'c'; // NON_COMPLIANT - std::int8_t a6 = 10; +private: + unsigned char x; +}; - std::uint8_t a7 = 'c'; // NON_COMPLIANT - std::uint8_t a8 = 10; +class C2 { +public: + C2(signed char y) : x(y) {} - char a9 = 'c'; -} \ No newline at end of file +private: + signed char x; +}; + +/* Twin classes for std::uint8_t and std::int8_t */ +class C5 { +public: + C5(unsigned char y) : x(y) {} + +private: + std::uint8_t x; +}; + +class C6 { +public: + C6(signed char y) : x(y) {} + +private: + std::int8_t x; +}; + +void f1(unsigned char x) {} +void f2(signed char x) {} + +/* Twin functions for std::uint8_t and std::int8_t */ +void f9(std::uint8_t x) {} +void f10(std::int8_t x) {} + +int main() { + + /* ========== 1. Assigning a char to another char ========== */ + + /* ===== 1-1. Assigning a char to a char variable ===== */ + + unsigned char x1 = 1; + unsigned char y1 = + x1; // COMPLIANT: unsigned char assigned to an unsigned char + + signed char x2 = 1; + signed char y2 = x2; // COMPLIANT: signed char assigned to a signed char + + char x3 = 'x'; + unsigned char y3 = + x3; // NON-COMPLIANT: plain char assigned to a unsigned char + + char x4 = 'x'; + signed char y4 = x4; // NON-COMPLIANT: plain char assigned to a signed char + + /* Twin cases with std::uint8_t and std::int8_t */ + std::uint8_t x5 = 1; + std::uint8_t y5 = x5; // COMPLIANT: std::uint8_t assigned to a std::uint8_t + + std::int8_t x6 = 1; + std::int8_t y6 = x6; // COMPLIANT: std::int8_t assigned to a std::int8_t + + char x7 = 'x'; + std::uint8_t y7 = x7; // NON-COMPLIANT: plain char assigned to a std::uint8_t + + char x8 = 'x'; + std::int8_t y8 = x8; // NON-COMPLIANT: plain char assigned to a std::int8_t + + /* ===== 1-2. Assigning a char to a char member ===== */ + + C1 c1(1); // COMPLIANT: unsigned char arg passed to an unsigned + // char member + + C2 c2(1); // COMPLIANT: signed char arg passed to a signed char + // member + + C1 c3('x'); // NON-COMPLIANT: plain char arg passed to an unsigned char + // member + + C2 c4('x'); // NON-COMPLIANT: plain char arg passed to a signed char + // member + + /* Twin cases with std::uint8_t and std::int8_t */ + C5 c5(1); // COMPLIANT: std::uint8_t arg passed to a + // std::uint8_t member + + C6 c6(1); // COMPLIANT: std::int8_t arg passed to a std::int8_t + // member + + C5 c7('x'); // NON-COMPLIANT: plain char arg passed to a + // std::uint8_t member + + C6 c8('x'); // NON-COMPLIANT: plain char arg passed to a std::int8_t + // member + + /* ========== 1-3. Assigning a char to a char through a pointer ========== */ + + unsigned char x9 = 1; + unsigned char *y9 = &x9; + unsigned char z1 = + *y9; // COMPLIANT: unsigned char assigned to an *&unsigned char + + signed char x10 = 1; + signed char *y10 = &x10; + signed char z2 = *y10; // COMPLIANT: signed char assigned to an *&signed char + + char x11 = 1; + char *y11 = &x11; + unsigned char z3 = + *y11; // NON-COMPLIANT: plain char assigned to an *&unsigned char + + char x12 = 1; + char *y12 = &x12; + signed char z4 = + *y12; // NON-COMPLIANT: plain char assigned to an *&signed char + + /* Twin cases with std::uint8_t and std::int8_t */ + std::uint8_t x13 = 1; + std::uint8_t *y13 = &x13; + std::uint8_t z5 = + *y13; // COMPLIANT: std::uint8_t assigned to a *&std::uint8_t + + std::int8_t x14 = 1; + std::int8_t *y14 = &x14; + std::int8_t z6 = *y14; // COMPLIANT: std::int8_t assigned to an *&std::int8_t + + char x15 = 1; + char *y15 = &x15; + std::uint8_t z7 = + *y15; // NON-COMPLIANT: plain char assigned to an *&std::uint8_t + + char x16 = 1; + char *y16 = &x16; + std::int8_t z8 = + *y16; // NON-COMPLIANT: plain char assigned to an *&std::int8_t + + /* ========== 2. Passing a char argument to a char parameter ========== */ + + unsigned char a1 = 1; + f1(a1); // COMPLIANT: unsigned char arg passed to an unsigned char parameter + + signed char a2 = 1; + f2(a2); // COMPLIANT: signed char arg passed to a signed char parameter + + char a3 = 'a'; + f1(a3); // NON-COMPLIANT: plain char arg passed to an unsigned char parameter + + char a4 = 'a'; + f2(a4); // NON-COMPLIANT: plain char arg passed to a signed char parameter + + /* Twin cases with std::uint8_t and std::int8_t */ + std::uint8_t a5 = 1; + f9(a5); // COMPLIANT: std::uint8_t arg passed to a std::uint8_t parameter + + std::int8_t a6 = 1; + f10(a6); // COMPLIANT: std::int8_t arg passed to a std::int8_t parameter + + char a7 = 'a'; + f9(a7); // NON-COMPLIANT: plain char arg passed to a std::uint8_t parameter + + char a8 = 'a'; + f10(a8); // NON-COMPLIANT: plain char arg passed to a std::int8_t parameter +} diff --git a/cpp/autosar/test/rules/M5-0-3/CvalueExpressionConvertedToDifferentUnderlyingType.expected b/cpp/autosar/test/rules/M5-0-3/CvalueExpressionConvertedToDifferentUnderlyingType.expected index 5782ac9849..8ce6a225dc 100644 --- a/cpp/autosar/test/rules/M5-0-3/CvalueExpressionConvertedToDifferentUnderlyingType.expected +++ b/cpp/autosar/test/rules/M5-0-3/CvalueExpressionConvertedToDifferentUnderlyingType.expected @@ -1,3 +1,7 @@ -| test.cpp:11:8:11:14 | (int16_t)... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:11:8:11:14 | ... + ... | expression | -| test.cpp:11:8:11:14 | ... + ... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:11:8:11:14 | ... + ... | expression | -| test.cpp:13:8:13:13 | ... + ... | Implicit conversion converts cvalue $@ from signed short to signed int. | test.cpp:13:8:13:13 | ... + ... | expression | +| test.cpp:12:8:12:14 | (int16_t)... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:12:8:12:14 | ... + ... | expression | +| test.cpp:12:8:12:14 | ... + ... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:12:8:12:14 | ... + ... | expression | +| test.cpp:14:8:14:13 | ... + ... | Implicit conversion converts cvalue $@ from signed short to signed int. | test.cpp:14:8:14:13 | ... + ... | expression | +| test.cpp:23:13:23:19 | (int16_t)... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:23:13:23:19 | ... + ... | expression | +| test.cpp:25:13:25:45 | (int16_t)... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:25:13:25:45 | static_cast... | expression | +| test.cpp:31:12:31:18 | (int16_t)... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:31:12:31:18 | ... + ... | expression | +| test.cpp:33:12:33:44 | (int16_t)... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:33:12:33:44 | static_cast... | expression | diff --git a/cpp/autosar/test/rules/M5-0-3/test.cpp b/cpp/autosar/test/rules/M5-0-3/test.cpp index cb74512979..7275204519 100644 --- a/cpp/autosar/test/rules/M5-0-3/test.cpp +++ b/cpp/autosar/test/rules/M5-0-3/test.cpp @@ -1,4 +1,5 @@ #include + void f1() { using std::int16_t; using std::int32_t; @@ -13,4 +14,24 @@ void f1() { l3 = l2 + 1; // NON_COMPLIANT l3 = static_cast(l2) + 1; // COMPLIANT l3 = l2 + 0x01ffff; // COMPLIANT +} + +void int16_arg(std::int16_t t); + +void test_func_call() { + std::int8_t l1; + int16_arg(l1 + l1); // NON_COMPLIANT + int16_arg(static_cast(l1 + l1)); // COMPLIANT + int16_arg(static_cast(l1 + l1)); // NON_COMPLIANT +} + +std::int16_t test_return(int test) { + std::int8_t l1; + if (test > 0) { + return l1 + l1; // NON_COMPLIANT + } else if (test < 0) { + return static_cast(l1 + l1); // NON_COMPLIANT + } else { + return static_cast(l1 + l1); // COMPLIANT + } } \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-0-7/test.cpp b/cpp/autosar/test/rules/M5-0-7/test.cpp index 36a2259028..ecbddd6750 100644 --- a/cpp/autosar/test/rules/M5-0-7/test.cpp +++ b/cpp/autosar/test/rules/M5-0-7/test.cpp @@ -18,4 +18,13 @@ void f1() { s16a = static_cast(f32a / f32b); // NON_COMPLIANT s16a = static_cast(f32a); // COMPLIANT s16a = static_cast(f32a) / f32b; // COMPLIANT +} + +void int_arg(std::int32_t i); + +std::int16_t test_args() { + float f32a; + float f32b; + int_arg(static_cast(f32a)); // COMPLIANT - f32a is not a cvalue + return static_cast(f32a); // COMPLIANT - f32a is not a cvalue } \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-0-8/test.cpp b/cpp/autosar/test/rules/M5-0-8/test.cpp index 198bebed9f..ab785c661a 100644 --- a/cpp/autosar/test/rules/M5-0-8/test.cpp +++ b/cpp/autosar/test/rules/M5-0-8/test.cpp @@ -22,4 +22,22 @@ void f() { f64 = static_cast(1.0f + 1.0f); // NON_COMPLIANT f32 = static_cast(1.0f + 1); // COMPLIANT f64 = static_cast(1.0 + 1); // COMPLIANT; no suffix defines a double +} + +#include + +void function_args() { + std::vector v{0}; + + std::uint32_t u32{0}; + v.at(static_cast(u32)); // COMPLIANT - cast is not a cvalue + std::size_t st = + static_cast(u32); // COMPLIANT - cast is not a cvalue + v.at(st); +} + +std::size_t return_args() { + std::uint32_t u32{0}; + + return static_cast(u32); // COMPLIANT } \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-0-9/ExplicitSignednessConversionOfCValue.expected b/cpp/autosar/test/rules/M5-0-9/ExplicitSignednessConversionOfCValue.expected index b2619503b3..b7fc97f99c 100644 --- a/cpp/autosar/test/rules/M5-0-9/ExplicitSignednessConversionOfCValue.expected +++ b/cpp/autosar/test/rules/M5-0-9/ExplicitSignednessConversionOfCValue.expected @@ -1,3 +1,3 @@ -| test.cpp:16:8:16:35 | static_cast... | Explicit integral conversion converts the signedness of the $@ from unsigned to signed. | test.cpp:16:28:16:34 | ... + ... | cvalue | -| test.cpp:18:8:18:40 | static_cast... | Explicit integral conversion converts the signedness of the $@ from unsigned to signed. | test.cpp:18:28:18:39 | ... + ... | cvalue | -| test.cpp:20:8:20:35 | static_cast... | Explicit integral conversion converts the signedness of the $@ from unsigned to signed. | test.cpp:20:28:20:34 | ... * ... | cvalue | +| test.cpp:20:8:20:35 | static_cast... | Explicit integral conversion converts the signedness of the $@ from unsigned to signed. | test.cpp:20:28:20:34 | ... + ... | cvalue | +| test.cpp:22:8:22:40 | static_cast... | Explicit integral conversion converts the signedness of the $@ from unsigned to signed. | test.cpp:22:28:22:39 | ... + ... | cvalue | +| test.cpp:24:8:24:35 | static_cast... | Explicit integral conversion converts the signedness of the $@ from unsigned to signed. | test.cpp:24:28:24:34 | ... * ... | cvalue | diff --git a/cpp/autosar/test/rules/M5-0-9/test.cpp b/cpp/autosar/test/rules/M5-0-9/test.cpp index b46dbc390f..7b050d24de 100644 --- a/cpp/autosar/test/rules/M5-0-9/test.cpp +++ b/cpp/autosar/test/rules/M5-0-9/test.cpp @@ -1,4 +1,8 @@ #include + +void signed_arg(std::uint32_t s); +void unsigned_arg(std::uint32_t u); + void f() { using std::int16_t; using std::int32_t; @@ -22,4 +26,7 @@ void f() { i16 = static_cast(i16 / i8); // NON_COMPLIANT i8 = static_cast(u8) + static_cast(u8); // COMPLIANT + + unsigned(static_cast(i32)); // COMPLIANT - i32 is not a cvalue + signed(static_cast(u32)); // COMPLIANT - u32 is not a cvalue } \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-2-12/IdentifierWithArrayTypePassedAsFunctionArgumentDecayToAPointer.qlref b/cpp/autosar/test/rules/M5-2-12/IdentifierWithArrayTypePassedAsFunctionArgumentDecayToAPointer.qlref deleted file mode 100644 index 3a513b4cbe..0000000000 --- a/cpp/autosar/test/rules/M5-2-12/IdentifierWithArrayTypePassedAsFunctionArgumentDecayToAPointer.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M5-2-12/IdentifierWithArrayTypePassedAsFunctionArgumentDecayToAPointer.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-2-12/IdentifierWithArrayTypePassedAsFunctionArgumentDecayToAPointer.testref b/cpp/autosar/test/rules/M5-2-12/IdentifierWithArrayTypePassedAsFunctionArgumentDecayToAPointer.testref new file mode 100644 index 0000000000..06f2ec8fbb --- /dev/null +++ b/cpp/autosar/test/rules/M5-2-12/IdentifierWithArrayTypePassedAsFunctionArgumentDecayToAPointer.testref @@ -0,0 +1 @@ +cpp/common/test/rules/arraypassedasfunctionargumentdecaytoapointer/ArrayPassedAsFunctionArgumentDecayToAPointer.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.qlref b/cpp/autosar/test/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.qlref deleted file mode 100644 index c48e9498cc..0000000000 --- a/cpp/autosar/test/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-2-2/test.cpp b/cpp/autosar/test/rules/M5-2-2/test.cpp deleted file mode 100644 index 59c0cb4b37..0000000000 --- a/cpp/autosar/test/rules/M5-2-2/test.cpp +++ /dev/null @@ -1,18 +0,0 @@ -class C1 { -public: - virtual ~C1() {} -}; -class C2 : public virtual C1 { -public: - C2() {} - ~C2() {} -}; - -void f1() { - C2 l1; - C1 *p1 = &l1; - - // C2 *p2 = static_cast(p1); // NON_COMPLIANT, prohibited by compiler - C2 *p3 = dynamic_cast(p1); // COMPLIANT - C2 &l2 = dynamic_cast(*p1); // COMPLIANT -} diff --git a/cpp/autosar/test/rules/M5-2-6/CastNotConvertPointerToFunction.expected b/cpp/autosar/test/rules/M5-2-6/CastNotConvertPointerToFunction.expected deleted file mode 100644 index 63c33f26d7..0000000000 --- a/cpp/autosar/test/rules/M5-2-6/CastNotConvertPointerToFunction.expected +++ /dev/null @@ -1,2 +0,0 @@ -| test.cpp:2:3:2:34 | reinterpret_cast<..(*)(..)>... | Cast converting a pointer to function. | -| test.cpp:3:3:3:30 | reinterpret_cast... | Cast converting a pointer to function. | diff --git a/cpp/autosar/test/rules/M5-2-6/CastNotConvertPointerToFunction.qlref b/cpp/autosar/test/rules/M5-2-6/CastNotConvertPointerToFunction.qlref deleted file mode 100644 index 7f4d4c1161..0000000000 --- a/cpp/autosar/test/rules/M5-2-6/CastNotConvertPointerToFunction.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M5-2-6/CastNotConvertPointerToFunction.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-2-6/CastNotConvertPointerToFunction.testref b/cpp/autosar/test/rules/M5-2-6/CastNotConvertPointerToFunction.testref new file mode 100644 index 0000000000..e7bde2ea08 --- /dev/null +++ b/cpp/autosar/test/rules/M5-2-6/CastNotConvertPointerToFunction.testref @@ -0,0 +1 @@ +cpp/common/test/rules/castsbetweenapointertofunctionandanyothertype/CastsBetweenAPointerToFunctionAndAnyOtherType.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-2-6/test.cpp b/cpp/autosar/test/rules/M5-2-6/test.cpp deleted file mode 100644 index ac14351b00..0000000000 --- a/cpp/autosar/test/rules/M5-2-6/test.cpp +++ /dev/null @@ -1,4 +0,0 @@ -void f(int) { - reinterpret_cast(&f); // NON_COMPLIANT - reinterpret_cast(&f); // NON_COMPLIANT -} \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-3-1/test.cpp b/cpp/autosar/test/rules/M5-3-1/test.cpp index 9098e4e40e..4bda4c6682 100644 --- a/cpp/autosar/test/rules/M5-3-1/test.cpp +++ b/cpp/autosar/test/rules/M5-3-1/test.cpp @@ -25,4 +25,13 @@ template class A { void f() { A a; a.test1(); -} \ No newline at end of file +} + +template constexpr bool some_variable_template_v = false; +template <> constexpr bool some_variable_template_v = true; + +template +void template_with_no_except() noexcept(some_variable_template_v && + true) { // COMPLIANT +} +void test_template() { template_with_no_except(); } \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-3-2/UnaryMinusOperatorAppliedToAnExpressionWhoseUnderlyingTypeIsUnsigned.qlref b/cpp/autosar/test/rules/M5-3-2/UnaryMinusOperatorAppliedToAnExpressionWhoseUnderlyingTypeIsUnsigned.qlref deleted file mode 100644 index 37d8a72ce5..0000000000 --- a/cpp/autosar/test/rules/M5-3-2/UnaryMinusOperatorAppliedToAnExpressionWhoseUnderlyingTypeIsUnsigned.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M5-3-2/UnaryMinusOperatorAppliedToAnExpressionWhoseUnderlyingTypeIsUnsigned.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-3-2/UnaryMinusOperatorAppliedToAnExpressionWhoseUnderlyingTypeIsUnsigned.testref b/cpp/autosar/test/rules/M5-3-2/UnaryMinusOperatorAppliedToAnExpressionWhoseUnderlyingTypeIsUnsigned.testref new file mode 100644 index 0000000000..bd12c39fbd --- /dev/null +++ b/cpp/autosar/test/rules/M5-3-2/UnaryMinusOperatorAppliedToAnExpressionWhoseUnderlyingTypeIsUnsigned.testref @@ -0,0 +1 @@ +cpp/common/test/rules/builtinunaryoperatorappliedtounsignedexpression/BuiltInUnaryOperatorAppliedToUnsignedExpression.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-3-3/UnaryOperatorOverloaded.qlref b/cpp/autosar/test/rules/M5-3-3/UnaryOperatorOverloaded.qlref deleted file mode 100644 index 9e6cb1d0f8..0000000000 --- a/cpp/autosar/test/rules/M5-3-3/UnaryOperatorOverloaded.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M5-3-3/UnaryOperatorOverloaded.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-3-3/UnaryOperatorOverloaded.testref b/cpp/autosar/test/rules/M5-3-3/UnaryOperatorOverloaded.testref new file mode 100644 index 0000000000..1f2a126671 --- /dev/null +++ b/cpp/autosar/test/rules/M5-3-3/UnaryOperatorOverloaded.testref @@ -0,0 +1 @@ +cpp/common/test/rules/addressofoperatoroverloaded/AddressOfOperatorOverloaded.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M6-3-1/LoopCompoundCondition.qlref b/cpp/autosar/test/rules/M6-3-1/LoopCompoundCondition.qlref deleted file mode 100644 index 4ee6239a13..0000000000 --- a/cpp/autosar/test/rules/M6-3-1/LoopCompoundCondition.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M6-3-1/LoopCompoundCondition.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M6-3-1/LoopCompoundCondition.testref b/cpp/autosar/test/rules/M6-3-1/LoopCompoundCondition.testref new file mode 100644 index 0000000000..84dc7caf76 --- /dev/null +++ b/cpp/autosar/test/rules/M6-3-1/LoopCompoundCondition.testref @@ -0,0 +1 @@ +cpp/common/test/rules/loopcompoundcondition/LoopCompoundCondition.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M6-3-1/SwitchCompoundCondition.qlref b/cpp/autosar/test/rules/M6-3-1/SwitchCompoundCondition.qlref deleted file mode 100644 index eff312aa30..0000000000 --- a/cpp/autosar/test/rules/M6-3-1/SwitchCompoundCondition.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M6-3-1/SwitchCompoundCondition.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M6-3-1/SwitchCompoundCondition.testref b/cpp/autosar/test/rules/M6-3-1/SwitchCompoundCondition.testref new file mode 100644 index 0000000000..f02b02ba85 --- /dev/null +++ b/cpp/autosar/test/rules/M6-3-1/SwitchCompoundCondition.testref @@ -0,0 +1 @@ +cpp/common/test/rules/switchcompoundcondition/SwitchCompoundCondition.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M6-5-3/LoopCounterModifiedWithinStatement.expected b/cpp/autosar/test/rules/M6-5-3/LoopCounterModifiedWithinStatement.expected index a6988586f0..4643298e3a 100644 --- a/cpp/autosar/test/rules/M6-5-3/LoopCounterModifiedWithinStatement.expected +++ b/cpp/autosar/test/rules/M6-5-3/LoopCounterModifiedWithinStatement.expected @@ -2,3 +2,4 @@ | test.cpp:25:35:25:35 | x | Loop counters should not be modified within a statement in a for loop. | | test.cpp:36:5:36:5 | x | Loop counters should not be modified within a statement in a for loop. | | test.cpp:43:9:43:9 | i | Loop counters should not be modified within a statement in a for loop. | +| test.cpp:93:15:93:15 | i | Loop counters should not be modified within a statement in a for loop. | diff --git a/cpp/autosar/test/rules/M6-5-3/test.cpp b/cpp/autosar/test/rules/M6-5-3/test.cpp index a534e6ba8e..a41ba8a22d 100644 --- a/cpp/autosar/test/rules/M6-5-3/test.cpp +++ b/cpp/autosar/test/rules/M6-5-3/test.cpp @@ -43,3 +43,54 @@ void test_loop_counter_mod_in_side_effect() { inc(i); // NON_COMPLIANT - modifies `i` } } + +void test_loop_counter_reference_mod_in_condition() { + auto loop = [](int &i) { + for (; (i++ < 10); i++) { // NON_COMPLIANT + } + }; + int i = 0; + loop(i); +} + +void test_loop_counter_reference_mod() { + auto loop = [](int &i) { + for (; i < 10; i++) { // COMPLIANT + } + }; + int i = 0; + loop(i); +} + +void test_loop_const_reference() { + auto loop = []([[maybe_unused]] int const &i) { + for (int i = 0; i < 10; i++) { // COMPLIANT + } + }; + int i = 0; + loop(i); +} + +void test_loop_counter_reference_mod_in_statement() { + auto loop = [](int &i) { + for (; (i < 10); i++) { + i++; // NON_COMPLIANT + } + }; + int i = 0; + loop(i); +} + +int const_reference(int const &i) { return i; } + +int reference(int &i) { return i; } + +int copy(int i) { return i; } + +void test_pass_argument_by() { + for (int i = 0; i < 10; i++) { + const_reference(i); // COMPLIANT + reference(i); // NON_COMPLIANT + copy(i); // COMPLIANT + } +} diff --git a/cpp/autosar/test/rules/M7-3-1/GlobalNamespaceMembershipViolation.qlref b/cpp/autosar/test/rules/M7-3-1/GlobalNamespaceMembershipViolation.qlref deleted file mode 100644 index f2ec336eec..0000000000 --- a/cpp/autosar/test/rules/M7-3-1/GlobalNamespaceMembershipViolation.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M7-3-1/GlobalNamespaceMembershipViolation.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M7-3-1/GlobalNamespaceMembershipViolation.testref b/cpp/autosar/test/rules/M7-3-1/GlobalNamespaceMembershipViolation.testref new file mode 100644 index 0000000000..8f71738005 --- /dev/null +++ b/cpp/autosar/test/rules/M7-3-1/GlobalNamespaceMembershipViolation.testref @@ -0,0 +1 @@ +cpp/common/test/rules/globalnamespacedeclarations/GlobalNamespaceDeclarations.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M7-3-2/IdentifierMainUsedForAFunctionOtherThanTheGlobalFunctionMain.qlref b/cpp/autosar/test/rules/M7-3-2/IdentifierMainUsedForAFunctionOtherThanTheGlobalFunctionMain.qlref deleted file mode 100644 index 36bc86bb79..0000000000 --- a/cpp/autosar/test/rules/M7-3-2/IdentifierMainUsedForAFunctionOtherThanTheGlobalFunctionMain.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M7-3-2/IdentifierMainUsedForAFunctionOtherThanTheGlobalFunctionMain.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M7-3-2/IdentifierMainUsedForAFunctionOtherThanTheGlobalFunctionMain.testref b/cpp/autosar/test/rules/M7-3-2/IdentifierMainUsedForAFunctionOtherThanTheGlobalFunctionMain.testref new file mode 100644 index 0000000000..e149f3a33b --- /dev/null +++ b/cpp/autosar/test/rules/M7-3-2/IdentifierMainUsedForAFunctionOtherThanTheGlobalFunctionMain.testref @@ -0,0 +1 @@ +cpp/common/test/rules/nonglobalfunctionmain/NonGlobalFunctionMain.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M7-5-1/FunctionReturnAutomaticVarCondition.qlref b/cpp/autosar/test/rules/M7-5-1/FunctionReturnAutomaticVarCondition.qlref deleted file mode 100644 index 4cb410e095..0000000000 --- a/cpp/autosar/test/rules/M7-5-1/FunctionReturnAutomaticVarCondition.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M7-5-1/FunctionReturnAutomaticVarCondition.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M7-5-1/FunctionReturnAutomaticVarCondition.testref b/cpp/autosar/test/rules/M7-5-1/FunctionReturnAutomaticVarCondition.testref new file mode 100644 index 0000000000..45dbffde00 --- /dev/null +++ b/cpp/autosar/test/rules/M7-5-1/FunctionReturnAutomaticVarCondition.testref @@ -0,0 +1 @@ +cpp/common/test/rules/returnreferenceorpointertoautomaticlocalvariable/ReturnReferenceOrPointerToAutomaticLocalVariable.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M7-5-1/test.cpp b/cpp/autosar/test/rules/M7-5-1/test.cpp deleted file mode 100644 index bc4fbf8f1d..0000000000 --- a/cpp/autosar/test/rules/M7-5-1/test.cpp +++ /dev/null @@ -1,35 +0,0 @@ -int *test_ptr_return_f2() { - int x = 100; - return &x; // NON_COMPLIANT -} - -int *test_ptr_return_f3(int y) { return &y; } // NON_COMPLIANT - -int &test_ref_return_f2() { - int x = 100; - return x; // NON_COMPLIANT -} - -int &test_ref_return_f3(int y) { return y; } // NON_COMPLIANT - -int *test_ptr_return_f4() { - static int x = 1; - return &x; // COMPLIANT -} - -int test_return_f2() { - int x = 100; - return x; // COMPLIANT -} -template void t1(T &x, T &y) { - if (x > y) - x = y; // NON_COMPLIANT[FALSE NEGATIVE] - else - x = -y; // NON_COMPLIANT[FALSE NEGATIVE] -} - -void test_templatefunction_return() { - int j = 2; - int k = 3; - t1(j, k); -} \ No newline at end of file diff --git a/cpp/autosar/test/rules/M8-0-1/MultipleGlobalOrMemberDeclarators.qlref b/cpp/autosar/test/rules/M8-0-1/MultipleGlobalOrMemberDeclarators.qlref deleted file mode 100644 index 2703512673..0000000000 --- a/cpp/autosar/test/rules/M8-0-1/MultipleGlobalOrMemberDeclarators.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M8-0-1/MultipleGlobalOrMemberDeclarators.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M8-0-1/MultipleGlobalOrMemberDeclarators.testref b/cpp/autosar/test/rules/M8-0-1/MultipleGlobalOrMemberDeclarators.testref new file mode 100644 index 0000000000..434cb47456 --- /dev/null +++ b/cpp/autosar/test/rules/M8-0-1/MultipleGlobalOrMemberDeclarators.testref @@ -0,0 +1 @@ +cpp/common/test/rules/multipleglobalormemberdeclarators/MultipleGlobalOrMemberDeclarators.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M8-0-1/MultipleLocalDeclarators.qlref b/cpp/autosar/test/rules/M8-0-1/MultipleLocalDeclarators.qlref deleted file mode 100644 index 2375201bf3..0000000000 --- a/cpp/autosar/test/rules/M8-0-1/MultipleLocalDeclarators.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M8-0-1/MultipleLocalDeclarators.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M8-0-1/MultipleLocalDeclarators.testref b/cpp/autosar/test/rules/M8-0-1/MultipleLocalDeclarators.testref new file mode 100644 index 0000000000..be7c9ac352 --- /dev/null +++ b/cpp/autosar/test/rules/M8-0-1/MultipleLocalDeclarators.testref @@ -0,0 +1 @@ +cpp/common/test/rules/multiplelocaldeclarators/MultipleLocalDeclarators.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M8-3-1/VirtualFunctionParametersUseTheSameDefaultArguments.expected b/cpp/autosar/test/rules/M8-3-1/VirtualFunctionParametersUseTheSameDefaultArguments.expected deleted file mode 100644 index b5cdd76a2b..0000000000 --- a/cpp/autosar/test/rules/M8-3-1/VirtualFunctionParametersUseTheSameDefaultArguments.expected +++ /dev/null @@ -1,2 +0,0 @@ -| test.cpp:16:8:16:8 | f | $@ does not have the same default parameters as $@ | test.cpp:16:8:16:8 | f | overriding function | test.cpp:4:16:4:16 | f | overridden function | -| test.cpp:21:8:21:8 | f | $@ does not have the same default parameters as $@ | test.cpp:21:8:21:8 | f | overriding function | test.cpp:4:16:4:16 | f | overridden function | diff --git a/cpp/autosar/test/rules/M8-3-1/VirtualFunctionParametersUseTheSameDefaultArguments.qlref b/cpp/autosar/test/rules/M8-3-1/VirtualFunctionParametersUseTheSameDefaultArguments.qlref deleted file mode 100644 index ae0c1df157..0000000000 --- a/cpp/autosar/test/rules/M8-3-1/VirtualFunctionParametersUseTheSameDefaultArguments.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M8-3-1/VirtualFunctionParametersUseTheSameDefaultArguments.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M8-3-1/VirtualFunctionParametersUseTheSameDefaultArguments.testref b/cpp/autosar/test/rules/M8-3-1/VirtualFunctionParametersUseTheSameDefaultArguments.testref new file mode 100644 index 0000000000..7e06403515 --- /dev/null +++ b/cpp/autosar/test/rules/M8-3-1/VirtualFunctionParametersUseTheSameDefaultArguments.testref @@ -0,0 +1 @@ +cpp/common/test/rules/overridingshallspecifydifferentdefaultarguments/OverridingShallSpecifyDifferentDefaultArguments.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.expected b/cpp/autosar/test/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.expected index ee9652f505..af7e9efc36 100644 --- a/cpp/autosar/test/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.expected +++ b/cpp/autosar/test/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.expected @@ -1,3 +1,5 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstMemberFunctionReturnsNonConstPointer.ql:53,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstMemberFunctionReturnsNonConstPointer.ql:55,7-15) | test.cpp:8:8:8:11 | getA | Const member function returns a pointer to class data $@. | test.cpp:3:8:3:8 | a | a | | test.cpp:9:8:9:11 | getB | Const member function returns a pointer to class data $@. | test.cpp:4:8:4:8 | b | b | | test.cpp:11:6:11:12 | getThis | Const member function returns a pointer to class data $@. | test.cpp:11:36:11:39 | this | this | diff --git a/cpp/autosar/test/rules/M9-6-4/NamedBitFieldsWithSignedIntegerTypeShallHaveALengthOfMoreThanOneBit.expected b/cpp/autosar/test/rules/M9-6-4/NamedBitFieldsWithSignedIntegerTypeShallHaveALengthOfMoreThanOneBit.expected deleted file mode 100644 index 26b9aac563..0000000000 --- a/cpp/autosar/test/rules/M9-6-4/NamedBitFieldsWithSignedIntegerTypeShallHaveALengthOfMoreThanOneBit.expected +++ /dev/null @@ -1 +0,0 @@ -| test.cpp:2:14:2:14 | x | A named bit-field with signed integral type should have at least 2 bits of storage | diff --git a/cpp/autosar/test/rules/M9-6-4/NamedBitFieldsWithSignedIntegerTypeShallHaveALengthOfMoreThanOneBit.qlref b/cpp/autosar/test/rules/M9-6-4/NamedBitFieldsWithSignedIntegerTypeShallHaveALengthOfMoreThanOneBit.qlref deleted file mode 100644 index cdb9677f5f..0000000000 --- a/cpp/autosar/test/rules/M9-6-4/NamedBitFieldsWithSignedIntegerTypeShallHaveALengthOfMoreThanOneBit.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M9-6-4/NamedBitFieldsWithSignedIntegerTypeShallHaveALengthOfMoreThanOneBit.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M9-6-4/NamedBitFieldsWithSignedIntegerTypeShallHaveALengthOfMoreThanOneBit.testref b/cpp/autosar/test/rules/M9-6-4/NamedBitFieldsWithSignedIntegerTypeShallHaveALengthOfMoreThanOneBit.testref new file mode 100644 index 0000000000..5dd7991a37 --- /dev/null +++ b/cpp/autosar/test/rules/M9-6-4/NamedBitFieldsWithSignedIntegerTypeShallHaveALengthOfMoreThanOneBit.testref @@ -0,0 +1 @@ +cpp/common/test/rules/namedbitfieldswithsignedintegertype/NamedBitFieldsWithSignedIntegerType.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M9-6-4/test.cpp b/cpp/autosar/test/rules/M9-6-4/test.cpp deleted file mode 100644 index d3939b71ee..0000000000 --- a/cpp/autosar/test/rules/M9-6-4/test.cpp +++ /dev/null @@ -1,8 +0,0 @@ -struct S { - signed int x : 1; // NON-COMPLIANT - signed int y : 5; // COMPLIANT - signed int z : 7; // COMPLIANT - signed int : 0; // COMPLIANT - signed int : 1; // COMPLIANT - signed int : 2; // COMPLIANT -}; \ No newline at end of file diff --git a/cpp/cert/src/codeql-pack.lock.yml b/cpp/cert/src/codeql-pack.lock.yml index 514e6963d0..a45ea8f438 100644 --- a/cpp/cert/src/codeql-pack.lock.yml +++ b/cpp/cert/src/codeql-pack.lock.yml @@ -2,13 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.9.3 + version: 4.0.3 codeql/dataflow: - version: 0.0.4 + version: 2.0.3 + codeql/mad: + version: 1.0.19 + codeql/rangeanalysis: + version: 1.0.19 codeql/ssa: - version: 0.1.5 + version: 1.0.19 codeql/tutorial: - version: 0.1.5 + version: 1.0.19 + codeql/typeflow: + version: 1.0.19 + codeql/typetracking: + version: 2.0.3 codeql/util: - version: 0.1.5 + version: 2.0.6 + codeql/xml: + version: 1.0.19 compiled: false diff --git a/cpp/cert/src/codeql-suites/cert-cpp-default.qls b/cpp/cert/src/codeql-suites/cert-cpp-default.qls new file mode 100644 index 0000000000..e9211246b1 --- /dev/null +++ b/cpp/cert/src/codeql-suites/cert-cpp-default.qls @@ -0,0 +1,9 @@ +- description: CERT C++ 2016 (Default) +- qlpack: codeql/cert-cpp-coding-standards +- include: + kind: + - problem + - path-problem +- exclude: + tags contain: + - external/cert/default-disabled diff --git a/cpp/cert/src/codeql-suites/cert-cpp-l1.qls b/cpp/cert/src/codeql-suites/cert-cpp-l1.qls new file mode 100644 index 0000000000..d96def2456 --- /dev/null +++ b/cpp/cert/src/codeql-suites/cert-cpp-l1.qls @@ -0,0 +1,12 @@ +- description: CERT C++ 2016 Level 1 Rules (Priority 12 - Priority 27) +- qlpack: codeql/cert-cpp-coding-standards +- include: + kind: + - problem + - path-problem + - external/cert/obligation/rule + tags contain: + - external/cert/level/l1 +- exclude: + tags contain: + - external/cert/default-disabled \ No newline at end of file diff --git a/cpp/cert/src/codeql-suites/cert-cpp-l2.qls b/cpp/cert/src/codeql-suites/cert-cpp-l2.qls new file mode 100644 index 0000000000..b08cb07536 --- /dev/null +++ b/cpp/cert/src/codeql-suites/cert-cpp-l2.qls @@ -0,0 +1,12 @@ +- description: CERT C++ 2016 Level 2 Rules (Priority 6 - Priority 9) +- qlpack: codeql/cert-cpp-coding-standards +- include: + kind: + - problem + - path-problem + - external/cert/obligation/rule + tags contain: + - external/cert/level/l2 +- exclude: + tags contain: + - external/cert/default-disabled \ No newline at end of file diff --git a/cpp/cert/src/codeql-suites/cert-cpp-l3.qls b/cpp/cert/src/codeql-suites/cert-cpp-l3.qls new file mode 100644 index 0000000000..ca621c96ab --- /dev/null +++ b/cpp/cert/src/codeql-suites/cert-cpp-l3.qls @@ -0,0 +1,12 @@ +- description: CERT C++ 2016 Level 3 Rules (Priority 1 - Priority 4) +- qlpack: codeql/cert-cpp-coding-standards +- include: + kind: + - problem + - path-problem + - external/cert/obligation/rule + tags contain: + - external/cert/level/l3 +- exclude: + tags contain: + - external/cert/default-disabled \ No newline at end of file diff --git a/cpp/cert/src/codeql-suites/cert-cpp-single-translation-unit.qls b/cpp/cert/src/codeql-suites/cert-cpp-single-translation-unit.qls new file mode 100644 index 0000000000..2f09815e0d --- /dev/null +++ b/cpp/cert/src/codeql-suites/cert-cpp-single-translation-unit.qls @@ -0,0 +1,11 @@ +- description: CERT C++ 2016 (Single Translation Unit) +- qlpack: codeql/cert-cpp-coding-standards +- include: + kind: + - problem + - path-problem + tags contain: + - scope/single-translation-unit +- exclude: + tags contain: + - external/cert/default-disabled diff --git a/cpp/cert/src/codeql-suites/cert-default.qls b/cpp/cert/src/codeql-suites/cert-default.qls index e9211246b1..66599b60fb 100644 --- a/cpp/cert/src/codeql-suites/cert-default.qls +++ b/cpp/cert/src/codeql-suites/cert-default.qls @@ -1,9 +1,2 @@ -- description: CERT C++ 2016 (Default) -- qlpack: codeql/cert-cpp-coding-standards -- include: - kind: - - problem - - path-problem -- exclude: - tags contain: - - external/cert/default-disabled +- description: "DEPRECATED - CERT C++ 2016 - use cert-cpp-default.qls instead" +- import: codeql-suites/cert-cpp-default.qls \ No newline at end of file diff --git a/cpp/cert/src/codeql-suites/cert-single-translation-unit.qls b/cpp/cert/src/codeql-suites/cert-single-translation-unit.qls index 2f09815e0d..4966648394 100644 --- a/cpp/cert/src/codeql-suites/cert-single-translation-unit.qls +++ b/cpp/cert/src/codeql-suites/cert-single-translation-unit.qls @@ -1,11 +1,2 @@ -- description: CERT C++ 2016 (Single Translation Unit) -- qlpack: codeql/cert-cpp-coding-standards -- include: - kind: - - problem - - path-problem - tags contain: - - scope/single-translation-unit -- exclude: - tags contain: - - external/cert/default-disabled +- description: "DEPRECATED - CERT C++ 2016 (Single Translation Unit) - use cert-cpp-single-translation-unit.qls instead" +- import: codeql-suites/cert-cpp-single-translation-unit.qls \ No newline at end of file diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index dfc4d0cbd9..08fdfc9746 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,8 +1,9 @@ name: codeql/cert-cpp-coding-standards -version: 2.32.0-dev +version: 2.52.0-dev description: CERT C++ 2016 suites: codeql-suites license: MIT +default-suite-file: codeql-suites/cert-cpp-default.qls dependencies: - codeql/cpp-all: 0.9.3 + codeql/cpp-all: 4.0.3 codeql/common-cpp-coding-standards: '*' diff --git a/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked.ql b/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked.ql index 88232118bb..53f362e275 100644 --- a/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked.ql +++ b/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con50-cpp * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked.ql b/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked.ql index 2f2f5a6cdb..c15dfca5fc 100644 --- a/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked.ql +++ b/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/con50-cpp * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions.ql b/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions.ql index df17ec9a27..13977e2c1d 100644 --- a/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions.ql +++ b/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions.ql @@ -10,6 +10,11 @@ * @tags external/cert/id/con51-cpp * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/low + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ @@ -31,6 +36,8 @@ where // To reduce the number of results we require that this is a direct child // of the lock within the same function lpn.coveredByLock().getASuccessor*() = lpn and + // Exclude RAII-style locks which cannot leak + lpn.coveredByLock().canLeak() and // report those expressions for which there doesn't exist a catch block not exists(CatchBlock cb | catches(cb, lpn, _) and diff --git a/cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.ql b/cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.ql index 49d5309113..9ca1a89525 100644 --- a/cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.ql +++ b/cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con52-cpp * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder.ql b/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder.ql index bbd075b930..d83b3d520b 100644 --- a/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder.ql +++ b/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con53-cpp * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.ql b/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.ql index 5584b7bec2..84255dbfc7 100644 --- a/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.ql +++ b/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con54-cpp * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CON55-CPP/PreserveSafetyWhenUsingConditionVariables.ql b/cpp/cert/src/rules/CON55-CPP/PreserveSafetyWhenUsingConditionVariables.ql index 05d73a4d9f..d4f43c7d09 100644 --- a/cpp/cert/src/rules/CON55-CPP/PreserveSafetyWhenUsingConditionVariables.ql +++ b/cpp/cert/src/rules/CON55-CPP/PreserveSafetyWhenUsingConditionVariables.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con55-cpp * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex.ql b/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex.ql index 94d23c8664..67edf2fc22 100644 --- a/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex.ql +++ b/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con56-cpp * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/high + * external/cert/priority/p1 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit.ql b/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit.ql index 478a37af65..09ec2fa3d5 100644 --- a/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit.ql +++ b/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con56-cpp * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/high + * external/cert/priority/p1 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert.ql b/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert.ql index a64e8fca2c..e5565ccbbb 100644 --- a/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert.ql +++ b/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert.ql @@ -10,6 +10,11 @@ * @tags external/cert/id/ctr50-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/high + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess.ql b/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess.ql index 2163412435..0652f065cb 100644 --- a/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess.ql +++ b/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/ctr51-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql b/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql index dc53b7a6d0..b022869136 100644 --- a/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql +++ b/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/ctr52-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ @@ -16,7 +21,7 @@ import codingstandards.cpp.cert import codingstandards.cpp.Iterators import codingstandards.cpp.rules.containeraccesswithoutrangecheck.ContainerAccessWithoutRangeCheck as ContainerAccessWithoutRangeCheck import semmle.code.cpp.controlflow.Guards -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import semmle.code.cpp.valuenumbering.GlobalValueNumbering /** diff --git a/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.ql b/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.ql index d0afb7754c..1512a7fd99 100644 --- a/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.ql +++ b/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.ql @@ -8,12 +8,18 @@ * @problem.severity error * @tags external/cert/id/ctr53-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ import cpp import codingstandards.cpp.cert import codingstandards.cpp.Iterators +import semmle.code.cpp.dataflow.DataFlow predicate startEndArgumentsDoNotPointToTheSameContainer( IteratorRangeFunctionCall fc, Expr arg, string reason diff --git a/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers.ql b/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers.ql index f47f9db201..2401bcbf54 100644 --- a/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers.ql +++ b/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/ctr54-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.ql b/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.ql index ce1fb52667..c6ea2c4518 100644 --- a/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.ql +++ b/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/ctr55-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ @@ -15,6 +20,7 @@ import cpp import codingstandards.cpp.cert import codingstandards.cpp.Iterators import semmle.code.cpp.controlflow.Dominance +import semmle.code.cpp.dataflow.DataFlow /** * Models a call to an iterator's `operator+` diff --git a/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.ql b/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.ql index a7756b6a6a..b4ac267225 100644 --- a/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.ql +++ b/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.ql @@ -8,12 +8,17 @@ * @problem.severity warning * @tags external/cert/id/ctr56-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/high + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ import cpp import codingstandards.cpp.cert -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import NonFinalClassToPointerArithmeticExprFlow::PathGraph class ArrayAccessOrPointerArith extends Expr { diff --git a/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate.ql b/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate.ql index f28409bfc9..950ecd0c46 100644 --- a/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate.ql +++ b/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/ctr57-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable.ql b/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable.ql index be26725105..304b532b79 100644 --- a/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable.ql +++ b/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/ctr58-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/high + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction.ql b/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction.ql index 368f154e22..b24988823c 100644 --- a/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction.ql +++ b/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction.ql @@ -9,6 +9,11 @@ * correctness * security * scope/single-translation-unit + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName.ql b/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName.ql index 074ae6ebfc..3f8ea668dd 100644 --- a/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName.ql +++ b/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName.ql @@ -10,6 +10,11 @@ * maintainability * readability * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName.ql b/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName.ql index 8cae916a9a..74d683a0cb 100644 --- a/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName.ql +++ b/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName.ql @@ -10,6 +10,11 @@ * maintainability * readability * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName.ql b/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName.ql index 03e1ef7264..fabf036198 100644 --- a/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName.ql +++ b/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName.ql @@ -10,6 +10,11 @@ * maintainability * readability * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName.ql b/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName.ql index 974b231c26..3aaf5d37cb 100644 --- a/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName.ql +++ b/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/dcl51-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier.ql b/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier.ql index b32bdf70ba..583a768d22 100644 --- a/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier.ql +++ b/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/dcl51-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.ql b/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.ql index 472f0444ad..c85a7536e9 100644 --- a/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.ql +++ b/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/dcl51-cpp * maintainability * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.ql b/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.ql index f7dddb4d99..81036f6f57 100644 --- a/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.ql +++ b/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.ql @@ -10,14 +10,19 @@ * maintainability * readability * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp import codingstandards.cpp.cert -import codingstandards.cpp.UserDefinedLiteral +import codingstandards.cpp.UserDefinedLiteral as udl -from UserDefinedLiteral udl +from udl::UserDefinedLiteral udl where not isExcluded(udl, NamingPackage::useOfReservedLiteralSuffixIdentifierQuery()) and not udl.hasCompliantSuffix() diff --git a/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.ql b/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.ql index e2f7270f9c..ed57351d6a 100644 --- a/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.ql +++ b/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/dcl51-cpp * maintainability * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier.ql b/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier.ql index 237ebbe985..f576144c46 100644 --- a/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier.ql +++ b/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier.ql @@ -9,6 +9,11 @@ * @problem.severity warning * @tags external/cert/id/dcl53-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ @@ -20,6 +25,6 @@ from UserVariable v, UserVariable hidden where not isExcluded(v, ScopePackage::localConstructorInitializedObjectHidesIdentifierQuery()) and v.getInitializer().getExpr() instanceof ConstructorCall and - hides(hidden, v) + hidesStrict(hidden, v) select v, "The declaration declares variable " + v.getName() + " that hides $@", hidden, hidden.getName() diff --git a/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.ql b/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.ql index 3f91530c84..45aa70dc31 100644 --- a/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.ql +++ b/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.ql @@ -8,12 +8,16 @@ * @problem.severity warning * @tags external/cert/id/dcl53-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp import codingstandards.cpp.cert -import codingstandards.cpp.Scope class LocalUserFunctionDeclarationEntry extends FunctionDeclarationEntry { DeclStmt ds; diff --git a/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction.ql b/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction.ql index 7f419397ee..8f168e90c8 100644 --- a/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction.ql +++ b/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/dcl54-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/low + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries.ql b/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries.ql index cf301dfb5f..85b72afaeb 100644 --- a/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries.ql +++ b/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/dcl55-cpp * security + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/high + * external/cert/priority/p1 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit.ql b/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit.ql index 1ad411427f..4eb94f3d1d 100644 --- a/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit.ql +++ b/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/dcl56-cpp * correctness * maintainability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions.ql b/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions.ql index 951169abe5..6f625fd308 100644 --- a/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions.ql +++ b/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/dcl57-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces.ql b/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces.ql index a0e94d083c..81242bc0f4 100644 --- a/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces.ql +++ b/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/dcl58-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile.ql b/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile.ql index 57dae96f09..2b8b364c7d 100644 --- a/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile.ql +++ b/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile.ql @@ -10,6 +10,11 @@ * @problem.severity error * @tags external/cert/id/dcl59-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed.ql b/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed.ql index 7908609cc6..84e63a9569 100644 --- a/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed.ql +++ b/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/dcl60-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/high + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert.ql b/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert.ql index 6c22010ef7..40a884fc5a 100644 --- a/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert.ql +++ b/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/err50-cpp * correctness * external/cert/audit + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert.ql b/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert.ql index 9c312672e7..548b7b4b94 100644 --- a/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert.ql +++ b/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err50-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert.ql b/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert.ql index ddee05aecf..4fe89c634d 100644 --- a/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert.ql +++ b/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err50-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert.ql b/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert.ql index 015a5ffede..2036ff2f46 100644 --- a/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert.ql +++ b/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err50-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert.ql b/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert.ql index 088cfe93b0..05d04de99e 100644 --- a/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert.ql +++ b/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err50-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions.ql b/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions.ql index 2811815821..f8447d4af5 100644 --- a/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions.ql +++ b/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err51-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp.ql b/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp.ql index 45e29d02ff..6c9cb2e436 100644 --- a/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp.ql +++ b/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/err52-cpp * correctness * scope/single-translation-unit + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock.ql b/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock.ql index c45c3785e6..8587a73c33 100644 --- a/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock.ql +++ b/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/err53-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert.ql b/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert.ql index 8c4c5b5f06..c3e0aeb2f5 100644 --- a/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert.ql +++ b/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err54-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications.ql b/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications.ql index 7d433e2480..4f35d3cd93 100644 --- a/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications.ql +++ b/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/err55-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety.ql b/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety.ql index b027d02e3f..5831a7f404 100644 --- a/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety.ql +++ b/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/err56-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/high + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions.ql b/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions.ql index e283ca8e95..6180bf2f83 100644 --- a/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions.ql +++ b/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/err57-cpp * correctness * security + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting.ql b/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting.ql index 843b1f0964..ca6b6ae83f 100644 --- a/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting.ql +++ b/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/err58-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries.ql b/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries.ql index 902d392c5f..e1c7af4030 100644 --- a/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries.ql +++ b/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries.ql @@ -11,6 +11,11 @@ * @problem.severity error * @tags external/cert/id/err59-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible.ql b/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible.ql index 37a5fedd14..61a145c7a1 100644 --- a/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible.ql +++ b/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err60-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference.ql b/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference.ql index 29b879b5ea..8cc9c47854 100644 --- a/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference.ql +++ b/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err61-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber.ql b/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber.ql index 9c6f8120c5..e5451a0fc4 100644 --- a/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber.ql +++ b/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err62-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql index a385ee1ffc..960d04449e 100644 --- a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql +++ b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql @@ -8,14 +8,19 @@ * @problem.severity warning * @tags external/cert/id/exp50-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ import cpp import codingstandards.cpp.cert import codingstandards.cpp.SideEffect -import codingstandards.cpp.dataflow.DataFlow -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.TaintTracking import semmle.code.cpp.valuenumbering.GlobalValueNumbering /** Holds if the function's return value is derived from the `AliasParamter` p. */ diff --git a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects.ql b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects.ql index 1ddb315506..4c268e9c7e 100644 --- a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects.ql +++ b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/exp50-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql b/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql index bdf6a7973e..d0935cc798 100644 --- a/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql +++ b/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql @@ -8,12 +8,17 @@ * @problem.severity error * @tags external/cert/id/exp51-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ import cpp import codingstandards.cpp.cert -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import AllocationToDeleteFlow::PathGraph module AllocationToDeleteConfig implements DataFlow::ConfigSig { diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.ql b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.ql index 217be3db6a..59745c2cd0 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.ql +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/exp52-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.ql b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.ql index 93bb653c11..c9ced6825c 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.ql +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/exp52-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.ql b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.ql index a32aa1eb14..d8ed036a06 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.ql +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/exp52-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.ql b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.ql index 4cc602362e..aa0b8ff23a 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.ql +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/exp52-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand.ql b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand.ql index cc43a008d9..dc65dddcd1 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand.ql +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/exp52-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory.ql b/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory.ql index 47ee746038..9839fae0fd 100644 --- a/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory.ql +++ b/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/exp53-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert.ql b/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert.ql index 4f72fc725a..534bb83796 100644 --- a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert.ql +++ b/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/exp54-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert.ql b/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert.ql index d97c002dbd..ea2349194b 100644 --- a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert.ql +++ b/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/exp54-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert.ql b/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert.ql index 3c915191d4..68216f2e43 100644 --- a/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert.ql +++ b/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/exp55-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage.ql b/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage.ql index 23efb87e0b..d8460c58fa 100644 --- a/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage.ql +++ b/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/exp56-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass.ql b/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass.ql index 4358f11b34..2a8345c05d 100644 --- a/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass.ql +++ b/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/exp57-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass.ql b/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass.ql index 8534885c9e..935218f78e 100644 --- a/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass.ql +++ b/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/exp57-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart.ql b/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart.ql index 5c7ef31a6f..b537fa34c5 100644 --- a/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart.ql +++ b/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart.ql @@ -9,6 +9,11 @@ * @problem.severity warning * @tags external/cert/id/exp58-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart.ql b/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart.ql index dab95c8303..1d34680261 100644 --- a/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart.ql +++ b/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/exp58-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart.ql b/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart.ql index 0b9e0a9f99..ce340d63c8 100644 --- a/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart.ql +++ b/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/exp58-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember.ql b/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember.ql index 8cda1c0851..7ece8faef6 100644 --- a/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember.ql +++ b/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember.ql @@ -7,6 +7,11 @@ * @problem.severity recommendation * @tags external/cert/id/exp59-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries.ql b/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries.ql index 8442e5eda1..ddd6fa0efc 100644 --- a/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries.ql +++ b/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/exp60-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference.ql b/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference.ql index c57de9b2d1..1268d1c82b 100644 --- a/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference.ql +++ b/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference.ql @@ -10,6 +10,11 @@ * @tags external/cert/id/exp61-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference.ql b/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference.ql index 8487c78039..eb76ba6187 100644 --- a/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference.ql +++ b/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference.ql @@ -10,6 +10,11 @@ * @tags external/cert/id/exp61-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation.ql b/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation.ql index 4b8b67368f..64bfb4673b 100644 --- a/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation.ql +++ b/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/exp62-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation.ql b/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation.ql index 87f797bf25..0e8847257c 100644 --- a/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation.ql +++ b/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/exp62-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation.ql b/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation.ql index 302410def1..a4ae635289 100644 --- a/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation.ql +++ b/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/exp62-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject.ql b/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject.ql index 785d4b8b2b..48e534bfbb 100644 --- a/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject.ql +++ b/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/exp63-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition.ql b/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition.ql index e30168dc23..0333955f72 100644 --- a/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition.ql +++ b/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/fio50-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded.ql b/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded.ql index 383fb9db1f..a444692594 100644 --- a/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded.ql +++ b/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/fio51-cpp * correctness * security + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue.ql b/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue.ql index f90d3a42ef..c7437073e9 100644 --- a/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue.ql +++ b/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/int50-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM50-CPP/UseAfterFree.ql b/cpp/cert/src/rules/MEM50-CPP/UseAfterFree.ql index 59bf3e5bc7..8c31fc104c 100644 --- a/cpp/cert/src/rules/MEM50-CPP/UseAfterFree.ql +++ b/cpp/cert/src/rules/MEM50-CPP/UseAfterFree.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/mem50-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources.ql b/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources.ql index 5854b169f2..70fd363c64 100644 --- a/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources.ql +++ b/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/mem51-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.ql b/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.ql index c25e1aa0ad..90685f1c96 100644 --- a/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.ql +++ b/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.ql @@ -7,13 +7,18 @@ * @problem.severity error * @tags external/cert/id/mem52-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ import cpp import codingstandards.cpp.cert import semmle.code.cpp.controlflow.Guards -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.exceptions.ExceptionSpecifications /** diff --git a/cpp/cert/src/rules/MEM53-CPP/ManuallyManagedLifetime.qll b/cpp/cert/src/rules/MEM53-CPP/ManuallyManagedLifetime.qll index 358a3583fc..0eaf9f8dfa 100644 --- a/cpp/cert/src/rules/MEM53-CPP/ManuallyManagedLifetime.qll +++ b/cpp/cert/src/rules/MEM53-CPP/ManuallyManagedLifetime.qll @@ -1,9 +1,9 @@ import codingstandards.cpp.cert import codingstandards.cpp.Conversion -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType import ManuallyManagedLifetime import semmle.code.cpp.controlflow.Dominance -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking /** * A taint-tracking configuration from allocation expressions to casts to a specific pointer type. @@ -14,12 +14,15 @@ module AllocToStaticCastConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { exists(AllocationExpr ae | ae.getType().getUnspecifiedType() instanceof VoidPointerType and - source.asExpr() = ae and - // Ignore realloc, as that memory may already be partially constructed - not ae.(FunctionCall).getTarget().getName().toLowerCase().matches("%realloc%") + source.asExpr() = ae ) } + predicate isBarrier(DataFlow::Node sanitizer) { + // Ignore realloc, as that memory may already be partially constructed + sanitizer.asExpr().(FunctionCall).getTarget().getName().toLowerCase().matches("%realloc%") + } + predicate isSink(DataFlow::Node sink) { exists(StaticOrCStyleCast sc, Class nonTrivialClass | sc.getExpr() = sink.asExpr() and diff --git a/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql b/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql index 30c5280482..a56fa18da8 100644 --- a/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql +++ b/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql @@ -7,14 +7,19 @@ * @problem.severity error * @tags external/cert/id/mem53-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ import cpp import codingstandards.cpp.cert -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType import ManuallyManagedLifetime -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import AllocToStaticCastFlow::PathGraph /* diff --git a/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.ql b/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.ql index b498729d69..fe6fff2d4f 100644 --- a/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.ql +++ b/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.ql @@ -7,13 +7,18 @@ * @problem.severity error * @tags external/cert/id/mem53-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ import cpp import codingstandards.cpp.cert import ManuallyManagedLifetime -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import FreeWithoutDestructorFlow::PathGraph from FreeWithoutDestructorFlow::PathNode source, FreeWithoutDestructorFlow::PathNode sink diff --git a/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert.ql b/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert.ql index 695d39de69..fca9190552 100644 --- a/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert.ql +++ b/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert.ql @@ -10,6 +10,11 @@ * @tags external/cert/id/mem54-cpp * security * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert.ql b/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert.ql index 4993de85ed..d623e85a50 100644 --- a/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert.ql +++ b/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/mem54-cpp * security * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert.ql b/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert.ql index d3366f15fc..fd8f4f3a04 100644 --- a/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert.ql +++ b/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/mem55-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert.ql b/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert.ql index 564d74c333..2740498eef 100644 --- a/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert.ql +++ b/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/mem55-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.ql b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.ql index c07dbff76c..072c69201f 100644 --- a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.ql +++ b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/mem55-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert.ql b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert.ql index 0b02be8b3f..da4b63200b 100644 --- a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert.ql +++ b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/mem55-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert.ql b/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert.ql index 7fa3209151..ba7a39272a 100644 --- a/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert.ql +++ b/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/mem56-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.ql b/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.ql index f8a5247ff1..6c3d18c27f 100644 --- a/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.ql +++ b/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/mem57-cpp * correctness * security + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.ql b/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.ql index 8ab68974cb..b67cec99f3 100644 --- a/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.ql +++ b/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/msc50-cpp * security * scope/single-translation-unit + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.ql b/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.ql index 52b14d9629..5322fbbde3 100644 --- a/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.ql +++ b/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.ql @@ -9,13 +9,18 @@ * @tags external/cert/id/msc51-cpp * security * correctness + * external/cert/severity/medium + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ import cpp import codingstandards.cpp.cert import codingstandards.cpp.standardlibrary.Random -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking from RandomNumberEngineCreation createRandomNumberEngine, string seedSource where diff --git a/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert.ql b/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert.ql index 9634592715..dcf42a78f4 100644 --- a/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert.ql +++ b/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/msc52-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert.ql b/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert.ql index 511369e46c..5044b3b421 100644 --- a/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert.ql +++ b/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/msc53-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction.ql b/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction.ql index a537346630..885d8caa0a 100644 --- a/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction.ql +++ b/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/msc54-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors.ql b/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors.ql index 5cbcee6be9..1c3df97cfa 100644 --- a/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors.ql +++ b/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors.ql @@ -7,6 +7,11 @@ * @precision very-high * @problem.severity error * @tags external/cert/id/oop50-cpp + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects.ql b/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects.ql index f0af256fb9..4cb654730b 100644 --- a/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects.ql +++ b/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects.ql @@ -7,6 +7,11 @@ * @precision very-high * @problem.severity error * @tags external/cert/id/oop51-cpp + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor.ql b/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor.ql index 13bfdd5c0c..190c4d720d 100644 --- a/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor.ql +++ b/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor.ql @@ -7,6 +7,11 @@ * @precision very-high * @problem.severity warning * @tags external/cert/id/oop52-cpp + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit.ql b/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit.ql index 96fd7812d7..b42b54ef6c 100644 --- a/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit.ql +++ b/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit.ql @@ -12,6 +12,11 @@ * security * maintainability * readability + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment.ql b/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment.ql index 85940bf862..844d0f54bb 100644 --- a/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment.ql +++ b/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/oop54-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember.ql b/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember.ql index ead970ca71..27c63c2c16 100644 --- a/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember.ql +++ b/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/oop55-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember.ql b/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember.ql index 614d3fbaca..72d640f29b 100644 --- a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember.ql +++ b/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/oop55-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember.ql b/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember.ql index e6b8f10d9c..202123c11c 100644 --- a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember.ql +++ b/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/oop55-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements.ql b/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements.ql index 18b259ef86..981bd1ce5b 100644 --- a/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements.ql +++ b/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/oop56-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements.ql b/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements.ql index ea499791ff..4d59b36b52 100644 --- a/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements.ql +++ b/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/oop56-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions.ql b/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions.ql index 19b14730bb..9ac17e84a0 100644 --- a/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions.ql +++ b/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/oop57-cpp * correctness * scope/single-translation-unit + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject.ql b/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject.ql index 97cfe0fa3c..9ad0593702 100644 --- a/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject.ql +++ b/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/oop58-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert.ql b/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert.ql index 9ff12eca5c..2cd08be70a 100644 --- a/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert.ql +++ b/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert.ql @@ -7,6 +7,11 @@ * @precision very-high * @problem.severity recommendation * @tags external/cert/id/str50-cpp + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert.ql b/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert.ql index d79297a63b..59f56207cd 100644 --- a/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert.ql +++ b/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert.ql @@ -7,6 +7,11 @@ * @precision very-high * @problem.severity recommendation * @tags external/cert/id/str50-cpp + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer.ql b/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer.ql index e775dc205f..a6337e2fcf 100644 --- a/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer.ql +++ b/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/str51-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString.ql b/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString.ql index 211e490b33..21c29f54ef 100644 --- a/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString.ql +++ b/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/str52-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess.ql b/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess.ql index 3300b77e18..c92f2b2316 100644 --- a/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess.ql +++ b/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/str53-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/test/codeql-pack.lock.yml b/cpp/cert/test/codeql-pack.lock.yml index 514e6963d0..a45ea8f438 100644 --- a/cpp/cert/test/codeql-pack.lock.yml +++ b/cpp/cert/test/codeql-pack.lock.yml @@ -2,13 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.9.3 + version: 4.0.3 codeql/dataflow: - version: 0.0.4 + version: 2.0.3 + codeql/mad: + version: 1.0.19 + codeql/rangeanalysis: + version: 1.0.19 codeql/ssa: - version: 0.1.5 + version: 1.0.19 codeql/tutorial: - version: 0.1.5 + version: 1.0.19 + codeql/typeflow: + version: 1.0.19 + codeql/typetracking: + version: 2.0.3 codeql/util: - version: 0.1.5 + version: 2.0.6 + codeql/xml: + version: 1.0.19 compiled: false diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index a2fe672e5b..7dda15503a 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.32.0-dev +version: 2.52.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/cert/test/rules/CON51-CPP/test.cpp b/cpp/cert/test/rules/CON51-CPP/test.cpp index 7f5731e479..6d714f7e16 100644 --- a/cpp/cert/test/rules/CON51-CPP/test.cpp +++ b/cpp/cert/test/rules/CON51-CPP/test.cpp @@ -83,6 +83,11 @@ void f8(std::mutex *pm) { } } +void f9(std::mutex *pm) { + std::lock_guard lg(*pm); + mightThrow(); // COMPLIANT +} + void m() { std::mutex pm; std::thread t1 = std::thread(f1, &pm); @@ -93,4 +98,5 @@ void m() { std::thread t6 = std::thread(f6, &pm); std::thread t7 = std::thread(f7, &pm); std::thread t8 = std::thread(f8, &pm); + std::thread t9 = std::thread(f9, &pm); } diff --git a/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected b/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected index 4e87d1436c..6be9fd55cc 100644 --- a/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected +++ b/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected @@ -1,3 +1,12 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:93,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:93,27-35) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:94,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:98,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:98,29-37) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:99,11-19) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:109,35-43) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:110,11-19) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:109,9-22) | test.cpp:8:42:8:46 | call to begin | Output iterator for $@ is not guaranteed to be large enough for the input iterator. | test.cpp:8:3:8:11 | call to copy | call to copy | | test.cpp:17:42:17:46 | call to begin | Output iterator for $@ is not guaranteed to be large enough for the input iterator. | test.cpp:17:3:17:11 | call to copy | call to copy | | test.cpp:55:42:55:46 | call to begin | Output iterator for $@ is not guaranteed to be large enough for the input iterator. | test.cpp:55:3:55:11 | call to copy | call to copy | diff --git a/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected b/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected index 61260a0579..d25d23185a 100644 --- a/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected +++ b/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected @@ -1,3 +1,9 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:29,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:29,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:30,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:36,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:36,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:37,7-15) | test.cpp:7:3:7:15 | call to for_each | The $@ of iterator range function does not point to the end of an iterator. | test.cpp:7:28:7:32 | call to begin | argument | | test.cpp:7:3:7:15 | call to for_each | The $@ of iterator range function does not point to the start of an iterator. | test.cpp:7:19:7:21 | call to end | argument | | test.cpp:8:3:8:15 | call to for_each | The $@ of iterator range function does not point to the end of an iterator. | test.cpp:8:30:8:34 | call to begin | argument | diff --git a/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected b/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected index 0a06677b54..db3b7358d8 100644 --- a/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected +++ b/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected @@ -1,3 +1,12 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:44,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:44,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:44,51-59) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:45,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:45,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:45,52-60) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:80,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:80,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:81,7-15) | test.cpp:8:7:8:7 | i | Increment of iterator may overflow since its bounds are not checked. | | test.cpp:9:9:9:9 | i | Increment of iterator may overflow since its bounds are not checked. | | test.cpp:10:9:10:9 | i | Increment of iterator may overflow since its bounds are not checked. | diff --git a/cpp/cert/test/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.expected b/cpp/cert/test/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.expected index 0ee15c65b5..51ef13412c 100644 --- a/cpp/cert/test/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.expected +++ b/cpp/cert/test/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.expected @@ -1,15 +1,19 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:46,62-70) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:47,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:56,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:62,3-11) edges -| test.cpp:15:19:15:21 | foo | test.cpp:16:24:16:26 | foo | -| test.cpp:15:19:15:21 | foo | test.cpp:16:51:16:53 | foo | -| test.cpp:27:19:27:21 | foo | test.cpp:29:18:29:20 | foo | -| test.cpp:40:12:40:19 | new | test.cpp:43:6:43:7 | l1 | -| test.cpp:40:12:40:19 | new | test.cpp:44:6:44:7 | l1 | -| test.cpp:42:12:42:14 | & ... | test.cpp:45:6:45:7 | l3 | -| test.cpp:42:12:42:14 | & ... | test.cpp:46:6:46:7 | l3 | -| test.cpp:43:6:43:7 | l1 | test.cpp:15:19:15:21 | foo | -| test.cpp:44:6:44:7 | l1 | test.cpp:27:19:27:21 | foo | -| test.cpp:45:6:45:7 | l3 | test.cpp:15:19:15:21 | foo | -| test.cpp:46:6:46:7 | l3 | test.cpp:27:19:27:21 | foo | +| test.cpp:15:19:15:21 | foo | test.cpp:16:24:16:26 | foo | provenance | | +| test.cpp:15:19:15:21 | foo | test.cpp:16:51:16:53 | foo | provenance | | +| test.cpp:27:19:27:21 | foo | test.cpp:29:18:29:20 | foo | provenance | | +| test.cpp:40:12:40:19 | new | test.cpp:43:6:43:7 | l1 | provenance | | +| test.cpp:40:12:40:19 | new | test.cpp:44:6:44:7 | l1 | provenance | | +| test.cpp:42:12:42:14 | & ... | test.cpp:45:6:45:7 | l3 | provenance | | +| test.cpp:42:12:42:14 | & ... | test.cpp:46:6:46:7 | l3 | provenance | | +| test.cpp:43:6:43:7 | l1 | test.cpp:15:19:15:21 | foo | provenance | | +| test.cpp:44:6:44:7 | l1 | test.cpp:27:19:27:21 | foo | provenance | | +| test.cpp:45:6:45:7 | l3 | test.cpp:15:19:15:21 | foo | provenance | | +| test.cpp:46:6:46:7 | l3 | test.cpp:27:19:27:21 | foo | provenance | | nodes | test.cpp:15:19:15:21 | foo | semmle.label | foo | | test.cpp:16:24:16:26 | foo | semmle.label | foo | diff --git a/cpp/cert/test/rules/DCL51-CPP/FunctionReusesReservedName.expected b/cpp/cert/test/rules/DCL51-CPP/FunctionReusesReservedName.expected index e945f93c57..97bbccbbd0 100644 --- a/cpp/cert/test/rules/DCL51-CPP/FunctionReusesReservedName.expected +++ b/cpp/cert/test/rules/DCL51-CPP/FunctionReusesReservedName.expected @@ -1 +1 @@ -| test.cpp:20:6:20:8 | min | The function $@ reuses a reserved standard library name. | test.cpp:20:6:20:8 | min | min | +| test.cpp:22:6:22:8 | min | The function $@ reuses a reserved standard library name. | test.cpp:22:6:22:8 | min | min | diff --git a/cpp/cert/test/rules/DCL51-CPP/ObjectReusesReservedName.expected b/cpp/cert/test/rules/DCL51-CPP/ObjectReusesReservedName.expected index 698b0c6067..d1c0b8d60e 100644 --- a/cpp/cert/test/rules/DCL51-CPP/ObjectReusesReservedName.expected +++ b/cpp/cert/test/rules/DCL51-CPP/ObjectReusesReservedName.expected @@ -1 +1 @@ -| test.cpp:18:5:18:10 | tzname | The variable $@ reuses a reserved standard library name. | test.cpp:18:5:18:10 | tzname | tzname | +| test.cpp:19:5:19:10 | tzname | The variable $@ reuses a reserved standard library name. | test.cpp:19:5:19:10 | tzname | tzname | diff --git a/cpp/cert/test/rules/DCL51-CPP/RedefiningOfStandardLibraryName.expected b/cpp/cert/test/rules/DCL51-CPP/RedefiningOfStandardLibraryName.expected index f5b15966ba..fb01130c4d 100644 --- a/cpp/cert/test/rules/DCL51-CPP/RedefiningOfStandardLibraryName.expected +++ b/cpp/cert/test/rules/DCL51-CPP/RedefiningOfStandardLibraryName.expected @@ -1,3 +1,3 @@ | test.cpp:6:1:6:14 | #undef INT_MAX | Redefinition of INT_MAX declared in a standard library header. | | test.cpp:7:1:7:20 | #define SIZE_MAX 256 | Redefinition of SIZE_MAX declared in a standard library header. | -| test.cpp:37:1:38:9 | #define FD_SET(X) int _ ## X | Redefinition of FD_SET declared in a standard library header. | +| test.cpp:39:1:40:9 | #define FD_SET(X) int _ ## X | Redefinition of FD_SET declared in a standard library header. | diff --git a/cpp/cert/test/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.expected b/cpp/cert/test/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.expected index 3b0a94429a..0d52226d5f 100644 --- a/cpp/cert/test/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.expected +++ b/cpp/cert/test/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.expected @@ -1,2 +1,2 @@ -| test.cpp:25:5:25:7 | __x | Name $@ uses the reserved prefix '__'. | test.cpp:25:5:25:7 | __x | __x | -| test.cpp:30:5:30:7 | __x | Name $@ uses the reserved prefix '__'. | test.cpp:30:5:30:7 | __x | __x | +| test.cpp:27:5:27:7 | __x | Name $@ uses the reserved prefix '__'. | test.cpp:27:5:27:7 | __x | __x | +| test.cpp:32:5:32:7 | __x | Name $@ uses the reserved prefix '__'. | test.cpp:32:5:32:7 | __x | __x | diff --git a/cpp/cert/test/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.expected b/cpp/cert/test/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.expected index f8863eab59..96f3b1068e 100644 --- a/cpp/cert/test/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.expected +++ b/cpp/cert/test/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.expected @@ -1 +1 @@ -| test.cpp:22:6:22:17 | operator ""x | Literal suffix identifier $@ does not start with an underscore. | test.cpp:22:6:22:17 | operator ""x | operator ""x | +| test.cpp:24:6:24:17 | operator ""x | Literal suffix identifier $@ does not start with an underscore. | test.cpp:24:6:24:17 | operator ""x | operator ""x | diff --git a/cpp/cert/test/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.expected b/cpp/cert/test/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.expected index 679ad58deb..544a26c996 100644 --- a/cpp/cert/test/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.expected +++ b/cpp/cert/test/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.expected @@ -1,5 +1,5 @@ -| test.cpp:26:5:26:6 | _X | Name $@ uses the reserved prefix '_'. | test.cpp:26:5:26:6 | _X | _X | -| test.cpp:27:5:27:6 | _x | Name $@ uses the reserved prefix '_'. | test.cpp:27:5:27:6 | _x | _x | -| test.cpp:31:5:31:6 | _X | Name $@ uses the reserved prefix '_'. | test.cpp:31:5:31:6 | _X | _X | -| test.cpp:35:1:35:3 | _i | Name $@ uses the reserved prefix '_'. | test.cpp:35:1:35:3 | _i | _i | +| test.cpp:28:5:28:6 | _X | Name $@ uses the reserved prefix '_'. | test.cpp:28:5:28:6 | _X | _X | +| test.cpp:29:5:29:6 | _x | Name $@ uses the reserved prefix '_'. | test.cpp:29:5:29:6 | _x | _x | +| test.cpp:33:5:33:6 | _X | Name $@ uses the reserved prefix '_'. | test.cpp:33:5:33:6 | _X | _X | +| test.cpp:37:1:37:3 | _i | Name $@ uses the reserved prefix '_'. | test.cpp:37:1:37:3 | _i | _i | | test.h:2:1:2:15 | #define _TEST_H | Name $@ uses the reserved prefix '_'. | test.h:2:1:2:15 | #define _TEST_H | _TEST_H | diff --git a/cpp/cert/test/rules/DCL51-CPP/test.cpp b/cpp/cert/test/rules/DCL51-CPP/test.cpp index 5e27dd2390..9248041b57 100644 --- a/cpp/cert/test/rules/DCL51-CPP/test.cpp +++ b/cpp/cert/test/rules/DCL51-CPP/test.cpp @@ -15,7 +15,9 @@ enum { // int NULL = 0; // NON_COMPLIANT, but not supported by compilers in practice +namespace ns { int tzname = 0; // NON_COMPLIANT +} void min() {} // NON_COMPLIANT @@ -48,4 +50,4 @@ void test_lambda(const int y) { // Lambda generates a static function called `_FUN` when the lambda is // converted to a function pointer g([](int x) { return x; }); // COMPLIANT - compiler generated -} \ No newline at end of file +} diff --git a/cpp/cert/test/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.expected b/cpp/cert/test/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.expected index b432856e8b..08d46a7bbd 100644 --- a/cpp/cert/test/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.expected +++ b/cpp/cert/test/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.expected @@ -1,3 +1,27 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:29,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:29,59-67) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:32,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:32,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:36,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:36,59-67) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:45,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:45,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:45,53-61) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:48,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:48,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:57,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:57,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:64,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:64,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:76,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:76,55-63) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:29,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:32,7-20) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:36,7-20) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:48,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:57,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:64,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:76,5-18) | test.cpp:82:3:82:4 | call to f2 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.cpp:82:6:82:7 | call to f5 | call to f5 | test.cpp:82:12:82:13 | call to f6 | call to f6 | | test.cpp:84:3:84:4 | call to f2 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.cpp:84:6:84:7 | call to f5 | call to f5 | test.cpp:84:12:84:13 | call to f7 | call to f7 | | test.cpp:87:3:87:4 | call to f2 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.cpp:87:9:87:10 | call to m1 | call to m1 | test.cpp:87:18:87:19 | call to m1 | call to m1 | diff --git a/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected b/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected index a50daa096e..8b7a4902cc 100644 --- a/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected +++ b/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected @@ -1,6 +1,10 @@ +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 | -| test.cpp:7:22:7:40 | new[] | test.cpp:10:12:10:13 | l2 | +| 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[] | diff --git a/cpp/cert/test/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.expected b/cpp/cert/test/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.expected index b7452ec199..41fa58045f 100644 --- a/cpp/cert/test/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.expected +++ b/cpp/cert/test/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.expected @@ -1,2 +1,9 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:64,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:66,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:82,46-54) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:83,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:87,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:90,35-43) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:95,38-46) | test.cpp:24:7:24:34 | new | nothrow new allocation of $@ returns here without a subsequent check to see whether the pointer is valid. | test.cpp:24:7:24:34 | new | StructA * | | test.cpp:40:17:40:38 | call to allocate_without_check | nothrow new allocation of $@ returns here without a subsequent check to see whether the pointer is valid. | test.cpp:35:17:35:44 | new | StructA * | diff --git a/cpp/cert/test/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.expected b/cpp/cert/test/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.expected index 00ed15c370..f7f4705ef3 100644 --- a/cpp/cert/test/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.expected +++ b/cpp/cert/test/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.expected @@ -1,8 +1,8 @@ edges -| test.cpp:16:26:16:31 | call to malloc | test.cpp:22:8:22:9 | a1 | -| test.cpp:17:38:17:43 | call to malloc | test.cpp:23:8:23:9 | a2 | -| test.cpp:18:26:18:39 | call to operator new | test.cpp:26:21:26:22 | a3 | -| test.cpp:20:29:20:42 | call to operator new | test.cpp:27:21:27:22 | a4 | +| test.cpp:16:26:16:31 | call to malloc | test.cpp:22:8:22:9 | a1 | provenance | | +| test.cpp:17:38:17:43 | call to malloc | test.cpp:23:8:23:9 | a2 | provenance | | +| test.cpp:18:26:18:39 | call to operator new | test.cpp:26:21:26:22 | a3 | provenance | | +| test.cpp:20:29:20:42 | call to operator new | test.cpp:27:21:27:22 | a4 | provenance | | nodes | test.cpp:16:26:16:31 | call to malloc | semmle.label | call to malloc | | test.cpp:17:38:17:43 | call to malloc | semmle.label | call to malloc | diff --git a/cpp/cert/test/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.expected b/cpp/cert/test/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.expected index 0128221ffc..606ccbff2b 100644 --- a/cpp/cert/test/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.expected +++ b/cpp/cert/test/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.expected @@ -1,3 +1,4 @@ +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (BadlySeededRandomNumberGenerator.ql:42,7-20) | test.cpp:9:33:9:33 | call to linear_congruential_engine | Random number generator linear_congruential_engine is default-initialized and is therefore not properly seeded. | | test.cpp:10:30:10:31 | call to linear_congruential_engine | Random number generator linear_congruential_engine is default-initialized and is therefore not properly seeded. | | test.cpp:11:21:11:22 | call to linear_congruential_engine | Random number generator linear_congruential_engine is default-initialized and is therefore not properly seeded. | diff --git a/cpp/common/src/codeql-pack.lock.yml b/cpp/common/src/codeql-pack.lock.yml index 514e6963d0..a45ea8f438 100644 --- a/cpp/common/src/codeql-pack.lock.yml +++ b/cpp/common/src/codeql-pack.lock.yml @@ -2,13 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.9.3 + version: 4.0.3 codeql/dataflow: - version: 0.0.4 + version: 2.0.3 + codeql/mad: + version: 1.0.19 + codeql/rangeanalysis: + version: 1.0.19 codeql/ssa: - version: 0.1.5 + version: 1.0.19 codeql/tutorial: - version: 0.1.5 + version: 1.0.19 + codeql/typeflow: + version: 1.0.19 + codeql/typetracking: + version: 2.0.3 codeql/util: - version: 0.1.5 + version: 2.0.6 + codeql/xml: + version: 1.0.19 compiled: false diff --git a/cpp/common/src/codingstandards/cpp/AccessPath.qll b/cpp/common/src/codingstandards/cpp/AccessPath.qll index 2393d25db4..3af462e1ec 100644 --- a/cpp/common/src/codingstandards/cpp/AccessPath.qll +++ b/cpp/common/src/codingstandards/cpp/AccessPath.qll @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow newtype TFieldQualifier = ExplicitQualifier(VariableAccess v) or diff --git a/cpp/common/src/codingstandards/cpp/AlertReporting.qll b/cpp/common/src/codingstandards/cpp/AlertReporting.qll new file mode 100644 index 0000000000..a85ae4097b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/AlertReporting.qll @@ -0,0 +1,76 @@ +/** + * Provides a library for managing how alerts are reported. + */ + +import cpp + +signature class ResultType extends Element; + +/** + * A module for unwrapping results that occur in macro expansions. + */ +module MacroUnwrapper { + /** + * Gets a macro invocation that applies to the result element. + */ + private MacroInvocation getAMacroInvocation(ResultElement re) { + result.getAnAffectedElement() = re + } + + private MacroInvocation getASubsumedMacroInvocation(ResultElement re) { + result = getAMacroInvocation(re) and + // Only report cases where the element is not located at the macro expansion site + // This means we'll report results in macro arguments in the macro argument + // location, not within the macro itself. + // + // Do not join start column values. + pragma[only_bind_out](result.getLocation().getStartColumn()) = + pragma[only_bind_out](re.getLocation().getStartColumn()) + } + + /** + * Gets the primary macro invocation that generated the result element. + * + * Does not hold for cases where the result element is located at a macro argument site. + */ + MacroInvocation getPrimaryMacroInvocation(ResultElement re) { + exists(MacroInvocation mi | + mi = getASubsumedMacroInvocation(re) and + // No other more specific macro that expands to element + not exists(MacroInvocation otherMi | + otherMi = getAMacroInvocation(re) and otherMi.getParentInvocation() = mi + ) and + result = mi + ) + } + + /** + * Gets the primary macro that generated the result element. + */ + Macro getPrimaryMacro(ResultElement re) { result = getPrimaryMacroInvocation(re).getMacro() } + + /** + * If a result element is expanded from a macro invocation, then return the "primary" macro that + * generated the element, otherwise return the element itself. + */ + Element unwrapElement(ResultElement re) { + if exists(getPrimaryMacro(re)) then result = getPrimaryMacro(re) else result = re + } + + /* Final class so we can extend it */ + final private class FinalMacroInvocation = MacroInvocation; + + /* A macro invocation that expands to create a `ResultElement` */ + class ResultMacroExpansion extends FinalMacroInvocation { + ResultElement re; + + ResultMacroExpansion() { re = getAnExpandedElement() } + + ResultElement getResultElement() { result = re } + } + + /* The most specific macro invocation that expands to create this `ResultElement`. */ + class PrimaryMacroExpansion extends ResultMacroExpansion { + PrimaryMacroExpansion() { this = getPrimaryMacroInvocation(re) } + } +} diff --git a/cpp/common/src/codingstandards/cpp/Allocations.qll b/cpp/common/src/codingstandards/cpp/Allocations.qll index 5bc87221e2..decdfe9fc4 100644 --- a/cpp/common/src/codingstandards/cpp/Allocations.qll +++ b/cpp/common/src/codingstandards/cpp/Allocations.qll @@ -7,7 +7,7 @@ import cpp import semmle.code.cpp.controlflow.SSA -import codingstandards.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow /** * Holds if `alloc` is a use of `malloc` or `new`. `kind` is diff --git a/cpp/common/src/codingstandards/cpp/BannedFunctions.qll b/cpp/common/src/codingstandards/cpp/BannedFunctions.qll new file mode 100644 index 0000000000..174d0a8433 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/BannedFunctions.qll @@ -0,0 +1,69 @@ +/** + * A library for supporting the consistent detection of banned functions in C++ code. + */ + +import cpp +import AlertReporting + +/** + * A signature for a banned function. + */ +signature class BannedFunction extends Function; + +/** + * A module for detecting uses of banned functions in C++ code. + */ +module BannedFunctions { + final private class FinalExpr = Expr; + + /** + * An expression that uses a banned function. + * + * It can be either a function call or a function access (taking the address of the function). + */ + class UseExpr extends FinalExpr { + string action; + F bannedFunction; + + UseExpr() { + this.(FunctionCall).getTarget() = bannedFunction and + action = "Call to" + or + this.(FunctionAccess).getTarget() = bannedFunction and + action = "Address taken for" + } + + string getFunctionName() { result = bannedFunction.getName() } + + string getAction() { result = action } + + Element getPrimaryElement() { + // If this is defined in a macro in the users source location, then report the macro + // expansion, otherwise report the element itself. This ensures that we always report + // the use of the terminating function, but combine usages when the macro is defined + // by the user. + exists(Element e | e = MacroUnwrapper::unwrapElement(this) | + if exists(e.getFile().getRelativePath()) then result = e else result = this + ) + } + } + + final private class FinalElement = Element; + + /** + * A `Use` of a banned function. + * + * This is an `Element` in a program which represents the use of a banned function. + * For uses within macro expansions, this may report the location of the macro, if + * it is defined within the user's source code. + */ + class Use extends FinalElement { + UseExpr use; + + Use() { this = use.getPrimaryElement() } + + string getFunctionName() { result = use.getFunctionName() } + + string getAction() { result = use.getAction() } + } +} diff --git a/cpp/common/src/codingstandards/cpp/BinaryOperations.qll b/cpp/common/src/codingstandards/cpp/BinaryOperations.qll new file mode 100644 index 0000000000..5302535fef --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/BinaryOperations.qll @@ -0,0 +1,75 @@ +import cpp + +private signature class BinaryOp extends BinaryOperation; + +private signature class AssignBinaryOp extends AssignOperation; + +/** + * A module for unifying the `BinaryOperation` and `AssignOperation` hierarchies. + */ +private module BinaryOpUnifier { + final class FinalExpr = Expr; + + class BinaryExpr extends FinalExpr { + BinaryExpr() { + this instanceof BinaryOpType or + this instanceof AssignBinaryOpType + } + + Expr getLeftOperand() { + result = this.(BinaryOpType).getLeftOperand() + or + result = this.(AssignBinaryOpType).getLValue() + } + + Expr getRightOperand() { + result = this.(BinaryOpType).getRightOperand() + or + result = this.(AssignBinaryOpType).getRValue() + } + + string getOperator() { + result = this.(BinaryOpType).getOperator() + or + result = this.(AssignBinaryOpType).getOperator() + } + } +} + +/** + * A binary shift operation (`<<` or `>>`). + */ +class BinaryShiftOperation extends BinaryOperation { + BinaryShiftOperation() { + this instanceof LShiftExpr or + this instanceof RShiftExpr + } +} + +/** + * A binary shift assignment operation (`<<=` or `>>=`). + */ +class AssignShiftOperation extends AssignOperation { + AssignShiftOperation() { + this instanceof AssignLShiftExpr or + this instanceof AssignRShiftExpr + } +} + +/** + * A binary bitwise operation or binary bitwise assignment operation, including shift operations. + */ +class BinaryBitwiseOpOrAssignOp = + BinaryOpUnifier::BinaryExpr; + +/** + * A binary shift operation (`<<` or `>>`) or shift assignment operation (`<<=` or `>>=`). + */ +class BinaryShiftOpOrAssignOp = + BinaryOpUnifier::BinaryExpr; + +/** + * A binary arithmetic operation or binary arithmetic assignment operation. + */ +class BinaryArithmeticOpOrAssignOp = + BinaryOpUnifier::BinaryExpr; diff --git a/cpp/common/src/codingstandards/cpp/Bitwise.qll b/cpp/common/src/codingstandards/cpp/Bitwise.qll deleted file mode 100644 index 0e19cae29d..0000000000 --- a/cpp/common/src/codingstandards/cpp/Bitwise.qll +++ /dev/null @@ -1,20 +0,0 @@ -/** - * A library for addressing issues in bitwise operator modelling in our database schema. - */ - -private import cpp as cpp - -module Bitwise { - /** - * A binary bitwise assign operation, excluding += and -= on pointers, which seem to be erroneously - * included. - */ - class AssignBitwiseOperation extends cpp::AssignBitwiseOperation { - AssignBitwiseOperation() { - // exclude += and -= on pointers, which seem to be erroneously included - // in the database schema - not this instanceof cpp::AssignPointerAddExpr and - not this instanceof cpp::AssignPointerSubExpr - } - } -} diff --git a/cpp/common/src/codingstandards/cpp/BuiltInNumericTypes.qll b/cpp/common/src/codingstandards/cpp/BuiltInNumericTypes.qll index b145428a57..b156930810 100644 --- a/cpp/common/src/codingstandards/cpp/BuiltInNumericTypes.qll +++ b/cpp/common/src/codingstandards/cpp/BuiltInNumericTypes.qll @@ -20,3 +20,10 @@ class BuiltInIntegerType extends BuiltInType { class ExcludedVariable extends Parameter { ExcludedVariable() { getFunction() instanceof MainFunction } } + +/** + * Any main function. + */ +class ExcludedFunction extends Function { + ExcludedFunction() { this instanceof MainFunction } +} diff --git a/cpp/common/src/codingstandards/cpp/CStyleCasts.qll b/cpp/common/src/codingstandards/cpp/CStyleCasts.qll new file mode 100644 index 0000000000..b387f9898e --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/CStyleCasts.qll @@ -0,0 +1,18 @@ +import cpp +import codingstandards.cpp.Macro + +/** + * A C-style cast that is explicitly user written and has a known target type. + */ +class ExplicitUserDefinedCStyleCast extends CStyleCast { + ExplicitUserDefinedCStyleCast() { + not this.isImplicit() and + not this.getType() instanceof UnknownType and + // For casts in templates that occur on types related to a template parameter, the copy of th + // cast in the uninstantiated template is represented as a `CStyleCast` even if in practice all + // the instantiations represent it as a `ConstructorCall`. To avoid the common false positive case + // of using the functional cast notation to call a constructor we exclude all `CStyleCast`s on + // uninstantiated templates, and instead rely on reporting results within instantiations. + not this.isFromUninstantiatedTemplate(_) + } +} diff --git a/cpp/common/src/codingstandards/cpp/Call.qll b/cpp/common/src/codingstandards/cpp/Call.qll new file mode 100644 index 0000000000..4edbb454a6 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/Call.qll @@ -0,0 +1,19 @@ +import cpp +import codingstandards.cpp.types.Type +import codingstandards.cpp.types.FunctionType + +/** + * Gets the `FunctionType` of an expression call. + */ +FunctionType getExprCallFunctionType(ExprCall call) { + // A standard expression call + // Returns a FunctionPointerIshType + result = call.(ExprCall).getExpr().getType() + or + // An expression call using the pointer to member operator (.* or ->*) + // This special handling is required because we don't have a CodeQL class representing the call + // to a pointer to member function, but the right hand side is extracted as the -1 child of the + // call. + // Returns a RoutineType + result = call.(ExprCall).getChild(-1).getType().(PointerToMemberType).getBaseType() +} diff --git a/cpp/common/src/codingstandards/cpp/Class.qll b/cpp/common/src/codingstandards/cpp/Class.qll index 418f027809..6f730736f9 100644 --- a/cpp/common/src/codingstandards/cpp/Class.qll +++ b/cpp/common/src/codingstandards/cpp/Class.qll @@ -191,7 +191,13 @@ class TrivialMemberFunction extends IntrospectedMemberFunction { * class. */ class TemplateOrTemplateClassMemberFunction extends MemberFunction { - TemplateOrTemplateClassMemberFunction() { isFromUninstantiatedTemplate(_) } + TemplateOrTemplateClassMemberFunction() { + ( + isFromUninstantiatedTemplate(_) or + isFromTemplateInstantiation(_) + ) and + not this.isCompilerGenerated() + } } /** diff --git a/cpp/common/src/codingstandards/cpp/Clvalues.qll b/cpp/common/src/codingstandards/cpp/Clvalues.qll new file mode 100644 index 0000000000..157041f13b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/Clvalues.qll @@ -0,0 +1,20 @@ +import cpp + +/** + * An lvalue in C (as opposed to C++). + * + * Note that `Expr.isLValue()` matches for C++ lvalues, which is a larger set + * than the set of C lvalues. + */ +predicate isCLValue(Expr expr) { + expr instanceof PointerFieldAccess + or + expr.isLValue() and + not expr instanceof ConditionalExpr and + not expr instanceof AssignExpr and + not expr instanceof CommaExpr and + not exists(Cast c | c = expr.getConversion*()) + or + // 6.5.2.5.4: Compound literals are always lvalues. + expr instanceof AggregateLiteral +} diff --git a/cpp/common/src/codingstandards/cpp/Compatible.qll b/cpp/common/src/codingstandards/cpp/Compatible.qll deleted file mode 100644 index 12a53965fe..0000000000 --- a/cpp/common/src/codingstandards/cpp/Compatible.qll +++ /dev/null @@ -1,26 +0,0 @@ -import cpp - -predicate typesCompatible(Type t1, Type t2) { - t1 = t2 - or - //signed int is same as int ect - t1.(IntegralType).getCanonicalArithmeticType() = t2.(IntegralType).getCanonicalArithmeticType() -} - -predicate parameterTypesIncompatible(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { - exists(ParameterDeclarationEntry p1, ParameterDeclarationEntry p2, int i | - p1 = f1.getParameterDeclarationEntry(i) and - p2 = f2.getParameterDeclarationEntry(i) - | - not typesCompatible(p1.getType(), p2.getType()) - ) -} - -predicate parameterNamesIncompatible(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { - exists(ParameterDeclarationEntry p1, ParameterDeclarationEntry p2, int i | - p1 = f1.getParameterDeclarationEntry(i) and - p2 = f2.getParameterDeclarationEntry(i) - | - not p1.getName() = p2.getName() - ) -} diff --git a/cpp/common/src/codingstandards/cpp/Concurrency.qll b/cpp/common/src/codingstandards/cpp/Concurrency.qll index d856fa4515..3f7e5c1af9 100644 --- a/cpp/common/src/codingstandards/cpp/Concurrency.qll +++ b/cpp/common/src/codingstandards/cpp/Concurrency.qll @@ -1,938 +1,14 @@ import cpp -import codingstandards.cpp.dataflow.TaintTracking - -/** - * Models CFG nodes which should be added to a thread context. - */ -abstract class ThreadedCFGPathExtension extends ControlFlowNode { - /** - * Returns the next `ControlFlowNode` in this thread context. - */ - abstract ControlFlowNode getNext(); -} - -/** - * Models a `FunctionCall` invoked from a threaded context. - */ -class ThreadContextFunctionCall extends FunctionCall, ThreadedCFGPathExtension { - override ControlFlowNode getNext() { getTarget().getEntryPoint() = result } -} - -/** - * Models a specialized `FunctionCall` that may create a thread. - */ -abstract class ThreadCreationFunction extends FunctionCall, ThreadedCFGPathExtension { - /** - * Returns the function that will be invoked. - */ - abstract Function getFunction(); -} - -/** - * Models a call to a thread constructor via `std::thread`. - */ -class ThreadConstructorCall extends ConstructorCall, ThreadCreationFunction { - Function f; - - ThreadConstructorCall() { - getTarget().getDeclaringType().hasQualifiedName("std", "thread") and - f = getArgument(0).(FunctionAccess).getTarget() - } - - /** - * Returns the function that will be invoked by this `std::thread`. - */ - override Function getFunction() { result = f } - - override ControlFlowNode getNext() { result = getFunction().getEntryPoint() } -} - -/** - * Models a call to a thread constructor via `thrd_create`. - */ -class C11ThreadCreateCall extends ThreadCreationFunction { - Function f; - - C11ThreadCreateCall() { - getTarget().getName() = "thrd_create" and - ( - f = getArgument(1).(FunctionAccess).getTarget() or - f = getArgument(1).(AddressOfExpr).getOperand().(FunctionAccess).getTarget() - ) - } - - /** - * Returns the function that will be invoked by this thread. - */ - override Function getFunction() { result = f } - - override ControlFlowNode getNext() { result = getFunction().getEntryPoint() } -} - -/** - * Common base class providing an interface into function call - * based mutex locks. - */ -abstract class MutexFunctionCall extends LockingOperation { - abstract predicate isRecursive(); - - abstract predicate isSpeculativeLock(); - - abstract predicate unlocks(MutexFunctionCall fc); -} - -/** - * Models calls to various mutex types found in CPP. - */ -class CPPMutexFunctionCall extends MutexFunctionCall { - VariableAccess var; - - CPPMutexFunctionCall() { - ( - // the non recursive kinds - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "mutex") or - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "timed_mutex") or - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "shared_timed_mutex") or - // the recursive ones - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "recursive_mutex") or - getTarget() - .(MemberFunction) - .getDeclaringType() - .hasQualifiedName("std", "recursive_timed_mutex") - ) and - var = getQualifier() - } - - /** - * Holds if this mutex is a recursive mutex. - */ - override predicate isRecursive() { - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "recursive_mutex") or - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "recursive_timed_mutex") - } - - /** - * Holds if this `CPPMutexFunctionCall` is a lock. - */ - override predicate isLock() { - not isLockingOperationWithinLockingOperation(this) and - getTarget().getName() = "lock" - } - - /** - * Holds if this `CPPMutexFunctionCall` is a speculative lock, defined as calling - * one of the speculative locking functions such as `try_lock`. - */ - override predicate isSpeculativeLock() { - getTarget().getName() in [ - "try_lock", "try_lock_for", "try_lock_until", "try_lock_shared_for", "try_lock_shared_until" - ] - } - - /** - * Returns the lock to which this `CPPMutexFunctionCall` refers to. - */ - override Variable getLock() { result = getQualifier().(VariableAccess).getTarget() } - - /** - * Returns the qualifier for this `CPPMutexFunctionCall`. - */ - override Expr getLockExpr() { result = var } - - /** - * Holds if this is a `unlock` and *may* unlock the previously locked `MutexFunctionCall`. - * This predicate does not check that the mutex is currently locked. - */ - override predicate unlocks(MutexFunctionCall fc) { - isUnlock() and - fc.getQualifier().(VariableAccess).getTarget() = getQualifier().(VariableAccess).getTarget() - } - - /** - * Holds if this is an unlock call. - */ - override predicate isUnlock() { getTarget().getName() = "unlock" } -} - -/** - * Models calls to various mutex types specialized to C code. - */ -class CMutexFunctionCall extends MutexFunctionCall { - Expr arg; - - CMutexFunctionCall() { - // the non recursive kinds - getTarget().getName() = ["mtx_lock", "mtx_unlock", "mtx_timedlock", "mtx_trylock"] and - arg = getArgument(0) - } - - /** - * Holds if this mutex is a recursive mutex. - */ - override predicate isRecursive() { none() } - - /** - * Holds if this `CMutexFunctionCall` is a lock. - */ - override predicate isLock() { - not isLockingOperationWithinLockingOperation(this) and - getTarget().getName() = ["mtx_lock", "mtx_timedlock", "mtx_trylock"] - } - - /** - * Holds if this `CMutexFunctionCall` is a speculative lock, defined as calling - * one of the speculative locking functions such as `try_lock`. - */ - override predicate isSpeculativeLock() { - getTarget().getName() in ["mtx_timedlock", "mtx_trylock"] - } - - /** - * Returns the `Variable` to which this `CMutexFunctionCall` refers to. For this - * style of lock it can reference a number of different variables. - */ - override Variable getLock() { - exists(VariableAccess va | - TaintTracking::localTaint(DataFlow::exprNode(va), DataFlow::exprNode(getLockExpr())) and - result = va.getTarget() - ) - } - - /** - * Returns the expression for this `CMutexFunctionCall`. - */ - override Expr getLockExpr() { result = arg } - - /** - * Holds if this is a `unlock` and *may* unlock the previously locked `CMutexFunctionCall`. - * This predicate does not check that the mutex is currently locked. - */ - override predicate unlocks(MutexFunctionCall fc) { - isUnlock() and - fc.getLock() = getLock() - } - - /** - * Holds if this is an unlock call. - */ - override predicate isUnlock() { getTarget().getName() = "mtx_unlock" } -} - -/** - * The thread-aware predecessor function is defined in terms of the thread aware - * successor function. This is because it is simpler to construct the forward - * paths of a thread's execution than the backwards paths. For this reason we - * require a `start` and `end` node. - * - * The logic of this function is that a thread aware predecessor is one that - * follows a `start` node, is not equal to the ending node, and does not follow - * the `end` node. Such nodes can only be predecessors of `end`. - * - * For this reason this function requires a `start` node from which to start - * considering something a predecessor of `end`. - */ -pragma[inline] -ControlFlowNode getAThreadContextAwarePredecessor(ControlFlowNode start, ControlFlowNode end) { - result = getAThreadContextAwareSuccessor(start) and - not result = getAThreadContextAwareSuccessor(end) and - not result = end -} - -/** - * A predicate for finding successors of `ControlFlowNode`s that are aware of - * the objects that my flow into a thread's context. This is achieved by adding - * additional edges to thread entry points and function calls. - */ -ControlFlowNode getAThreadContextAwareSuccessorR(ControlFlowNode cfn) { - result = cfn.getASuccessor() - or - result = cfn.(ThreadedCFGPathExtension).getNext() -} - -ControlFlowNode getAThreadContextAwareSuccessor(ControlFlowNode m) { - result = getAThreadContextAwareSuccessorR*(m) and - // for performance reasons we handle back edges by enforcing a lexical - // ordering restriction on these nodes if they are both in - // the same loop. One way of doing this is as follows: - // - // ````and ( - // exists(Loop loop | - // loop.getAChild*() = m and - // loop.getAChild*() = result - // ) - // implies - // not result.getLocation().isBefore(m.getLocation()) - // )``` - // In this implementation we opt for the more generic form below - // which seems to have reasonable performance. - ( - m.getEnclosingStmt().getParentStmt*() = result.getEnclosingStmt().getParentStmt*() - implies - not exists(Location l1, Location l2 | - l1 = result.getLocation() and - l2 = m.getLocation() - | - l1.getEndLine() < l2.getStartLine() - or - l1.getStartLine() = l2.getEndLine() and - l1.getEndColumn() < l2.getStartColumn() - ) - ) -} - -abstract class LockingOperation extends FunctionCall { - /** - * Returns the target of the lock underlying this RAII-style lock. - */ - abstract Variable getLock(); - - /** - * Returns the lock underlying this RAII-style lock. - */ - abstract Expr getLockExpr(); - - /** - * Holds if this is a lock operation - */ - abstract predicate isLock(); - - /** - * Holds if this is an unlock operation - */ - abstract predicate isUnlock(); - - /** - * Holds if this locking operation is really a locking operation within a - * designated locking operation. This library assumes the underlying locking - * operations are implemented correctly in that calling a `LockingOperation` - * results in the creation of a singular lock. - */ - predicate isLockingOperationWithinLockingOperation(LockingOperation inner) { - exists(LockingOperation outer | outer.getTarget() = inner.getEnclosingFunction()) - } -} - -/** - * Models a RAII-Style lock. - */ -class RAIIStyleLock extends LockingOperation { - VariableAccess lock; - Element e; - - RAIIStyleLock() { - ( - getTarget().getDeclaringType().hasQualifiedName("std", "lock_guard") or - getTarget().getDeclaringType().hasQualifiedName("std", "unique_lock") or - getTarget().getDeclaringType().hasQualifiedName("std", "scoped_lock") - ) - } - - /** - * Holds if this is a lock operation - */ - override predicate isLock() { - not isLockingOperationWithinLockingOperation(this) and - this instanceof ConstructorCall and - lock = getArgument(0).getAChild*() and - // defer_locks don't cause a lock - not exists(Expr exp | - exp = getArgument(1) and - exp.(VariableAccess) - .getTarget() - .getUnderlyingType() - .(Class) - .hasQualifiedName("std", "defer_lock_t") - ) - } - - /** - * Holds if this is an unlock operation - */ - override predicate isUnlock() { this instanceof DestructorCall } - - /** - * Returns the target of the lock underlying this RAII-style lock. - */ - override Variable getLock() { result = lock.getTarget() } - - /** - * Returns the lock underlying this RAII-style lock. - */ - override Expr getLockExpr() { result = lock } -} - -/** - * Models a function that may be executed by some thread. - */ -abstract class ThreadedFunction extends Function { } - -/** - * Models a function that may be executed by some thread via - * C++ standard classes. - */ -class CPPThreadedFunction extends ThreadedFunction { - CPPThreadedFunction() { exists(ThreadConstructorCall tcc | tcc.getFunction() = this) } -} - -/** - * Models a function that may be executed by some thread via - * C11 standard functions. - */ -class C11ThreadedFunction extends ThreadedFunction { - C11ThreadedFunction() { exists(C11ThreadCreateCall cc | cc.getFunction() = this) } -} - -/** - * Models a control flow node within a function that may be executed by some - * thread. - */ -class ThreadedCFN extends ControlFlowNode { - ThreadedCFN() { - exists(ThreadedFunction tf | this = getAThreadContextAwareSuccessor(tf.getEntryPoint())) - } -} - -/** - * Models a `ControlFlowNode` that is protected by some sort of lock. - */ -class LockProtectedControlFlowNode extends ThreadedCFN { - FunctionCall lockingFunction; - - LockProtectedControlFlowNode() { - exists(LockingOperation lock | - // there is a node that is a lock - lockingFunction = lock and - lock.isLock() and - // this node should be a successor of this lock - this = getAThreadContextAwareSuccessor(lock) and - // and there should not exist a predecessor of this - // node that is an unlock. Since we are doing thread context - // aware tracking it is easier to go forwards than backwards - // in constructing the call graph. Thus we can define predecessor - // in terms of a node that is a successor of the lock but NOT a - // successor of the current node. - not exists(ControlFlowNode unlock | - // it's an unlock - unlock = getAThreadContextAwarePredecessor(lock, this) and - unlock.(MutexFunctionCall).isUnlock() and - // note that we don't check that it's the same lock -- this is left - // to the caller to enforce this condition. - // Because of the way that `getAThreadContextAwarePredecessor` works, it is possible - // for operations PAST it to be technically part of the predecessors. - // Thus, we need to make sure that this node is a - // successor of the unlock in the CFG - getAThreadContextAwareSuccessor(unlock) = this - ) and - (lock instanceof MutexFunctionCall implies not this.(MutexFunctionCall).isUnlock()) - ) - } - - /** - * The `MutexFunctionCall` holding the lock that locks this node. - */ - FunctionCall coveredByLock() { result = lockingFunction } - - /** - * The lock underlying this `LockProtectedControlFlowNode`. - */ - Variable getAProtectingLock() { result = lockingFunction.(LockingOperation).getLock() } -} - -/** - * Models a function that conditionally waits. - */ -abstract class ConditionalWait extends FunctionCall { } - -/** - * Models a function in CPP that will conditionally wait. - */ -class CPPConditionalWait extends ConditionalWait { - CPPConditionalWait() { - exists(MemberFunction mf | - mf = getTarget() and - mf.getDeclaringType().hasQualifiedName("std", "condition_variable") and - mf.getName() in ["wait", "wait_for", "wait_until"] - ) - } -} - -/** - * Models a function in C that will conditionally wait. - */ -class CConditionalWait extends ConditionalWait { - CConditionalWait() { getTarget().getName() in ["cnd_wait"] } -} - -/** - * Models a call to a `std::thread` constructor that depends on a mutex. - */ -class MutexDependentThreadConstructor extends ThreadConstructorCall { - Expr mutexExpr; - - MutexDependentThreadConstructor() { - mutexExpr = getAnArgument() and - mutexExpr.getUnderlyingType().stripType() instanceof MutexType - } - - Expr dependentMutex() { result = mutexExpr } -} - -/** - * Models thread waiting functions. - */ -abstract class ThreadWait extends FunctionCall { } - -/** - * Models a call to a `std::thread` join. - */ -class CPPThreadWait extends ThreadWait { - VariableAccess var; - - CPPThreadWait() { - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "thread") and - getTarget().getName() = "join" - } -} - -/** - * Models a call to `thrd_join` in C11. - */ -class C11ThreadWait extends ThreadWait { - VariableAccess var; - - C11ThreadWait() { getTarget().getName() = "thrd_join" } -} - -/** - * Models thread detach functions. - */ -abstract class ThreadDetach extends FunctionCall { } - -/** - * Models a call to `thrd_detach` in C11. - */ -class C11ThreadDetach extends ThreadWait { - VariableAccess var; - - C11ThreadDetach() { getTarget().getName() = "thrd_detach" } -} - -abstract class MutexSource extends FunctionCall { } - -/** - * Models a C++ style mutex. - */ -class CPPMutexSource extends MutexSource, ConstructorCall { - CPPMutexSource() { getTarget().getDeclaringType().hasQualifiedName("std", "mutex") } -} - -/** - * Models a C11 style mutex. - */ -class C11MutexSource extends MutexSource, FunctionCall { - C11MutexSource() { getTarget().hasName("mtx_init") } -} - -/** - * Models a thread dependent mutex. A thread dependent mutex is a mutex - * that is used by a thread. This dependency is established either by directly - * passing in a mutex or by referencing a mutex that is in the local scope. The utility - * of this class is it captures the `DataFlow::Node` source at which the mutex - * came from. For example, if it is passed in from a local function to a thread. - * This functionality is critical, since it allows one to inspect how the thread - * behaves with respect to the owner of a resource. - * - * To model the myriad ways this can happen, the subclasses of this class are - * responsible for implementing the various usage patterns. - */ -abstract class ThreadDependentMutex extends DataFlow::Node { - DataFlow::Node sink; - - DataFlow::Node getASource() { - // the source is either the thing that declared - // the mutex - result = this - or - // or the thread we are using it in - result = getAThreadSource() - } - - /** - * Gets the dataflow nodes corresponding to thread local usages of the - * dependent mutex. - */ - DataFlow::Node getAThreadSource() { - // here we line up the actual parameter at the thread creation - // site with the formal parameter in the target thread. - // Note that there are differences between the C and C++ versions - // of the argument ordering in the thread creation function. However, - // since the C version only takes one parameter (as opposed to multiple) - // we can simplify this search by considering only the first argument. - exists(FunctionCall fc, Function f, int n | - // Get the argument to which the mutex flowed. - fc.getArgument(n) = sink.asExpr() and - // Get the thread function we are calling. - f = fc.getArgument(0).(FunctionAccess).getTarget() and - // in C++, there is an extra argument to the `std::thread` call - // so we must subtract 1 since this is not passed to the thread. - ( - result = DataFlow::exprNode(f.getParameter(n - 1).getAnAccess()) - or - // In C, only one argument is allowed. Thus IF the flow predicate holds, - // it will be to the first argument - result = DataFlow::exprNode(f.getParameter(0).getAnAccess()) - ) - ) - } - - /** - * Produces the set of dataflow nodes to thread creation for threads - * that are dependent on this mutex. - */ - DataFlow::Node getADependentThreadCreationExpr() { - exists(FunctionCall fc | - fc.getAnArgument() = sink.asExpr() and - result = DataFlow::exprNode(fc) - ) - } - - /** - * Gets a set of usages of this mutex in both the local and thread scope. - * In the case of scoped usage, this also captures typical accesses of variables. - */ - DataFlow::Node getAUsage() { TaintTracking::localTaint(getASource(), result) } -} - -/** - * This class models the type of thread/mutex dependency that is established - * through the typical parameter passing mechanisms found in C++. - */ -class FlowBasedThreadDependentMutex extends ThreadDependentMutex { - FlowBasedThreadDependentMutex() { - // some sort of dataflow, likely through parameter passing. - ThreadDependentMutexFlow::flow(this, sink) - } -} - -/** - * This class models the type of thread/mutex dependency that is established by - * either scope based accesses (e.g., global variables) or block scope differences. - */ -class AccessBasedThreadDependentMutex extends ThreadDependentMutex { - Variable variableSource; - - AccessBasedThreadDependentMutex() { - // encapsulates usages from outside scopes not directly expressed - // in dataflow. - exists(MutexSource mutexSrc, ThreadedFunction f | - DataFlow::exprNode(mutexSrc) = this and - // find a variable that was assigned the mutex - TaintTracking::localTaint(DataFlow::exprNode(mutexSrc), - DataFlow::exprNode(variableSource.getAnAssignedValue())) and - // find all subsequent accesses of that variable that are within a - // function and set those to the sink - exists(VariableAccess va | - va = variableSource.getAnAccess() and - va.getEnclosingFunction() = f and - sink = DataFlow::exprNode(va) - ) - ) - } - - override DataFlow::Node getAUsage() { DataFlow::exprNode(variableSource.getAnAccess()) = result } -} - -/** - * In the typical C thread model, a mutex is a created by a function that is not responsible - * for creating the variable. Thus this class encodes a slightly different semantics - * wherein the usage pattern is that of variables that have been both initialized - * and then subsequently passed into a thread directly. - */ -class DeclarationInitBasedThreadDependentMutex extends ThreadDependentMutex { - Variable variableSource; - - DeclarationInitBasedThreadDependentMutex() { - exists(MutexSource ms, ThreadCreationFunction tcf | - this = DataFlow::exprNode(ms) and - // accessed as a mutex source - TaintTracking::localTaint(DataFlow::exprNode(variableSource.getAnAccess()), - DataFlow::exprNode(ms.getAnArgument())) and - // subsequently passed to a thread creation function (order not strictly - // enforced for performance reasons) - sink = DataFlow::exprNode(tcf.getAnArgument()) and - TaintTracking::localTaint(DataFlow::exprNode(variableSource.getAnAccess()), sink) - ) - } - - override DataFlow::Node getAUsage() { - TaintTracking::localTaint(getASource(), result) or - DataFlow::exprNode(variableSource.getAnAccess()) = result - } - - override DataFlow::Node getASource() { - // the source is either the thing that declared - // the mutex - result = this - or - // or the thread we are using it in - result = getAThreadSource() - } - - DataFlow::Node getSink() { result = sink } - - /** - * Gets the dataflow nodes corresponding to thread local usages of the - * dependent mutex. - */ - override DataFlow::Node getAThreadSource() { - // here we line up the actual parameter at the thread creation - // site with the formal parameter in the target thread. - // Note that there are differences between the C and C++ versions - // of the argument ordering in the thread creation function. However, - // since the C version only takes one parameter (as opposed to multiple) - // we can simplify this search by considering only the first argument. - exists( - FunctionCall fc, Function f, int n // CPP Version - | - fc.getArgument(n) = sink.asExpr() and - f = fc.getArgument(0).(FunctionAccess).getTarget() and - // in C++, there is an extra argument to the `std::thread` call - // so we must subtract 1 since this is not passed to the thread. - result = DataFlow::exprNode(f.getParameter(n - 1).getAnAccess()) - ) - or - exists( - FunctionCall fc, Function f // C Version - | - fc.getAnArgument() = sink.asExpr() and - // in C, the second argument is the function - f = fc.getArgument(1).(FunctionAccess).getTarget() and - // in C, the passed argument is always the zeroth argument - result = DataFlow::exprNode(f.getParameter(0).getAnAccess()) - ) - } -} - -/** - * In the typical C model, another way to use mutexes is to work with global variables - * that can be initialized at various points -- one of which must be inside a thread. - * This class encapsulates this pattern. - */ -class DeclarationInitAccessBasedThreadDependentMutex extends ThreadDependentMutex { - Variable variableSource; - - DeclarationInitAccessBasedThreadDependentMutex() { - exists(MutexSource ms, ThreadedFunction tf, VariableAccess va | - this = DataFlow::exprNode(ms) and - // accessed as a mutex source - TaintTracking::localTaint(DataFlow::exprNode(variableSource.getAnAccess()), - DataFlow::exprNode(ms.getAnArgument())) and - // is accessed somewhere else - va = variableSource.getAnAccess() and - sink = DataFlow::exprNode(va) and - // one of which must be a thread - va.getEnclosingFunction() = tf - ) - } - - override DataFlow::Node getAUsage() { result = DataFlow::exprNode(variableSource.getAnAccess()) } -} - -module ThreadDependentMutexConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node node) { node.asExpr() instanceof MutexSource } - - predicate isSink(DataFlow::Node node) { - exists(ThreadCreationFunction f | f.getAnArgument() = node.asExpr()) - } -} - -module ThreadDependentMutexFlow = TaintTracking::Global; - -/** - * Models expressions that destroy mutexes. - */ -abstract class MutexDestroyer extends StmtParent { - /** - * Gets the expression that references the mutex being destroyed. - */ - abstract Expr getMutexExpr(); -} - -/** - * Models C style mutex destruction via `mtx_destroy`. - */ -class C11MutexDestroyer extends MutexDestroyer, FunctionCall { - C11MutexDestroyer() { getTarget().getName() = "mtx_destroy" } - - /** - * Returns the `Expr` being destroyed. - */ - override Expr getMutexExpr() { result = getArgument(0) } -} - -/** - * Models a delete expression -- note it is necessary to add this in - * addition to destructors to handle certain implementations of the - * standard library which obscure the destructors of mutexes. - */ -class DeleteMutexDestroyer extends MutexDestroyer { - DeleteMutexDestroyer() { this instanceof DeleteExpr } - - override Expr getMutexExpr() { this.(DeleteExpr).getExpr() = result } -} - -/** - * Models a possible mutex variable that if it goes - * out of scope would destroy an underlying mutex. - */ -class LocalMutexDestroyer extends MutexDestroyer { - Expr assignedValue; - - LocalMutexDestroyer() { - exists(LocalVariable lv | - // static types aren't destroyers - not lv.isStatic() and - // neither are pointers - not lv.getType() instanceof PointerType and - lv.getAnAssignedValue() = assignedValue and - // map the location to the return statements of the - // enclosing function - exists(ReturnStmt rs | - rs.getEnclosingFunction() = assignedValue.getEnclosingFunction() and - rs = this - ) - ) - } - - override Expr getMutexExpr() { result = assignedValue } -} - -/** - * Models implicit or explicit calls to the destructor of a mutex, either via - * a `delete` statement or a variable going out of scope. - */ -class DestructorMutexDestroyer extends MutexDestroyer, DestructorCall { - DestructorMutexDestroyer() { getTarget().getDeclaringType().hasQualifiedName("std", "mutex") } - - /** - * Returns the `Expr` being deleted. - */ - override Expr getMutexExpr() { getQualifier() = result } -} - -/** - * Models a conditional variable denoted by `std::condition_variable`. - */ -class ConditionalVariable extends Variable { - ConditionalVariable() { - getUnderlyingType().(Class).hasQualifiedName("std", "condition_variable") - } -} - -/** - * Models a conditional function, which is a function that depends on the value - * of a conditional variable. - */ -class ConditionalFunction extends Function { - ConditionalFunction() { - exists(ConditionalVariable cv | cv.getAnAccess().getEnclosingFunction() = this) - } -} - -/** - * Models calls to thread specific storage function calls. - */ -abstract class ThreadSpecificStorageFunctionCall extends FunctionCall { - /** - * Gets the key to which this call references. - */ - Expr getKey() { getArgument(0) = result } -} - -/** - * Models calls to `tss_get`. - */ -class TSSGetFunctionCall extends ThreadSpecificStorageFunctionCall { - TSSGetFunctionCall() { getTarget().getName() = "tss_get" } -} - -/** - * Models calls to `tss_set`. - */ -class TSSSetFunctionCall extends ThreadSpecificStorageFunctionCall { - TSSSetFunctionCall() { getTarget().getName() = "tss_set" } -} - -/** - * Models calls to `tss_create` - */ -class TSSCreateFunctionCall extends ThreadSpecificStorageFunctionCall { - TSSCreateFunctionCall() { getTarget().getName() = "tss_create" } - - predicate hasDeallocator() { - not exists(MacroInvocation mi, NullMacro nm | - getArgument(1) = mi.getExpr() and - mi = nm.getAnInvocation() - ) - } -} - -/** - * Models calls to `tss_delete` - */ -class TSSDeleteFunctionCall extends ThreadSpecificStorageFunctionCall { - TSSDeleteFunctionCall() { getTarget().getName() = "tss_delete" } -} - -/** - * Gets a call to `DeallocationExpr` that deallocates memory owned by thread specific - * storage. - */ -predicate getAThreadSpecificStorageDeallocationCall(C11ThreadCreateCall tcc, DeallocationExpr dexp) { - exists(TSSGetFunctionCall tsg | - tcc.getFunction().getEntryPoint().getASuccessor*() = tsg and - DataFlow::localFlow(DataFlow::exprNode(tsg), DataFlow::exprNode(dexp.getFreedExpr())) - ) -} - -/** - * Models calls to routines `atomic_compare_exchange_weak` and - * `atomic_compare_exchange_weak_explicit` in the `stdatomic` library. - * Note that these are typically implemented as macros within Clang and - * GCC's standard libraries. - */ -class AtomicCompareExchange extends MacroInvocation { - AtomicCompareExchange() { - getMacroName() = "atomic_compare_exchange_weak" - or - // some compilers model `atomic_compare_exchange_weak` as a macro that - // expands to `atomic_compare_exchange_weak_explicit` so this defeats that - // and other similar modeling. - getMacroName() = "atomic_compare_exchange_weak_explicit" and - not exists(MacroInvocation m | - m.getMacroName() = "atomic_compare_exchange_weak" and - m.getAnExpandedElement() = getAnExpandedElement() - ) - } -} - -/** - * Models calls to routines `atomic_store` and - * `atomic_store_explicit` in the `stdatomic` library. - * Note that these are typically implemented as macros within Clang and - * GCC's standard libraries. - */ -class AtomicStore extends MacroInvocation { - AtomicStore() { - getMacroName() = "atomic_store" - or - // some compilers model `atomic_compare_exchange_weak` as a macro that - // expands to `atomic_compare_exchange_weak_explicit` so this defeats that - // and other similar modeling. - getMacroName() = "atomic_store_explicit" and - not exists(MacroInvocation m | - m.getMacroName() = "atomic_store" and - m.getAnExpandedElement() = getAnExpandedElement() - ) - } -} +import codingstandards.cpp.concurrency.Atomic +import codingstandards.cpp.concurrency.CConditionOperation +import codingstandards.cpp.concurrency.ControlFlow +import codingstandards.cpp.concurrency.ConditionalWait +import codingstandards.cpp.concurrency.LockingOperation +import codingstandards.cpp.concurrency.LockProtectedControlFlow +import codingstandards.cpp.concurrency.MutexDestroyer +import codingstandards.cpp.concurrency.ThreadCreation +import codingstandards.cpp.concurrency.ThreadedFunction +import codingstandards.cpp.concurrency.ThreadDependentMutex +import codingstandards.cpp.concurrency.ThreadSpecificStorage +import codingstandards.cpp.concurrency.ThreadWaitDetach +import codingstandards.cpp.concurrency.Types diff --git a/cpp/common/src/codingstandards/cpp/ConstHelpers.qll b/cpp/common/src/codingstandards/cpp/ConstHelpers.qll index 8cba3efde4..a3d12fd127 100644 --- a/cpp/common/src/codingstandards/cpp/ConstHelpers.qll +++ b/cpp/common/src/codingstandards/cpp/ConstHelpers.qll @@ -4,7 +4,7 @@ import cpp import codingstandards.cpp.SideEffect -import codingstandards.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.FunctionParameter /** A variable that can be modified (both the pointer and object pointed to if pointer type) */ diff --git a/cpp/common/src/codingstandards/cpp/ConstantExpressions.qll b/cpp/common/src/codingstandards/cpp/ConstantExpressions.qll new file mode 100644 index 0000000000..f6c0863e54 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/ConstantExpressions.qll @@ -0,0 +1,97 @@ +import cpp + +final private class FinalExpr = Expr; + +/** + * An integer constant expression as defined by the C++17 standard. + */ +class IntegerConstantExpr extends FinalExpr { + IntegerConstantExpr() { + // An integer constant expression is a constant expression that has an + // integral type. + this.isConstant() and + exists(Type unspecifiedType | unspecifiedType = this.getUnspecifiedType() | + unspecifiedType instanceof IntegralType + or + // Unscoped enum type + unspecifiedType instanceof Enum and + not unspecifiedType instanceof ScopedEnum + ) + } + + /** + * Gets the value of this integer constant expression. + * + * This is only defined for expressions that are constant expressions, and + * that have a value that can be represented as a `BigInt`. + */ + QlBuiltins::BigInt getConstantValue() { + if exists(getPreConversionConstantValue()) + then result = getPreConversionConstantValue() + else result = this.getValue().toBigInt() + } + + /** + * Gets the pre-conversion constant value of this integer constant expression, if it is different + * from `getValue()`. + * + * This is required because `Expr.getValue()` returns the _converted constant expression value_ + * for non-literal constant expressions, which is the expression value after conversions have been + * applied, but for validating conversions we need the _pre-conversion constant expression value_. + */ + private QlBuiltins::BigInt getPreConversionConstantValue() { + // Access of a variable that has a constant initializer + result = + this.(VariableAccess) + .getTarget() + .getInitializer() + .getExpr() + .getFullyConverted() + .getValue() + .toBigInt() + or + result = this.(EnumConstantAccess).getTarget().getValue().toBigInt() + or + result = -this.(UnaryMinusExpr).getOperand().getFullyConverted().getValue().toBigInt() + or + result = this.(UnaryPlusExpr).getOperand().getFullyConverted().getValue().toBigInt() + or + result = this.(ComplementExpr).getOperand().getFullyConverted().getValue().toBigInt().bitNot() + or + exists(BinaryOperation op, QlBuiltins::BigInt left, QlBuiltins::BigInt right | + op = this and + left = op.getLeftOperand().getFullyConverted().getValue().toBigInt() and + right = op.getRightOperand().getFullyConverted().getValue().toBigInt() + | + op instanceof AddExpr and + result = left + right + or + op instanceof SubExpr and + result = left - right + or + op instanceof MulExpr and + result = left * right + or + op instanceof DivExpr and + result = left / right + or + op instanceof RemExpr and + result = left % right + or + op instanceof BitwiseAndExpr and + result = left.bitAnd(right) + or + op instanceof BitwiseOrExpr and + result = left.bitOr(right) + or + op instanceof BitwiseXorExpr and + result = left.bitXor(right) + or + op instanceof RShiftExpr and + result = left.bitShiftRightSigned(right.toInt()) + or + op instanceof LShiftExpr and + result = left.bitShiftLeft(right.toInt()) + ) + } +} diff --git a/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll b/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll index c974ec7eb8..ca3a7fb251 100644 --- a/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll +++ b/cpp/common/src/codingstandards/cpp/Cpp14Literal.qll @@ -9,6 +9,9 @@ module Cpp14Literal { /** An numeric literal. */ abstract class NumericLiteral extends StandardLibrary::Literal { } + /** Convenience for implementing class `UnrecognizedNumericLiteral` */ + abstract private class RecognizedNumericLiteral extends StandardLibrary::Literal { } + /** An integer literal. */ abstract class IntegerLiteral extends NumericLiteral { predicate isSigned() { not isUnsigned() } @@ -23,7 +26,7 @@ module Cpp14Literal { * ``` * Octal literals must always start with the digit `0`. */ - class OctalLiteral extends IntegerLiteral { + class OctalLiteral extends IntegerLiteral, RecognizedNumericLiteral { OctalLiteral() { getValueText().regexpMatch("\\s*0[0-7']*[uUlL]*\\s*") } override string getAPrimaryQlClass() { result = "OctalLiteral" } @@ -35,7 +38,7 @@ module Cpp14Literal { * unsigned int32_t minus2 = 0xfffffffe; * ``` */ - class HexLiteral extends IntegerLiteral { + class HexLiteral extends IntegerLiteral, RecognizedNumericLiteral { HexLiteral() { getValueText().regexpMatch("\\s*0[xX][0-9a-fA-F']+[uUlL]*\\s*") } override string getAPrimaryQlClass() { result = "HexLiteral" } @@ -47,7 +50,7 @@ module Cpp14Literal { * unsigned int32_t binary = 0b101010; * ``` */ - class BinaryLiteral extends IntegerLiteral { + class BinaryLiteral extends IntegerLiteral, RecognizedNumericLiteral { BinaryLiteral() { getValueText().regexpMatch("\\s*0[bB][0-1']*[uUlL]*\\s*") } override string getAPrimaryQlClass() { result = "BinaryLiteral" } @@ -59,7 +62,7 @@ module Cpp14Literal { * unsigned int32_t decimal = 10340923; * ``` */ - class DecimalLiteral extends IntegerLiteral { + class DecimalLiteral extends IntegerLiteral, RecognizedNumericLiteral { DecimalLiteral() { getValueText().regexpMatch("\\s*[1-9][0-9']*[uUlL]*\\s*") } override string getAPrimaryQlClass() { result = "DecimalLiteral" } @@ -71,7 +74,7 @@ module Cpp14Literal { * double floating = 1.340923e-19; * ``` */ - class FloatingLiteral extends NumericLiteral { + class FloatingLiteral extends NumericLiteral, RecognizedNumericLiteral { FloatingLiteral() { getValueText().regexpMatch("\\s*[0-9][0-9']*(\\.[0-9']+)?([eE][\\+\\-]?[0-9']+)?[flFL]?\\s*") and // A decimal literal takes precedent @@ -83,6 +86,21 @@ module Cpp14Literal { override string getAPrimaryQlClass() { result = "FloatingLiteral" } } + /** + * Literal values with conversions and macros cannot always be trivially + * parsed from `Literal.getValueText()`, and have loss of required + * information in `Literal.getValue()`. This class covers cases that appear + * to be `NumericLiteral`s but cannot be determined to be a hex, decimal, + * octal, binary, or float literal, but still are parsed as a Literal with a + * number value. + */ + class UnrecognizedNumericLiteral extends NumericLiteral { + UnrecognizedNumericLiteral() { + this.getValue().regexpMatch("[0-9.e]+") and + not this instanceof RecognizedNumericLiteral + } + } + /** * A character literal. For example: * ``` diff --git a/cpp/common/src/codingstandards/cpp/Emergent.qll b/cpp/common/src/codingstandards/cpp/Emergent.qll index 9036c12bd7..30f1df58e4 100644 --- a/cpp/common/src/codingstandards/cpp/Emergent.qll +++ b/cpp/common/src/codingstandards/cpp/Emergent.qll @@ -6,44 +6,10 @@ import cpp module C11 { abstract class EmergentLanguageFeature extends Element { } - class AlignAsAttribute extends EmergentLanguageFeature, Attribute { - AlignAsAttribute() { getName() = "_Alignas" } - } - - class AtomicVariableSpecifier extends EmergentLanguageFeature, Variable { - AtomicVariableSpecifier() { - getType().(DerivedType).getBaseType*().getASpecifier().getName() = "atomic" - } - } - - class AtomicDeclaration extends EmergentLanguageFeature, Declaration { - AtomicDeclaration() { getASpecifier().getName() = "atomic" } - } - - class ThreadLocalDeclaration extends EmergentLanguageFeature, Declaration { - ThreadLocalDeclaration() { getASpecifier().getName() = "is_thread_local" } - } - - class EmergentHeader extends EmergentLanguageFeature, Include { - EmergentHeader() { - getIncludedFile().getBaseName() = ["stdalign.h", "stdatomic.h", "stdnoreturn.h", "threads.h"] - } - } - class LibExt1Macro extends EmergentLanguageFeature, Macro { LibExt1Macro() { getName() = "__STDC_WANT_LIB_EXT1__" and getBody() = "1" } } - - class GenericMacro extends EmergentLanguageFeature, Macro { - GenericMacro() { getBody().indexOf("_Generic") = 0 } - } - - class NoReturnSpecificer extends EmergentLanguageFeature, Function { - NoReturnSpecificer() { getASpecifier().getName() = "noreturn" } - } - - class AlignOf extends EmergentLanguageFeature, AlignofTypeOperator { } } diff --git a/cpp/common/src/codingstandards/cpp/EncapsulatingFunctions.qll b/cpp/common/src/codingstandards/cpp/EncapsulatingFunctions.qll index d8d9739033..559c04ce98 100644 --- a/cpp/common/src/codingstandards/cpp/EncapsulatingFunctions.qll +++ b/cpp/common/src/codingstandards/cpp/EncapsulatingFunctions.qll @@ -3,6 +3,7 @@ */ import cpp +import codingstandards.cpp.Class /** A function which represents the entry point into a specific thread of execution in the program. */ abstract class MainLikeFunction extends Function { } @@ -14,7 +15,38 @@ abstract class EncapsulatingFunction extends Function { } class MainFunction extends MainLikeFunction { MainFunction() { hasGlobalName("main") and - getType() instanceof IntType + getType().resolveTypedefs() instanceof IntType + } +} + +/** + * A test function from the GoogleTest infrastructure. + * + * Such functions can be treated as valid EntryPoint functions during analysis + * of "called" or "unused" functions. It is not straightforward to identify + * such functions, however, they have certain features that can be used for + * identification. This can be refined based on experiments/real-world use. + */ +class GoogleTestFunction extends MainLikeFunction { + GoogleTestFunction() { + // A GoogleTest function is named "TestBody" and + ( + this.hasName("TestBody") or + this instanceof SpecialMemberFunction + ) and + // it's parent class inherits a base class + exists(Class base | + base = this.getEnclosingAccessHolder+().(Class).getABaseClass+() and + ( + // with a name "Test" inside a namespace called "testing" + base.hasName("Test") and + base.getNamespace().hasName("testing") + or + // or at a location in a file called gtest.h (or gtest-internal.h, + // gtest-typed-test.h etc). + base.getDefinitionLocation().getFile().getBaseName().regexpMatch("gtest*.h") + ) + ) } } diff --git a/cpp/common/src/codingstandards/cpp/Exclusions.qll b/cpp/common/src/codingstandards/cpp/Exclusions.qll index b718f6535d..e6a477b220 100644 --- a/cpp/common/src/codingstandards/cpp/Exclusions.qll +++ b/cpp/common/src/codingstandards/cpp/Exclusions.qll @@ -35,19 +35,14 @@ predicate isExcluded(Element e, Query query, string reason) { ) and reason = "Query has an associated deviation record for the element's file." or - // The element is on the same line as a suppression comment - exists(Comment c | - c = dr.getACodeIdentifierComment() and - query = dr.getQuery() - | - exists(string filepath, int endLine | - // Comment occurs on the same line as the end line of the element - e.getLocation().hasLocationInfo(filepath, _, _, endLine, _) and - c.getLocation().hasLocationInfo(filepath, endLine, _, _, _) - ) - ) and - reason = - "Query has an associated deviation record with a code identifier that is applied to the element." + // The element is annotated by a code identifier that deviates this rule + exists(CodeIdentifierDeviation deviationInCode | + dr.getQuery() = query and + deviationInCode = dr.getACodeIdentifierDeviation() and + deviationInCode.isElementMatching(e) and + reason = + "Query has an associated deviation record with a code identifier that is applied to the element." + ) ) or // The effective category of the query is 'Disapplied'. diff --git a/cpp/common/src/codingstandards/cpp/Expr.qll b/cpp/common/src/codingstandards/cpp/Expr.qll index fe2877f849..54ba86c5b7 100644 --- a/cpp/common/src/codingstandards/cpp/Expr.qll +++ b/cpp/common/src/codingstandards/cpp/Expr.qll @@ -1,4 +1,5 @@ import cpp +private import semmle.code.cpp.dataflow.DataFlow private import semmle.code.cpp.valuenumbering.GlobalValueNumbering import codingstandards.cpp.AccessPath @@ -148,9 +149,9 @@ module MisraExpr { private predicate isCValue(Expr e) { not e.isConstant() and ( - exists(ReturnStmt return | e = return.getExpr()) + exists(ReturnStmt return | e = return.getExpr().getExplicitlyConverted()) or - exists(Call call | e = call.getAnArgument()) + exists(FunctionCall call | e = call.getAnArgument().getExplicitlyConverted()) ) or isCValue(e.(ParenthesisExpr).getExpr()) @@ -267,7 +268,9 @@ predicate isCompileTimeEvaluatedCall(Call call) { parameterUsingDefaultValue.getAnAssignedValue() = defaultValue | isDirectCompileTimeEvaluatedExpression(defaultValue) - ) + ) and + // 4. the call's qualifier is compile time evaluated. + (not call.hasQualifier() or isCompileTimeEvaluatedExpression(call.getQualifier())) } /* diff --git a/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll b/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll index 7686714635..026fd93045 100644 --- a/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll +++ b/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll @@ -4,7 +4,7 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.controlflow.Guards /* diff --git a/cpp/common/src/codingstandards/cpp/FloatingPoint.qll b/cpp/common/src/codingstandards/cpp/FloatingPoint.qll new file mode 100644 index 0000000000..e2a13bd62e --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/FloatingPoint.qll @@ -0,0 +1,413 @@ +import codeql.util.Boolean +import codingstandards.cpp.RestrictedRangeAnalysis +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis as SimpleRangeAnalysis + +predicate exprMayEqualZero(Expr e) { + RestrictedRangeAnalysis::upperBound(e) >= 0 and + RestrictedRangeAnalysis::lowerBound(e) <= 0 and + not guardedNotEqualZero(e) +} + +newtype TFPClassification = + TFinite() or + TNaN() or + TInfinite() + +class FPClassification extends TFPClassification { + string toString() { + this = TFinite() and + result = "finite" + or + this = TNaN() and + result = "NaN" + or + this = TInfinite() and + result = "infinite" + } +} + +newtype TFPClassificationConstraint = + /* The value may be infinite, NaN, or finite. */ + TUnclassified() or + /** + * The value must be one of: infinite, NaN, or finite. + * + * If strict is `true` then this inverts naively. For example, `!isfinite(x)` means `x` must not + * be finite. However, `!iszero(x)` is true for some finite values, and inverts to + * `TUnclassified`. + */ + TExactFPClassification(TFPClassification cls, Boolean strict) or + /* The value must not be one of: infinite, NaN, or finite. */ + TExcludeFPClassification(TFPClassification cls1) + +class FPClassificationConstraint extends TFPClassificationConstraint { + string toString() { + this = TUnclassified() and + result = "unclassified" + or + exists(FPClassification cls, Boolean strict | + this = TExactFPClassification(cls, strict) and + result = "must be " + cls.toString() + ", strict: " + strict.toString() + or + this = TExcludeFPClassification(cls) and + result = "must NOT be " + cls.toString() + ) + } + + /** + * Invert the constraint, for instance, "must be finite" becomes "must not be finite". + * + * Non-strict exact constraints are inverted to the unclassified constraint. For example, + * `iszero(x)` guarantees `x` to be finite, however, `!iszero(x)` can be true for all three + * classes of floating point values. + * + * The unclassified constraint inverts to itself. + */ + FPClassificationConstraint invert() { + // Unclassified inverts to itself. + this = TUnclassified() and result = this + or + exists(FPClassification cls | + // `!isfinite()` implies is infinite or NaN. + this = TExactFPClassification(cls, true) and + result = TExcludeFPClassification(cls) + or + // `!iszero()` implies nothing. + this = TExactFPClassification(cls, false) and + result = TUnclassified() + or + // For completeness: `!isfinite(x) ? ... : x` would imply `isfinite(x)`. + this = TExcludeFPClassification(cls) and + result = TExactFPClassification(cls, true) + ) + } + + /** + * Naively invert the constraint, for instance, "must be finite" becomes "must not be finite". + * + * Word of caution: inverting a guard condition does not necessarily invert the constraint. For + * example, `iszero(x)` guarantees `x` to be finite, however, `isnotzero(x)` does not guarantee + * `x` not to be finite. + * + * The unclassified constraint is not inverted. + */ + FPClassificationConstraint naiveInversion() { + this = TUnclassified() and result = this + or + exists(FPClassification cls | + this = TExactFPClassification(cls, _) and + result = TExcludeFPClassification(cls) + or + this = TExcludeFPClassification(cls) and + result = TExactFPClassification(cls, true) + ) + } + + predicate mustBe(FPClassification cls) { this = TExactFPClassification(cls, _) } + + predicate mustNotBe(FPClassification cls) { + this = TExcludeFPClassification(cls) + or + this = TExactFPClassification(_, _) and + not this = TExactFPClassification(cls, _) + } + + predicate mayBe(FPClassification cls) { not mustNotBe(cls) } +} + +/** + * The names of the functions or macros that classify floating point values. + * + * These names reflect a check that a value is finite, or infinite, or NaN. Finite and NaN checks + * are either strict (return true for all values in the class) or not (return true for some + * values). + * + * The infinite check is always strict, and specially, returns 1 or -1 for positive or negative + * infinity. + */ +newtype TFPClassifierName = + TClassifiesFinite(string name, boolean strict) { + strict = true and + name = ["finite" + ["", "l", "f"], "isfinite"] + or + strict = false and + name = ["isnormal", "issubnormal", "iszero"] + } or + TClassifiesNaN(string name, boolean strict) { + strict = true and + name = "isnan" + ["", "f", "l"] + or + strict = false and + name = "issignaling" + } or + TClassifiesInfinite(string name) { name = "isinf" + ["", "f", "l"] } + +class FPClassifierName extends TFPClassifierName { + string name; + boolean strict; + + FPClassifierName() { + this = TClassifiesFinite(name, strict) + or + this = TClassifiesInfinite(name) and + strict = true + or + this = TClassifiesNaN(name, strict) + } + + string toString() { result = name } + + /** The classification name, for instance, "isfinite". */ + string getName() { result = name } + + /** + * Whether the check holds for all values in the class, or only some. + * + * For instance, "isfinite" is strict because it returns true for all finite values, but + * "isnormal" is not as it returns false for some finite values. + */ + predicate isStrict() { strict = true } + + FPClassificationConstraint getConstraint() { + this = TClassifiesFinite(_, strict) and + result = TExactFPClassification(any(TFinite t), strict) + or + this = TClassifiesNaN(_, strict) and + result = TExactFPClassification(any(TNaN t), strict) + or + this = TClassifiesInfinite(_) and + // TODO: isinf() is special + result = TExactFPClassification(any(TInfinite t), false) + } +} + +/** + * An invocation of a classification function, for instance, "isfinite(x)", implemented as a macro. + */ +class FPClassifierMacroInvocation extends MacroInvocation { + FPClassifierName classifier; + + FPClassifierMacroInvocation() { getMacroName() = classifier.getName() } + + Expr getCheckedExpr() { + // Getting the checked expr in a cross-platform way is extroardinarily difficult, as glibc has + // multiple conditional implementations of the same macro. Assume the checked expr is a + // variable access so we can search optimistically like so: + exists(VariableAccess va | + va.getTarget().getName() = getExpandedArgument(0) and + va = getAnExpandedElement() and + result = va + ) + } + + /** + * The classification name, for instance, "isfinite". + */ + FPClassifierName getFPClassifierName() { result = classifier } +} + +/** + * A classification function, for instance, "isfinite", when implemented as a function. + */ +class FPClassifierFunction extends Function { + FPClassifierName classifier; + + FPClassifierFunction() { getName() = classifier.getName() } + + FPClassifierName getFPClassifierName() { result = classifier } +} + +class FPClassificationGuard instanceof GuardCondition { + Expr floatExpr; + Expr checkResultExpr; + FPClassifierName classifier; + + FPClassificationGuard() { + super.comparesEq(checkResultExpr, _, _, _) and + ( + exists(FPClassifierMacroInvocation m | + floatExpr = m.getCheckedExpr() and + checkResultExpr = m.getExpr() and + classifier = m.getFPClassifierName() + ) + or + exists(FunctionCall fc, FPClassifierFunction f | + fc.getTarget() = f and + floatExpr = fc.getArgument(0) and + checkResultExpr = fc and + classifier = f.getFPClassifierName() + ) + ) + } + + string toString() { + result = + classifier.toString() + " guard on " + floatExpr.toString() + " via " + + checkResultExpr.toString() + } + + predicate constrainsFPClass(Expr e, FPClassificationConstraint constraint, Boolean testIsTrue) { + floatExpr = e and + exists(BooleanValue value, boolean areEqual, int testResult, FPClassificationConstraint base | + super.comparesEq(checkResultExpr, testResult, areEqual, value) and + base = getBaseConstraint(areEqual, testResult) and + if value.getValue() = testIsTrue then constraint = base else constraint = base.invert() + ) + } + + // Helper predicate, gets base constraint assuming `classifier() == value` or `classifier != value`. + private FPClassificationConstraint getBaseConstraint(Boolean areEqual, int testResult) { + exists(FPClassificationConstraint base | + testResult = 0 and + exists(Boolean strict | + // Handle isfinite() != 0: + classifier = TClassifiesFinite(_, strict) and + base = TExactFPClassification(TFinite(), strict) + or + // Handle isNaN() != 0: + classifier = TClassifiesNaN(_, strict) and + base = TExactFPClassification(TNaN(), strict) + or + // Handle isinf() != 0, which matches for +/- infinity: + classifier = TClassifiesInfinite(_) and + base = TExactFPClassification(TInfinite(), true) + ) and + // Invert the base constraint in the case of `classifier() == 0` + if areEqual = false then result = base else result = base.invert() + or + // Handle isinf() == 1 or isInf() == -1, which matches for one of +/- infinity: + testResult = 1 and + classifier = TClassifiesInfinite(_) and + base = TExactFPClassification(TInfinite(), false) and + // Invert the base constraint in the case of `classifier() != 1` + if areEqual = true then result = base else result = base.invert() + // TODO: handle fpclassify() == FP_INFINITE, FP_NAN, FP_NORMAL, FP_ZERO, etc. + ) + } + + predicate controls(Expr e, boolean testIsTrue) { + exists(IRGuardCondition irg, IRBlock irb, Instruction eir, BooleanValue bval | + irg.getUnconvertedResultExpression() = this and + bval.getValue() = testIsTrue and + irg.valueControls(irb, bval) and + eir.getAst().(ControlFlowNode).getBasicBlock() = e.getBasicBlock() and + eir.getBlock() = irb + ) + } +} + +predicate guardedNotEqualZero(Expr e) { + /* Note Boolean cmpEq, false means cmpNeq */ + exists(Expr checked, GuardCondition guard, boolean cmpEq, BooleanValue value | + hashCons(checked) = hashCons(e) and + guard.controls(e.getBasicBlock(), cmpEq) and + value.getValue() = cmpEq and + guard.comparesEq(checked, 0, false, value) + ) + or + exists(Expr checked, Expr val, int valVal, GuardCondition guard, boolean cmpEq | + hashCons(checked) = hashCons(e) and + forex(float v | + v = [RestrictedRangeAnalysis::lowerBound(val), RestrictedRangeAnalysis::upperBound(val)] + | + valVal = v + ) and + guard.controls(e.getBasicBlock(), cmpEq) and + guard.comparesEq(checked, val, -valVal, false, cmpEq) + ) +} + +predicate guardedNotFPClass(Expr e, FPClassification cls) { + /* Note Boolean cmpEq, false means cmpNeq */ + exists( + Expr checked, FPClassificationGuard guard, FPClassificationConstraint constraint, boolean cmpEq + | + hashCons(checked) = hashCons(e) and + guard.controls(e, cmpEq) and + guard.constrainsFPClass(checked, constraint, cmpEq) and + constraint.mustNotBe(cls) and + not checked = e + ) +} + +predicate exprMayEqualInfinity(Expr e, Boolean positive) { + exists(float target | + positive = true and target = 1.0 / 0.0 + or + positive = false and target = -1.0 / 0.0 + | + RestrictedRangeAnalysis::upperBound(e.getUnconverted()) = target or + RestrictedRangeAnalysis::lowerBound(e.getUnconverted()) = target + ) and + not guardedNotFPClass(e, TInfinite()) and + not e.getType() instanceof IntegralType +} + +signature float upperBoundPredicate(Expr e); + +signature float lowerBoundPredicate(Expr e); + +signature predicate exprMayEqualZeroPredicate(Expr e); + +predicate exprMayEqualZeroNaive(Expr e) { e.getValue().toFloat() = 0 } + +/** + * Get the math function name variants for the given name, e.g., "acos" has variants "acos", + * "acosf", and "acosl". + */ +Function getMathVariants(string name) { result.hasGlobalOrStdName([name, name + "f", name + "l"]) } + +module DomainError< + upperBoundPredicate/1 ub, lowerBoundPredicate/1 lb, exprMayEqualZeroPredicate/1 mayEqualZero> +{ + predicate hasDomainError(FunctionCall fc, string description) { + exists(Function functionWithDomainError | fc.getTarget() = functionWithDomainError | + functionWithDomainError = [getMathVariants(["acos", "asin", "atanh"])] and + not ( + ub(fc.getArgument(0)) <= 1.0 and + lb(fc.getArgument(0)) >= -1.0 + ) and + description = + "the argument has a range " + lb(fc.getArgument(0)) + "..." + ub(fc.getArgument(0)) + + " which is outside the domain of this function (-1.0...1.0)" + or + functionWithDomainError = getMathVariants(["atan2", "pow"]) and + ( + mayEqualZero(fc.getArgument(0)) and + mayEqualZero(fc.getArgument(1)) and + description = "both arguments are equal to zero" + ) + or + functionWithDomainError = getMathVariants("pow") and + ( + ub(fc.getArgument(0)) < 0.0 and + ub(fc.getArgument(1)) < 0.0 and + description = "both arguments are less than zero" + ) + or + functionWithDomainError = getMathVariants("acosh") and + ub(fc.getArgument(0)) < 1.0 and + description = "argument is less than 1" + or + //pole error is the same as domain for logb and tgamma (but not ilogb - no pole error exists) + functionWithDomainError = getMathVariants(["ilogb", "logb", "tgamma"]) and + fc.getArgument(0).getValue().toFloat() = 0 and + description = "argument is equal to zero" + or + functionWithDomainError = getMathVariants(["log", "log10", "log2", "sqrt"]) and + ub(fc.getArgument(0)) < 0.0 and + description = "argument is negative" + or + functionWithDomainError = getMathVariants("log1p") and + ub(fc.getArgument(0)) < -1.0 and + description = "argument is less than 1" + or + functionWithDomainError = getMathVariants("fmod") and + fc.getArgument(1).getValue().toFloat() = 0 and + description = "y is 0" + ) + } +} + +import DomainError as RestrictedDomainError +import DomainError as SimpleDomainError diff --git a/cpp/common/src/codingstandards/cpp/Includes.qll b/cpp/common/src/codingstandards/cpp/Includes.qll new file mode 100644 index 0000000000..c0c66ae2f5 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/Includes.qll @@ -0,0 +1,37 @@ +/** A library which supports analysis of includes. */ + +import cpp +import codingstandards.cpp.PreprocessorDirective +import semmle.code.cpp.headers.MultipleInclusion + +pragma[noinline] +private predicate hasIncludeLocation(Include include, string filepath, int startline) { + include.getLocation().hasLocationInfo(filepath, startline, _, _, _) +} + +/** + * Holds if `include` is included conditionally based on the branch directive `b1`. + */ +pragma[noinline] +predicate isConditionallyIncluded(PreprocessorBranchDirective bd, Include include) { + not bd = any(CorrectIncludeGuard c).getIfndef() and + not bd.getHead().regexpMatch(".*_H(_.*)?") and + exists(string filepath, int startline, int endline, int includeline | + isBranchDirectiveRange(bd, filepath, startline, endline) and + hasIncludeLocation(include, filepath, includeline) and + startline < includeline and + endline > includeline + ) +} + +/** + * Gets a file which is directly included from `fromFile` unconditionally. + */ +File getAnUnconditionallyIncludedFile(File fromFile) { + // Find an include which isn't conditional + exists(Include i | + i.getFile() = fromFile and + not isConditionallyIncluded(_, i) and + result = i.getIncludedFile() + ) +} diff --git a/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll b/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll new file mode 100644 index 0000000000..ce72033ecc --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/IntegerConstantMacro.qll @@ -0,0 +1,37 @@ +import cpp + +/** + * The family of macros `xINTsize_C(arg)` (e.g. `UINT16_C(123)`) which are used + * to create an integer constant of type `Xint_leastSIZE_t` (e.g. + * `uint_least16_t). + */ +class IntegerConstantMacro extends Macro { + boolean signed; + int size; + + IntegerConstantMacro() { + signed = true and size = getName().regexpCapture("INT(8|16|32|64)_C", 1).toInt() + or + signed = false and size = getName().regexpCapture("UINT(8|16|32|64)_C", 1).toInt() + } + + predicate isSmall() { size < any(IntType it | it.isSigned()).getSize() * 8 } + + int getSize() { result = size } + + predicate isSigned() { signed = true } + + float maxValue() { + signed = true and result = 2.pow(size - 1 * 1.0) - 1 + or + signed = false and result = 2.pow(size) - 1 + } + + float minValue() { + signed = true and result = -2.pow(size - 1) + or + signed = false and result = 0 + } + + string getRangeString() { result = minValue().toString() + ".." + maxValue().toString() } +} diff --git a/c/common/src/codingstandards/c/IrreplaceableFunctionLikeMacro.qll b/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll similarity index 95% rename from c/common/src/codingstandards/c/IrreplaceableFunctionLikeMacro.qll rename to cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll index af62cacfd3..8daf129622 100644 --- a/c/common/src/codingstandards/c/IrreplaceableFunctionLikeMacro.qll +++ b/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll @@ -56,3 +56,7 @@ private class FunctionLikeMacroWithOperatorArgument extends IrreplaceableFunctio ) } } + +private class GenericMacro extends IrreplaceableFunctionLikeMacro { + GenericMacro() { getBody().matches("%_Generic%") } +} diff --git a/cpp/common/src/codingstandards/cpp/Iterators.qll b/cpp/common/src/codingstandards/cpp/Iterators.qll index 1b5199a806..c8c217aea4 100644 --- a/cpp/common/src/codingstandards/cpp/Iterators.qll +++ b/cpp/common/src/codingstandards/cpp/Iterators.qll @@ -3,8 +3,8 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow -import codingstandards.cpp.dataflow.TaintTracking +private import semmle.code.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.TaintTracking import codingstandards.cpp.StdNamespace import codingstandards.cpp.rules.containeraccesswithoutrangecheck.ContainerAccessWithoutRangeCheck as ContainerAccessWithoutRangeCheck import semmle.code.cpp.controlflow.Guards @@ -16,7 +16,9 @@ abstract class ContainerAccess extends VariableAccess { } pragma[noinline, nomagic] -predicate localTaint(DataFlow::Node n1, DataFlow::Node n2) { TaintTracking::localTaint(n1, n2) } +private predicate localTaint(DataFlow::Node n1, DataFlow::Node n2) { + TaintTracking::localTaint(n1, n2) +} // define this as anything with dataflow FROM the vector class ContainerPointerOrReferenceAccess extends ContainerAccess { @@ -37,7 +39,9 @@ class ContainerPointerOrReferenceAccess extends ContainerAccess { ) and localTaint(DataFlow::exprNode(fc), DataFlow::exprNode(this)) and (getUnderlyingType() instanceof ReferenceType or getUnderlyingType() instanceof PointerType) and - fc.getQualifier().(VariableAccess).getTarget() = owningContainer + fc.getQualifier().(VariableAccess).getTarget() = owningContainer and + // Exclude cases where we see taint into the owning container + not this = owningContainer.getAnAccess() ) } diff --git a/cpp/common/src/codingstandards/cpp/Literals.qll b/cpp/common/src/codingstandards/cpp/Literals.qll index c6845b181d..edec04152e 100644 --- a/cpp/common/src/codingstandards/cpp/Literals.qll +++ b/cpp/common/src/codingstandards/cpp/Literals.qll @@ -5,6 +5,8 @@ import cpp import codingstandards.cpp.Cpp14Literal +class IntegerLiteral = Cpp14Literal::IntegerLiteral; + /** Gets `Literal.getValueText()` truncated to at most 20 characters. */ string getTruncatedLiteralText(Literal l) { exists(string text | text = l.getValueText() | @@ -68,3 +70,46 @@ class BoolLiteral extends Literal { this.getValue() = "0" and this.getValueText() = "false" } } + +/** + * Abstract case to handle positive and negative "literal" expressions. + * + * All numeric literals in c/cpp are positive. To create a negative constant + * value in a program means applying the unary- operator to a positive literal. + * This class effectively describes positive or negative literals. + */ +abstract class PossiblyNegativeLiteral extends Expr { + /* The syntactic literal, stripped of potential negation */ + abstract Cpp14Literal::NumericLiteral getBaseLiteral(); + + /* The value as a literal reads, without potential underflows from negation */ + abstract float getRawValue(); + + predicate isNegative() { this instanceof NegativeLiteral } +} + +/** + * A negation of a positive literal, creating what can be thought of as a + * "negative literal." + */ +class NegativeLiteral extends PossiblyNegativeLiteral, UnaryMinusExpr { + Cpp14Literal::NumericLiteral literal; + + NegativeLiteral() { literal = getOperand() } + + override Cpp14Literal::NumericLiteral getBaseLiteral() { result = literal } + + override float getRawValue() { result = -literal.getValue().toFloat() } +} + +/** + * A literal which is not immediately negated by a parent unary- expression, + * which can be thought of as a "positive literal." + */ +class PositiveLiteral extends PossiblyNegativeLiteral, Cpp14Literal::NumericLiteral { + PositiveLiteral() { not exists(UnaryMinusExpr l | l.getOperand() = this) } + + override Cpp14Literal::NumericLiteral getBaseLiteral() { result = this } + + override float getRawValue() { result = getValue().toFloat() } +} diff --git a/cpp/common/src/codingstandards/cpp/Locations.qll b/cpp/common/src/codingstandards/cpp/Locations.qll new file mode 100644 index 0000000000..800f44d18a --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/Locations.qll @@ -0,0 +1,30 @@ +import cpp + +/** Holds if `lineNumber` is an indexed line number in file `f`. */ +predicate isLineNumber(File f, int lineNumber) { + exists(Location l | l.getFile() = f | + l.getStartLine() = lineNumber + or + l.getEndLine() = lineNumber + ) +} + +/** Gets the last line number in `f`. */ +int getLastLineNumber(File f) { result = max(int lineNumber | isLineNumber(f, lineNumber)) } + +/** Gets the last column number on the last line of `f`. */ +int getLastColumnNumber(File f) { + result = + max(Location l | + l.getFile() = f and + l.getEndLine() = getLastLineNumber(f) + | + l.getEndColumn() + ) +} + +/** Gets the last column number on the given line of `filepath`. */ +bindingset[filepath, lineNumber] +int getLastColumnNumber(string filepath, int lineNumber) { + result = max(Location l | l.hasLocationInfo(filepath, _, _, lineNumber, _) | l.getEndColumn()) +} diff --git a/cpp/common/src/codingstandards/cpp/Loops.qll b/cpp/common/src/codingstandards/cpp/Loops.qll index bfd68c49a0..1086355638 100644 --- a/cpp/common/src/codingstandards/cpp/Loops.qll +++ b/cpp/common/src/codingstandards/cpp/Loops.qll @@ -204,7 +204,7 @@ predicate isLoopCounterModifiedInCondition(ForStmt forLoop, VariableAccess loopC loopCounterAccess = getAnIterationVariable(forLoop).getAnAccess() and ( loopCounterAccess.isModified() or - loopCounterAccess.isAddressOfAccess() + loopCounterAccess.isAddressOfAccessNonConst() ) } @@ -219,7 +219,7 @@ predicate isLoopCounterModifiedInStatement( loopCounterAccess = loopCounter.getAnAccess() and ( loopCounterAccess.isModified() or - loopCounterAccess.isAddressOfAccess() + loopCounterAccess.isAddressOfAccessNonConst() ) and forLoop.getStmt().getChildStmt*() = loopCounterAccess.getEnclosingStmt() } @@ -374,3 +374,40 @@ predicate isInvalidLoop(ForStmt forLoop, string reason, Locatable reasonLocation reason = "its $@ is not a boolean" and reasonLabel = "loop control variable" } + +/** + * A comparison expression that has the minimum qualification as being a valid termination + * condition of a legacy for-loop. It is characterized by a value read from a variable being + * compared to a value, which is supposed to be the loop bound. + */ +class LegacyForLoopCondition extends RelationalOperation { + /** + * The legacy for-loop this relational operation is a condition of. + */ + ForStmt forLoop; + VariableAccess loopCounter; + Expr loopBound; + + LegacyForLoopCondition() { + this = forLoop.getCondition() and + loopCounter = this.getAnOperand() and + loopBound = this.getAnOperand() and + loopCounter.getTarget() = getAnIterationVariable(forLoop) and + loopBound != loopCounter + } + + /** + * Gets the for-loop this expression is a termination condition of. + */ + ForStmt getForLoop() { result = forLoop } + + /** + * Gets the variable access to the loop counter variable, appearing in this loop condition. + */ + VariableAccess getLoopCounter() { result = loopCounter } + + /** + * Gets the variable access to the loop bound variable, appearing in this loop condition. + */ + Expr getLoopBound() { result = loopBound } +} diff --git a/cpp/common/src/codingstandards/cpp/MatchingParenthesis.qll b/cpp/common/src/codingstandards/cpp/MatchingParenthesis.qll new file mode 100644 index 0000000000..8a28bd0517 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/MatchingParenthesis.qll @@ -0,0 +1,264 @@ +/** + * A library for parsing a string of parentheses and non-parentheses characters. + * + * Simply implement the signature class `InputString` for the set of strings that you wish to parse, + * and then use the `MatchingParenthesis` module which exposes the following classes/predicates: + * - `ParsedRoot`: The root of the parse tree. + * - `ParsedGroup`: Parenthesis groups. The root is also a group, even if not parenthesized. + * - `ParsedText`: All text that is not '(' or ')'. + * - `Tokenized`: A linked list of the tokens in the input string. + * - `textFrom(start, end)`: A function to get the text between two tokens. + * + * The parenthesis AST has functions `getChild(int i)` and `getParent()` to navigate the tree, as + * well as `getRoot()` and `getText()` for `ParsedText` nodes. They also have methods + * `getStartToken()`, `getEndToken()` which are especially useful with the method `textFrom(...)`. + * + * This module can allow for slightly more intelligent interpretation of macro strings, but it has + * limitations. + * - It _only_ handles the parenthesis. + * - It assumes parentheses are matched. + * - It does not handle the case where a parenthesis is inside a string literal. + * - It does not handle the case where a parenthesis is inside a comment. + * + * This module has been moderately optimized, but still it is best to be selective with the set of + * strings you attempt to parse with it. + */ + +import codeql.util.Option + +signature class InputString extends string; + +module MatchingParenthesis { + newtype TTokenType = + TOpenParen() or + TCloseParen() or + TNotParen() + + bindingset[char] + private TTokenType tokenTypeOfChar(string char) { + result = TOpenParen() and char = "(" + or + result = TCloseParen() and char = ")" + } + + private int inputId(Input i) { rank[result](Input inp) = i } + + private newtype TTokenized = + TTokenizerStart(int iid) { iid = inputId(_) } or + TToken(int iid, TTokenized prev, TTokenType token, int occurrence, int endPos) { + exists(string inputStr, int prevEndPos, int prevOccurrence, string char | + iid = inputId(inputStr) and + ( + prev = TTokenizerStart(iid) and prevOccurrence = -1 and prevEndPos = 0 + or + prev = TToken(iid, _, _, prevOccurrence, prevEndPos) + ) and + inputStr.charAt(prevEndPos) = char and + if char = ["(", ")"] + then ( + endPos = prevEndPos + 1 and + token = tokenTypeOfChar(char) and + occurrence = prevOccurrence + 1 + ) else ( + token = TNotParen() and + exists(inputStr.regexpFind("\\(|\\)", prevOccurrence + 1, endPos)) and + occurrence = prevOccurrence + ) + ) + } + + class Tokenized extends TTokenized { + string toString() { + getTokenType() = TOpenParen() and result = "(" + or + getTokenType() = TCloseParen() and result = ")" + or + getTokenType() = TNotParen() and result = "non-parenthesis" + } + + int getInputId() { this = TToken(result, _, _, _, _) } + + TTokenType getTokenType() { this = TToken(_, _, result, _, _) } + + Tokenized getPrevious() { this = TToken(_, result, _, _, _) } + + string getInputString() { + this = TToken(inputId(result), _, _, _, _) or this = TTokenizerStart(inputId(result)) + } + + int getStartPos() { + if exists(getPrevious()) then result = getPrevious().getEndPos() else result = 0 + } + + int getEndPos() { + this = TToken(_, _, _, _, result) + or + this = TTokenizerStart(_) and result = 0 + } + + string getText() { result = textFrom(this, this) } + + Tokenized getNext() { result.getPrevious() = this } + + Tokenized getLast() { + if exists(getNext()) then result = getNext().getLast() else result = this + } + } + + /** + * The root of the parse tree. + */ + class ParsedRoot extends ParsedGroup { + ParsedRoot() { not exists(getParent()) } + + override ParsedRoot getRoot() { result = this } + + override string getDebugText() { result = this.(Tokenized).getInputString() } + } + + /** + * A group of tokens that may be parenthesized. + * + * The `ParseRoot` is the only group that isn't parenthesized. + */ + class ParsedGroup extends Parsed { + ParsedGroup() { isGroup() } + + Parsed getChild(int i) { + result.getParent() = this and + result.getChildIdx() = i + } + } + + /** + * Get the text from the `start` token to the `end` token (inclusive on both ends). + */ + pragma[inline] + string textFrom(Tokenized start, Tokenized end) { + result = start.getInputString().substring(start.getStartPos(), end.getEndPos()) + } + + /** + * All text that is not '(' or ')'. + */ + class ParsedText extends Parsed { + ParsedText() { not isGroup() } + + string getText() { result = textFrom(getStartToken(), getEndToken()) } + } + + /** + * The AST for the input string parsed with matching parenthesis. + */ + class Parsed extends TTokenized { + Option::Option parent; + int childIdx; + boolean isGroup; + + Parsed() { + this.(Tokenized).getTokenType() = TNotParen() and + parseStepAppend(this, parent.asSome(), childIdx) and + isGroup = false + or + this.(Tokenized).getTokenType() = TOpenParen() and + parseStepOpen(this, parent.asSome(), childIdx) and + isGroup = true + or + this = TTokenizerStart(_) and + parent.isNone() and + childIdx = 0 and + isGroup = true + } + + ParsedRoot getRoot() { result = getParent().getRoot() } + + string getInputString() { result = this.(Tokenized).getInputString() } + + /** + * The token that starts this group. + * + * For `ParsedText`, this is the same as the end token. + */ + Tokenized getStartToken() { result = this } + + /** + * The token that endns this group. + * + * For `ParsedText`, this is the same as the start token. If parentheses are not matched, this + * may not have a result. + */ + Tokenized getEndToken() { + this.(Tokenized).getTokenType() = TNotParen() and + result = this + or + this.(Tokenized).getTokenType() = TOpenParen() and + parseStepClose(result, this) + or + this = TTokenizerStart(_) and + result = getStartToken().(Tokenized).getLast() + } + + /** + * The index of this child in the parent group. + */ + int getChildIdx() { result = childIdx } + + ParsedGroup getParent() { result = parent.asSome() } + + predicate isGroup() { isGroup = true } + + string getDebugText() { result = textFrom(getStartToken(), getEndToken()) } + + string toString() { result = this.(Tokenized).toString() } + } + + /** + * Parse open parenthesis and add it to the open group or parse root. Parsing algorithm may not + * behave reliably for mismatched parenthesis. + */ + private predicate parseStepOpen(Tokenized consumeToken, ParsedGroup parent, int childIdx) { + consumeToken.getTokenType() = TOpenParen() and + ( + consumeToken.getPrevious() = parent.getStartToken() and + childIdx = 0 + or + exists(Parsed prevSibling | + prevSibling.getEndToken() = consumeToken.getPrevious() and + childIdx = prevSibling.getChildIdx() + 1 and + parent = prevSibling.getParent() + ) + ) + } + + /** + * Parse raw text that isn't '(' or ')' and add it to the open group or parse root. + */ + private predicate parseStepAppend(Tokenized consumeToken, ParsedGroup parent, int childIdx) { + consumeToken.getTokenType() = TNotParen() and + ( + consumeToken.getPrevious() = parent.getStartToken() and childIdx = 0 + or + exists(Parsed prevSibling | + prevSibling.getEndToken() = consumeToken.getPrevious() and + childIdx = prevSibling.getChildIdx() + 1 and + parent = prevSibling.getParent() + ) + ) + } + + /** + * Parse a close parenthesis to close the currently open group. Parsing algorithm may not behave + * properly for mismatched parenthesis. + */ + private predicate parseStepClose(Tokenized consumeToken, ParsedGroup closed) { + consumeToken.getTokenType() = TCloseParen() and + ( + closed.getStartToken() = consumeToken.getPrevious() + or + exists(Parsed finalChild | + consumeToken.getPrevious() = finalChild.getEndToken() and + finalChild.getParent() = closed + ) + ) + } +} diff --git a/cpp/autosar/src/rules/M14-6-1/NameInDependentBase.qll b/cpp/common/src/codingstandards/cpp/NameInDependentBase.qll similarity index 99% rename from cpp/autosar/src/rules/M14-6-1/NameInDependentBase.qll rename to cpp/common/src/codingstandards/cpp/NameInDependentBase.qll index b3d12c044b..e599f286ae 100644 --- a/cpp/autosar/src/rules/M14-6-1/NameInDependentBase.qll +++ b/cpp/common/src/codingstandards/cpp/NameInDependentBase.qll @@ -1,5 +1,4 @@ import cpp -import codingstandards.cpp.autosar /** * Gets a dependent base type of the given template class. diff --git a/cpp/common/src/codingstandards/cpp/Noreturn.qll b/cpp/common/src/codingstandards/cpp/Noreturn.qll new file mode 100644 index 0000000000..eabe86b56e --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/Noreturn.qll @@ -0,0 +1,22 @@ +import cpp + +/** + * A function marked with _Noreturn or __attribute((noreturn)) + */ +class NoreturnFunction extends Function { + NoreturnFunction() { + this.getASpecifier().getName() = "noreturn" or + this.getAnAttribute().getName() = "noreturn" + } +} + +/** + * A function that may complete normally, and/or contains an explicit reachable + * return statement. + */ +predicate mayReturn(Function function) { + exists(ReturnStmt s | + function = s.getEnclosingFunction() and + s.getBasicBlock().isReachable() + ) +} diff --git a/cpp/common/src/codingstandards/cpp/Nullness.qll b/cpp/common/src/codingstandards/cpp/Nullness.qll index d76db4afad..8751c54d9b 100644 --- a/cpp/common/src/codingstandards/cpp/Nullness.qll +++ b/cpp/common/src/codingstandards/cpp/Nullness.qll @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow private class PointerToMember extends Variable { PointerToMember() { this.getType() instanceof PointerToMemberType } diff --git a/cpp/autosar/src/rules/A18-5-4/OperatorDelete.qll b/cpp/common/src/codingstandards/cpp/OperatorDelete.qll similarity index 96% rename from cpp/autosar/src/rules/A18-5-4/OperatorDelete.qll rename to cpp/common/src/codingstandards/cpp/OperatorDelete.qll index ada7d109cd..c9ff315866 100644 --- a/cpp/autosar/src/rules/A18-5-4/OperatorDelete.qll +++ b/cpp/common/src/codingstandards/cpp/OperatorDelete.qll @@ -1,5 +1,4 @@ import cpp -import codingstandards.cpp.autosar class StdNoThrow extends Class { StdNoThrow() { hasQualifiedName("std", "nothrow_t") } diff --git a/cpp/common/src/codingstandards/cpp/Overflow.qll b/cpp/common/src/codingstandards/cpp/Overflow.qll index dca1386513..b81147d6bf 100644 --- a/cpp/common/src/codingstandards/cpp/Overflow.qll +++ b/cpp/common/src/codingstandards/cpp/Overflow.qll @@ -6,7 +6,7 @@ import cpp import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis import SimpleRangeAnalysisCustomizations import semmle.code.cpp.controlflow.Guards -import codingstandards.cpp.dataflow.TaintTracking +private import semmle.code.cpp.dataflow.TaintTracking import semmle.code.cpp.valuenumbering.GlobalValueNumbering import codingstandards.cpp.Expr import codingstandards.cpp.UndefinedBehavior diff --git a/cpp/common/src/codingstandards/cpp/PreprocessorDirective.qll b/cpp/common/src/codingstandards/cpp/PreprocessorDirective.qll index fe619e5317..ca943742d9 100644 --- a/cpp/common/src/codingstandards/cpp/PreprocessorDirective.qll +++ b/cpp/common/src/codingstandards/cpp/PreprocessorDirective.qll @@ -40,3 +40,68 @@ class PreprocessorIfOrElif extends PreprocessorBranch { this instanceof PreprocessorElif } } + +/** + * Holds if the preprocessor directive `m` is located at `filepath` and `startline`. + */ +pragma[noinline] +predicate hasPreprocessorLocation(PreprocessorDirective m, string filepath, int startline) { + m.getLocation().hasLocationInfo(filepath, startline, _, _, _) +} + +/** + * Holds if `first` and `second` are a pair of branch directives in the same file, such that they + * share the same root if condition. + */ +pragma[noinline] +private predicate isBranchDirectivePair( + PreprocessorBranchDirective first, PreprocessorBranchDirective second, string filepath, + int b1StartLocation, int b2StartLocation +) { + first.getIf() = second.getIf() and + not first = second and + hasPreprocessorLocation(first, filepath, b1StartLocation) and + hasPreprocessorLocation(second, filepath, b2StartLocation) and + b1StartLocation < b2StartLocation +} + +/** + * Holds if `bd` is a branch directive in the range `filepath`, `startline`, `endline`. + */ +pragma[noinline] +predicate isBranchDirectiveRange( + PreprocessorBranchDirective bd, string filepath, int startline, int endline +) { + hasPreprocessorLocation(bd, filepath, startline) and + exists(PreprocessorBranchDirective next | + next = bd.getNext() and + // Avoid referencing filepath here, otherwise the optimiser will try to join + // on it + hasPreprocessorLocation(next, _, endline) + ) +} + +/** + * Holds if the macro `m` is defined within the branch directive `bd`. + */ +pragma[noinline] +predicate isMacroDefinedWithinBranch(PreprocessorBranchDirective bd, Macro m) { + exists(string filepath, int startline, int endline, int macroline | + isBranchDirectiveRange(bd, filepath, startline, endline) and + hasPreprocessorLocation(m, filepath, macroline) and + startline < macroline and + endline > macroline + ) +} + +/** + * Holds if the pair of macros are "conditional" i.e. only one of the macros is followed in any + * particular compilation of the containing file. + */ +predicate mutuallyExclusiveBranchDirectiveMacros(Macro firstMacro, Macro secondMacro) { + exists(PreprocessorBranchDirective b1, PreprocessorBranchDirective b2 | + isBranchDirectivePair(b1, b2, _, _, _) and + isMacroDefinedWithinBranch(b1, firstMacro) and + isMacroDefinedWithinBranch(b2, secondMacro) + ) +} diff --git a/cpp/common/src/codingstandards/cpp/ReadErrorsAndEOF.qll b/cpp/common/src/codingstandards/cpp/ReadErrorsAndEOF.qll index 7adb911c9f..94e7f89796 100644 --- a/cpp/common/src/codingstandards/cpp/ReadErrorsAndEOF.qll +++ b/cpp/common/src/codingstandards/cpp/ReadErrorsAndEOF.qll @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.standardlibrary.FileAccess /** diff --git a/cpp/common/src/codingstandards/cpp/Realloc.qll b/cpp/common/src/codingstandards/cpp/Realloc.qll new file mode 100644 index 0000000000..71acb7d7b1 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/Realloc.qll @@ -0,0 +1,18 @@ +import cpp +import codingstandards.cpp.CodingStandards + +class ReallocCall extends FunctionCall { + ReallocCall() { getTarget().hasGlobalOrStdName("realloc") } + + Expr getSizeArgument() { result = getArgument(1) } + + predicate sizeIsExactlyZero() { + upperBound(getSizeArgument().getConversion()) = 0 and + lowerBound(getSizeArgument().getConversion()) = 0 + } + + predicate sizeMayBeZero() { + upperBound(getSizeArgument().getConversion()) >= 0 and + lowerBound(getSizeArgument().getConversion()) <= 0 + } +} diff --git a/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll new file mode 100644 index 0000000000..d92b46335d --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll @@ -0,0 +1,2243 @@ +import semmle.code.cpp.controlflow.Guards +import semmle.code.cpp.valuenumbering.HashCons + +/** + * A fork of SimpleRangeAnalysis.qll, which is intended to only give results + * with a conservative basis. Forked from codeql/cpp-all@1.4.2. + * + * For instance, since range analysis is local, a function call (e.g. `f()`) is + * given the widest possible range in the original library. In this fork, we do + * not provide any result. + * + * Original library level doc comment from SimpleRangeAnalysis.qll: + * + * > Simple range analysis library. Range analysis is usually done as an + * > abstract interpretation over the lattice of range values. (A range is a + * > pair, containing a lower and upper bound for the value.) The problem + * > with this approach is that the lattice is very tall, which means it can + * > take an extremely large number of iterations to find the least fixed + * > point. This example illustrates the problem: + * + * > int count = 0; + * > for (; p; p = p->next) { + * > count = count+1; + * > } + * + * > The range of 'count' is initially (0,0), then (0,1) on the second + * > iteration, (0,2) on the third iteration, and so on until we eventually + * > reach maxInt. + * + * > This library uses a crude solution to the problem described above: if + * > the upper (or lower) bound of an expression might depend recursively on + * > itself then we round it up (down for lower bounds) to one of a fixed set + * > of values, such as 0, 1, 2, 256, and +Inf. This limits the height of the + * > lattice which ensures that the analysis will terminate in a reasonable + * > amount of time. This solution is similar to the abstract interpretation + * > technique known as 'widening', but it is less precise because we are + * > unable to inspect the bounds from the previous iteration of the fixed + * > point computation. For example, widening might be able to deduce that + * > the lower bound is -11 but we would approximate it to -16. + * + * > QL does not allow us to compute an aggregate over a recursive + * > sub-expression, so we cannot compute the minimum lower bound and maximum + * > upper bound during the recursive phase of the query. Instead, the + * > recursive phase computes a set of lower bounds and a set of upper bounds + * > for each expression. We compute the minimum lower bound and maximum + * > upper bound after the recursion is finished. This is another reason why + * > we need to limit the number of bounds per expression, because they will + * > all be stored until the recursive phase is finished. + * + * > The ranges are represented using a pair of floating point numbers. This + * > is simpler than using integers because floating point numbers cannot + * > overflow and wrap. It is also convenient because we can detect overflow + * > and negative overflow by looking for bounds that are outside the range + * > of the type. + * + * The differences between this library and the original are: + * - The `largeValue()` predicate, with a value of 1e15, used in place of + * `exprMaxVal()` and `exprMinVal()` in most places. + * - Support for range analysis extensions removed for simplicity. + * - Additional predicates have been added to check for non-zero values, and guards + * against values equalling zero. + * - Division by a constant value has been added as a supported operations. Division + * is always widened, as support for division introduces examples of significantly + * longer chains of dependent expressions than merely addition and multiplication. + * These long chains can introduce exponential growth in the number of candidate + * bounds, even without recursive binary operations, so widening is always applied. + * - Division operations where the range of the denominator includes zero (and its + * not guarded to be non-zero) and produce infinite upper and/or lower bounds. + * - Support for monotonically increasing and decreasing math functions has been + * added, including `log`, `exp`, `asin`, `atan`, `sinh`, and `sqrt`. If a math + * function increases or decreases monotonically, then the lower or upper bound of + * its input can be used to compute the lower or upper bound of the function call. + * Not all math functions increase or decrease monotonically. + */ +module RestrictedRangeAnalysis { + import cpp + private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils as Util + import semmle.code.cpp.rangeanalysis.RangeSSA + import SimpleRangeAnalysisCached + private import semmle.code.cpp.rangeanalysis.NanAnalysis + + float largeValue() { result = 1000000000000000.0 } + + /** + * This fixed set of lower bounds is used when the lower bounds of an + * expression are recursively defined. The inferred lower bound is rounded + * down to the nearest lower bound in the fixed set. This restricts the + * height of the lattice, which prevents the analysis from exploding. + * + * Note: these bounds were chosen fairly arbitrarily. Feel free to add more + * bounds to the set if it helps on specific examples and does not make + * performance dramatically worse on large codebases, such as libreoffice. + */ + private float wideningLowerBounds(ArithmeticType t) { + result = 2.0 or + result = 1.0 or + result = 0.0 or + result = -1.0 or + result = -2.0 or + result = -8.0 or + result = -16.0 or + result = -128.0 or + result = -256.0 or + result = -32768.0 or + result = -65536.0 or + result = -largeValue() or + result = Util::typeLowerBound(t) + //result = max(float v | v = Util::typeLowerBound(t) or v = -largeValue()) + } + + /** See comment for `wideningLowerBounds`, above. */ + private float wideningUpperBounds(ArithmeticType t) { + result = -2.0 or + result = -1.0 or + result = 0.0 or + result = 1.0 or + result = 2.0 or + result = 7.0 or + result = 15.0 or + result = 127.0 or + result = 255.0 or + result = 32767.0 or + result = 65535.0 or + result = largeValue() or + result = Util::typeUpperBound(t) + //result = min(float v | v = Util::typeLowerBound(t) or v = largeValue()) + } + + /** + * Gets the value of the expression `e`, if it is a constant. + * This predicate also handles the case of constant variables initialized in different + * compilation units, which doesn't necessarily have a getValue() result from the extractor. + */ + private string getValue(Expr e) { + if exists(e.getValue()) + then result = e.getValue() + else + /* + * It should be safe to propagate the initialization value to a variable if: + * The type of v is const, and + * The type of v is not volatile, and + * Either: + * v is a local/global variable, or + * v is a static member variable + */ + + exists(VariableAccess access, StaticStorageDurationVariable v | + not v.getUnderlyingType().isVolatile() and + v.getUnderlyingType().isConst() and + e = access and + v = access.getTarget() and + result = getValue(v.getAnAssignedValue()) + ) + } + + private float varMaxVal(Variable v) { + result = min(float f | f = Util::varMaxVal(v) or f = largeValue()) + } + + private float varMinVal(Variable v) { + result = max(float f | f = Util::varMinVal(v) or f = -largeValue()) + } + + private float exprMaxVal(Expr e) { + result = min(float f | f = Util::exprMaxVal(e) or f = largeValue()) + } + + private float exprMinVal(Expr e) { + result = max(float f | f = Util::exprMinVal(e) or f = -largeValue()) + } + + /** + * A bitwise `&` expression in which both operands are unsigned, or are effectively + * unsigned due to being a non-negative constant. + */ + private class UnsignedBitwiseAndExpr extends BitwiseAndExpr { + UnsignedBitwiseAndExpr() { + ( + this.getLeftOperand() + .getFullyConverted() + .getType() + .getUnderlyingType() + .(IntegralType) + .isUnsigned() or + getValue(this.getLeftOperand().getFullyConverted()).toInt() >= 0 + ) and + ( + this.getRightOperand() + .getFullyConverted() + .getType() + .getUnderlyingType() + .(IntegralType) + .isUnsigned() or + getValue(this.getRightOperand().getFullyConverted()).toInt() >= 0 + ) + } + } + + /** + * Gets the floor of `v`, with additional logic to work around issues with + * large numbers. + */ + bindingset[v] + float safeFloor(float v) { + // return the floor of v + v.abs() < 2.pow(31) and + result = v.floor() + or + // `floor()` doesn't work correctly on large numbers (since it returns an integer), + // so fall back to unrounded numbers at this scale. + not v.abs() < 2.pow(31) and + result = v + } + + /** A `MulExpr` where exactly one operand is constant. */ + private class MulByConstantExpr extends MulExpr { + float constant; + Expr operand; + + MulByConstantExpr() { + exists(Expr constantExpr | + this.hasOperands(constantExpr, operand) and + constant = getValue(constantExpr.getFullyConverted()).toFloat() and + not exists(getValue(operand.getFullyConverted()).toFloat()) + ) + } + + /** Gets the value of the constant operand. */ + float getConstant() { result = constant } + + /** Gets the non-constant operand. */ + Expr getOperand() { result = operand } + } + + private class UnsignedMulExpr extends MulExpr { + UnsignedMulExpr() { + this.getType().(IntegralType).isUnsigned() and + // Avoid overlap. It should be slightly cheaper to analyze + // `MulByConstantExpr`. + not this instanceof MulByConstantExpr + } + } + + /** + * Holds if `expr` is effectively a multiplication of `operand` with the + * positive constant `positive`. + */ + private predicate effectivelyMultipliesByPositive(Expr expr, Expr operand, float positive) { + operand = expr.(MulByConstantExpr).getOperand() and + positive = expr.(MulByConstantExpr).getConstant() and + positive >= 0.0 // includes positive zero + or + operand = expr.(UnaryPlusExpr).getOperand() and + positive = 1.0 + or + operand = expr.(CommaExpr).getRightOperand() and + positive = 1.0 + or + operand = expr.(StmtExpr).getResultExpr() and + positive = 1.0 + } + + /** + * Holds if `expr` is effectively a multiplication of `operand` with the + * negative constant `negative`. + */ + private predicate effectivelyMultipliesByNegative(Expr expr, Expr operand, float negative) { + operand = expr.(MulByConstantExpr).getOperand() and + negative = expr.(MulByConstantExpr).getConstant() and + negative < 0.0 // includes negative zero + or + operand = expr.(UnaryMinusExpr).getOperand() and + negative = -1.0 + } + + private class AssignMulByConstantExpr extends AssignMulExpr { + float constant; + + AssignMulByConstantExpr() { + constant = getValue(this.getRValue().getFullyConverted()).toFloat() + } + + float getConstant() { result = constant } + } + + private class AssignMulByPositiveConstantExpr extends AssignMulByConstantExpr { + AssignMulByPositiveConstantExpr() { constant >= 0.0 } + } + + private class AssignMulByNegativeConstantExpr extends AssignMulByConstantExpr { + AssignMulByNegativeConstantExpr() { constant < 0.0 } + } + + private class UnsignedAssignMulExpr extends AssignMulExpr { + UnsignedAssignMulExpr() { + this.getType().(IntegralType).isUnsigned() and + // Avoid overlap. It should be slightly cheaper to analyze + // `AssignMulByConstantExpr`. + not this instanceof AssignMulByConstantExpr + } + } + + /** + * Holds if `expr` is effectively a division of `operand` with the + * positive constant `positive`. + */ + private predicate dividesByPositive(DivExpr expr, Expr operand, float positive) { + operand = expr.(DivExpr).getLeftOperand() and + positive = expr.(DivExpr).getRightOperand().getValue().toFloat() and + positive > 0.0 // doesn't include zero + } + + /** + * Holds if `expr` is effectively a division of `operand` with the + * negative constant `negative`. + */ + private predicate dividesByNegative(Expr expr, Expr operand, float negative) { + operand = expr.(DivExpr).getLeftOperand() and + negative = getValue(expr.(DivExpr).getRightOperand().getFullyConverted()).toFloat() and + negative < 0.0 // doesn't include zero + } + + /** + * Holds if `expr` may divide by zero. Excludes dividing a constant zero divided by zero, + * which produces NaN instead of an infinite value. + */ + predicate dividesNonzeroByZero(Expr expr) { + exists(Expr divisor, Expr numerator | + divisor = expr.(DivExpr).getRightOperand() and + numerator = expr.(DivExpr).getLeftOperand() and + getTruncatedLowerBounds(divisor) <= 0.0 and + getTruncatedUpperBounds(divisor) >= 0.0 and + not isCheckedNotZero(divisor) and + not getValue(numerator).toFloat() = 0.0 + ) + } + + bindingset[name] + Function getMathVariants(string name) { + result.hasGlobalOrStdName([name, name + "f", name + "l"]) + } + + /** + * New support added for mathematical functions that either monotonically increase, or decrease, + * or that have a known lower or upper bound. + * + * For instance, log(x) monotonically increases over x, and acos(x) monotonically decreases, + * while sin(x) has a known output range of -1 to 1. + * + * `pow` is especially common so minimal work is done to support that here as well. `pow(c, x)` + * monotonically increases or decreases over `x` if `c` is a constant, though the reverse is not + * true except in special cases. + */ + newtype TSupportedMathFunctionCall = + /* A monotonically increasing function call. `extra` is a constant for `pow(x, c)`. */ + TMonotonicIncrease(FunctionCall fc, Expr input, float extra) { + // Note: Codeql has no default implementation in codeql for exp2, atanh, acosh, asinh, or + // log1p so we haven't taken the time to support them yet. + fc.getTarget() = + getMathVariants(["log", "log2", "log10", "exp", "asin", "atan", "sinh", "sqrt"]) and + input = fc.getArgument(0) and + extra = 0.0 + or + // Notes: pow is monotonic if the base argument is constant, increasing if the base is greater + // than 1 or between -1 and 0, and decreasing otherwise. A constant power is monotonic over the + // base in the positive or negative domain, but distinguishing those separately can introduce + // non-monotonic recursion errors. + fc.getTarget() = getMathVariants("pow") and + extra = fc.getArgument(0).getValue().toFloat() and + ( + extra > 1.0 + or + extra < 0.0 and extra > -1.0 + ) and + input = fc.getArgument(1) + } or + /* A monotonically decreasing function call. `extra` is a constant for `pow(x, c)`. */ + TMonotonicDecrease(FunctionCall fc, Expr input, float extra) { + fc.getTarget() = getMathVariants(["acos"]) and + input = fc.getArgument(0) and + extra = 0.0 + or + fc.getTarget() = getMathVariants("pow") and + extra = fc.getArgument(0).getValue().toFloat() and + ( + extra < -1.0 + or + extra > 0.0 and extra < 1.0 + ) and + input = fc.getArgument(1) + } or + /* A non-mononotic function call with a known lower bound. */ + TNonMonotonicLowerBound(FunctionCall fc, float lb) { + fc.getTarget() = getMathVariants("cosh") and + lb = 1.0 + or + fc.getTarget() = getMathVariants(["cos", "sin"]) and + lb = -1.0 + } or + /* A non-mononotic function call with a known upper bound. */ + TNonMonotonicUpperBound(FunctionCall fc, float lb) { + fc.getTarget() = getMathVariants(["cos", "sin"]) and + lb = 1.0 + } + + /** + * A function call that is supported by range analysis. + */ + class SupportedFunctionCall extends TSupportedMathFunctionCall { + string toString() { + exists(FunctionCall fc | + this = TMonotonicIncrease(fc, _, _) and + result = "Monotonic increase " + fc.getTarget().getName() + or + this = TMonotonicDecrease(fc, _, _) and + result = "Monotonic decrease " + fc.getTarget().getName() + or + this = TNonMonotonicLowerBound(fc, _) and + result = "Nonmonotonic lower bound " + fc.getTarget().getName() + or + this = TNonMonotonicUpperBound(fc, _) and + result = "Nonmonotonic upper bound " + fc.getTarget().getName() + ) + } + + /** Get the function call node this algebraic type corresponds to. */ + FunctionCall getFunctionCall() { + this = TMonotonicIncrease(result, _, _) + or + this = TMonotonicDecrease(result, _, _) + or + this = TNonMonotonicLowerBound(result, _) + or + this = TNonMonotonicUpperBound(result, _) + } + + /** Get the function name (`sin`, `pow`, etc.) without the `l` or `f` suffix. */ + bindingset[this, result] + string getBaseFunctionName() { getMathVariants(result) = getFunctionCall().getTarget() } + + /** + * Compute a result bound based on an input value and an extra constant value. + * + * The functions `getUpperBound()` and `getLowerBound()` automatically handle the differences + * between monotonically increasing and decreasing functions, and provide the input value. The + * `extra` float exists to support `pow(x, c)` for the constant `c`, otherwise it is `0.0`. + */ + bindingset[value, extra, this] + float compute(float value, float extra) { + exists(string name | name = getBaseFunctionName() | + name = "log" and + result = value.log() + or + name = "log2" and + result = value.log2() + or + name = "log10" and + result = value.log10() + or + name = "exp" and + result = value.exp() + or + name = "asin" and + result = value.asin() + or + name = "atan" and + result = value.atan() + or + name = "acos" and + result = value.acos() + or + name = "sinh" and + result = value.sinh() + or + name = "sqrt" and + result = value.sqrt() + or + name = "pow" and + result = extra.pow(value) + ) + } + + /** + * Get the lower bound of this function, based on its fixed range (if it has one) or based on + * the lower or upper bound of its input, if it is a monotonically increasing or decreasing + * function. + */ + float getLowerBound() { + this = TNonMonotonicLowerBound(_, result) + or + exists(Expr expr, float bound, float extra | + ( + this = TMonotonicIncrease(_, expr, extra) and + bound = getFullyConvertedLowerBounds(expr) + or + this = TMonotonicDecrease(_, expr, extra) and + bound = getFullyConvertedUpperBounds(expr) + ) and + result = compute(bound, extra) + ) + } + + /** + * Get the lower bound of this function, based on its fixed range (if it has one) or based on + * the lower or upper bound of its input, if it is a monotonically increasing or decreasing + * function. + */ + float getUpperBound() { + this = TNonMonotonicUpperBound(_, result) + or + exists(Expr expr, float bound, float extra | + ( + this = TMonotonicIncrease(_, expr, extra) and + bound = getFullyConvertedUpperBounds(expr) + or + this = TMonotonicDecrease(_, expr, extra) and + bound = getFullyConvertedLowerBounds(expr) + ) and + result = compute(bound, extra) + ) + } + } + + predicate supportedMathFunction(FunctionCall fc) { + exists(SupportedFunctionCall sfc | sfc.getFunctionCall() = fc) + } + + /** + * Holds if `expr` is checked with a guard to not be zero. + * + * Since our range analysis only tracks an upper and lower bound, that means if a variable has + * range [-10, 10], its range includes zero. In the body of an if statement that checks it's not + * equal to zero, we cannot update the range to reflect that as the upper and lower bounds are + * not changed. This problem is not the case for gt, lt, gte, lte, or ==, as these can be used to + * create a new subset range that does not include zero. + * + * It is important to know if an expr may be zero to avoid division by zero creating infinities. + */ + predicate isCheckedNotZero(Expr expr) { + exists(RangeSsaDefinition def, StackVariable v, VariableAccess guardVa, Expr guard | + // This is copied from getGuardedUpperBound, which says its only an approximation. This is + // indeed wrong in many cases. + def.isGuardPhi(v, guardVa, guard, _) and + exists(unique(BasicBlock b | b = def.(BasicBlock).getAPredecessor())) and + expr = def.getAUse(v) and + isNEPhi(v, def, guardVa, 0) + ) + or + guardedHashConsNotEqualZero(expr) + } + + predicate guardedHashConsNotEqualZero(Expr e) { + /* Note Boolean cmpEq, false means cmpNeq */ + exists(Expr check, Expr val, int valVal, GuardCondition guard, boolean cmpEq | + hashCons(check) = hashCons(e) and + valVal = getValue(val).toFloat() and + guard.controls(e.getBasicBlock(), cmpEq) and + ( + guard.comparesEq(check, val, -valVal, false, cmpEq) or + guard.comparesEq(val, check, -valVal, false, cmpEq) + ) + ) + } + + /** Set of expressions which we know how to analyze. */ + predicate analyzableExpr(Expr e) { + // The type of the expression must be arithmetic. We reuse the logic in + // `exprMinVal` to check this. + exists(Util::exprMinVal(e)) and + ( + exists(getValue(e).toFloat()) + or + effectivelyMultipliesByPositive(e, _, _) + or + effectivelyMultipliesByNegative(e, _, _) + or + dividesByPositive(e, _, _) + or + dividesByNegative(e, _, _) + or + // Introduces non-monotonic recursion. However, analysis mostly works with this + // commented out. + // or + // dividesNonzeroByZero(e) + e instanceof DivExpr // TODO: confirm this is OK + or + supportedMathFunction(e) + or + e instanceof MinExpr + or + e instanceof MaxExpr + or + e instanceof ConditionalExpr + or + e instanceof AddExpr + or + e instanceof SubExpr + or + e instanceof UnsignedMulExpr + or + e instanceof AssignExpr + or + e instanceof AssignAddExpr + or + e instanceof AssignSubExpr + or + e instanceof UnsignedAssignMulExpr + or + e instanceof AssignMulByConstantExpr + or + e instanceof CrementOperation + or + e instanceof RemExpr + or + // A conversion is analyzable, provided that its child has an arithmetic + // type. (Sometimes the child is a reference type, and so does not get + // any bounds.) Rather than checking whether the type of the child is + // arithmetic, we reuse the logic that is already encoded in + // `exprMinVal`. + exists(Util::exprMinVal(e.(Conversion).getExpr())) + or + // Also allow variable accesses, provided that they have SSA + // information. + exists(RangeSsaDefinition def | e = def.getAUse(_)) + or + e instanceof UnsignedBitwiseAndExpr + or + // `>>` by a constant + exists(getValue(e.(RShiftExpr).getRightOperand())) + ) + } + + /** + * Set of definitions that this definition depends on. The transitive + * closure of this relation is used to detect definitions which are + * recursively defined, so that we can prevent the analysis from exploding. + * + * The structure of `defDependsOnDef` and its helper predicates matches the + * structure of `getDefLowerBoundsImpl` and + * `getDefUpperBoundsImpl`. Therefore, if changes are made to the structure + * of the main analysis algorithm then matching changes need to be made + * here. + */ + private predicate defDependsOnDef( + RangeSsaDefinition def, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar + ) { + // Definitions with a defining value. + exists(Expr expr | assignmentDef(def, v, expr) | exprDependsOnDef(expr, srcDef, srcVar)) + or + // Assignment operations with a defining value + exists(AssignOperation assignOp | + analyzableExpr(assignOp) and + def = assignOp and + def.getAVariable() = v and + exprDependsOnDef(assignOp, srcDef, srcVar) + ) + or + exists(CrementOperation crem | + def = crem and + def.getAVariable() = v and + exprDependsOnDef(crem.getOperand(), srcDef, srcVar) + ) + or + // Phi nodes. + phiDependsOnDef(def, v, srcDef, srcVar) + } + + /** + * Helper predicate for `defDependsOnDef`. This predicate matches + * the structure of `getLowerBoundsImpl` and `getUpperBoundsImpl`. + */ + private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVariable srcVar) { + exists(Expr operand | + effectivelyMultipliesByNegative(e, operand, _) and + exprDependsOnDef(operand, srcDef, srcVar) + ) + or + exists(Expr operand | + effectivelyMultipliesByPositive(e, operand, _) and + exprDependsOnDef(operand, srcDef, srcVar) + ) + or + exists(Expr operand | + (dividesByPositive(e, operand, _) or dividesByNegative(e, operand, _)) and + exprDependsOnDef(operand, srcDef, srcVar) + ) + or + exists(DivExpr div | div = e | exprDependsOnDef(div.getAnOperand(), srcDef, srcVar)) + or + exists(MinExpr minExpr | e = minExpr | exprDependsOnDef(minExpr.getAnOperand(), srcDef, srcVar)) + or + exists(MaxExpr maxExpr | e = maxExpr | exprDependsOnDef(maxExpr.getAnOperand(), srcDef, srcVar)) + or + exists(ConditionalExpr condExpr | e = condExpr | + exprDependsOnDef(condExpr.getAnOperand(), srcDef, srcVar) + ) + or + exists(AddExpr addExpr | e = addExpr | exprDependsOnDef(addExpr.getAnOperand(), srcDef, srcVar)) + or + exists(SubExpr subExpr | e = subExpr | exprDependsOnDef(subExpr.getAnOperand(), srcDef, srcVar)) + or + exists(UnsignedMulExpr mulExpr | e = mulExpr | + exprDependsOnDef(mulExpr.getAnOperand(), srcDef, srcVar) + ) + or + exists(AssignExpr addExpr | e = addExpr | exprDependsOnDef(addExpr.getRValue(), srcDef, srcVar)) + or + exists(AssignAddExpr addExpr | e = addExpr | + exprDependsOnDef(addExpr.getAnOperand(), srcDef, srcVar) + ) + or + exists(AssignSubExpr subExpr | e = subExpr | + exprDependsOnDef(subExpr.getAnOperand(), srcDef, srcVar) + ) + or + exists(UnsignedAssignMulExpr mulExpr | e = mulExpr | + exprDependsOnDef(mulExpr.getAnOperand(), srcDef, srcVar) + ) + or + exists(AssignMulByConstantExpr mulExpr | e = mulExpr | + exprDependsOnDef(mulExpr.getLValue(), srcDef, srcVar) + ) + or + exists(CrementOperation crementExpr | e = crementExpr | + exprDependsOnDef(crementExpr.getOperand(), srcDef, srcVar) + ) + or + exists(RemExpr remExpr | e = remExpr | exprDependsOnDef(remExpr.getAnOperand(), srcDef, srcVar)) + or + exists(Conversion convExpr | e = convExpr | + exprDependsOnDef(convExpr.getExpr(), srcDef, srcVar) + ) + or + // unsigned `&` + exists(UnsignedBitwiseAndExpr andExpr | + andExpr = e and + exprDependsOnDef(andExpr.getAnOperand(), srcDef, srcVar) + ) + or + // `>>` by a constant + exists(RShiftExpr rs | + rs = e and + exists(getValue(rs.getRightOperand())) and + exprDependsOnDef(rs.getLeftOperand(), srcDef, srcVar) + ) + or + e = srcDef.getAUse(srcVar) + } + + /** + * Helper predicate for `defDependsOnDef`. This predicate matches + * the structure of `getPhiLowerBounds` and `getPhiUpperBounds`. + */ + private predicate phiDependsOnDef( + RangeSsaDefinition phi, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar + ) { + exists(VariableAccess access, Expr guard | phi.isGuardPhi(v, access, guard, _) | + exprDependsOnDef(guard.(ComparisonOperation).getAnOperand(), srcDef, srcVar) or + exprDependsOnDef(access, srcDef, srcVar) + ) + or + srcDef = phi.getAPhiInput(v) and srcVar = v + } + + /** The transitive closure of `defDependsOnDef`. */ + private predicate defDependsOnDefTransitively( + RangeSsaDefinition def, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar + ) { + defDependsOnDef(def, v, srcDef, srcVar) + or + exists(RangeSsaDefinition midDef, StackVariable midVar | + defDependsOnDef(def, v, midDef, midVar) + | + defDependsOnDefTransitively(midDef, midVar, srcDef, srcVar) + ) + } + + /** The set of definitions that depend recursively on themselves. */ + private predicate isRecursiveDef(RangeSsaDefinition def, StackVariable v) { + defDependsOnDefTransitively(def, v, def, v) + } + + /** + * Holds if the bounds of `e` depend on a recursive definition, meaning that + * `e` is likely to have many candidate bounds during the main recursion. + */ + private predicate isRecursiveExpr(Expr e) { + exists(RangeSsaDefinition def, StackVariable v | exprDependsOnDef(e, def, v) | + isRecursiveDef(def, v) + ) + } + + /** + * Holds if `binop` is a binary operation that's likely to be assigned a + * quadratic (or more) number of candidate bounds during the analysis. This can + * happen when two conditions are satisfied: + * 1. It is likely there are many more candidate bounds for `binop` than for + * its operands. For example, the number of candidate bounds for `x + y`, + * denoted here nbounds(`x + y`), will be O(nbounds(`x`) * nbounds(`y`)). + * In contrast, nbounds(`b ? x : y`) is only O(nbounds(`x`) + nbounds(`y`)). + * 2. Both operands of `binop` are recursively determined and are therefore + * likely to have a large number of candidate bounds. + */ + private predicate isRecursiveBinary(BinaryOperation binop) { + ( + binop instanceof UnsignedMulExpr + or + binop instanceof AddExpr + or + binop instanceof SubExpr + ) and + isRecursiveExpr(binop.getLeftOperand()) and + isRecursiveExpr(binop.getRightOperand()) + } + + private predicate applyWideningToBinary(BinaryOperation op) { + // Original behavior: + isRecursiveBinary(op) + or + // As we added support for DivExpr, we found cases of combinatorial explosion that are not + // caused by recursion. Given expr `x` that depends on a phi node that has evaluated y unique + // values, `x + x` will in the worst case evaluate to y^2 unique values, even if `x` is not + // recursive. By adding support for division, we have revealed certain pathological cases in + // open source code, for instance `posix_time_from_utc` from boringssl. We can reduce this + // greatly by widening, and targeting division effectively reduces the chains of evaluations + // that cause this issue while preserving the original behavior. + // + // There is also a set of functions intended to estimate the combinations of phi nodes each + // expression depends on, which could be used to accurately widen only expensive nodes. However, + // that estimation is more involved than it may seem, and hasn't yet resulted in a net + // improvement. See `estimatedPhiCombinationsExpr` and `estimatedPhiCombinationsDef`. + // + // This approach currently has the best performance. + op instanceof DivExpr + } + + /** + * Recursively scan this expr to see how many phi nodes it depends on. Binary expressions + * induce a combination effect, so `a + b` where `a` depends on 3 phi nodes and `b` depends on 4 + * will induce 3*4 = 12 phi node combinations. + * + * This currently requires additional optimization to be useful in practice. + */ + int estimatedPhiCombinationsExpr(Expr expr) { + if isRecursiveExpr(expr) + then + // Assume 10 values were computed to analyze recursive expressions. + result = 10 + else ( + exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) | + def.isPhiNode(v) and + result = estimatedPhiCombinationsDef(def, v) + ) + or + exists(BinaryOperation binop | + binop = expr and + result = + estimatedPhiCombinationsExpr(binop.getLeftOperand()) * + estimatedPhiCombinationsExpr(binop.getRightOperand()) + ) + or + not expr instanceof BinaryOperation and + exists(RangeSsaDefinition def, StackVariable v | exprDependsOnDef(expr, def, v) | + result = estimatedPhiCombinationsDef(def, v) + ) + or + not expr instanceof BinaryOperation and + not exprDependsOnDef(expr, _, _) and + result = 1 + ) + } + + /** + * Recursively scan this def to see how many phi nodes it depends on. + * + * If this def is a phi node, it sums its downstream cost and adds one to account for itself, + * which is not exactly correct. + * + * This def may also be a crement expression (not currently supported), or an assign expr + * (currently not supported), or an unanalyzable expression which is the root of the recursion + * and given a value of 1. + */ + language[monotonicAggregates] + int estimatedPhiCombinationsDef(RangeSsaDefinition def, StackVariable v) { + if isRecursiveDef(def, v) + then + // Assume 10 values were computed to analyze recursive expressions. + result = 10 + else ( + if def.isPhiNode(v) + then + exists(Expr e | e = def.getAUse(v) | + result = + 1 + + sum(RangeSsaDefinition srcDef | + srcDef = def.getAPhiInput(v) + | + estimatedPhiCombinationsDef(srcDef, v) + ) + ) + else ( + exists(Expr expr | assignmentDef(def, v, expr) | + result = estimatedPhiCombinationsExpr(expr) + ) + or + v = def.getAVariable() and + not assignmentDef(def, v, _) and + result = 1 + ) + ) + } + + /** + * We distinguish 3 kinds of RangeSsaDefinition: + * + * 1. Definitions with a defining value. + * For example: x = y+3 is a definition of x with defining value y+3. + * + * 2. Phi nodes: x3 = phi(x0,x1,x2) + * + * 3. Unanalyzable definitions. + * For example: a parameter is unanalyzable because we know nothing + * about its value. We assign these range [-largeValue(), largeValue()] + * + * This predicate finds all the definitions in the first set. + */ + private predicate assignmentDef(RangeSsaDefinition def, StackVariable v, Expr expr) { + Util::getVariableRangeType(v) instanceof ArithmeticType and + ( + def = v.getInitializer().getExpr() and def = expr + or + exists(AssignExpr assign | + def = assign and + assign.getLValue() = v.getAnAccess() and + expr = assign.getRValue() + ) + ) + } + + /** See comment above assignmentDef. */ + private predicate analyzableDef(RangeSsaDefinition def, StackVariable v) { + assignmentDef(def, v, _) + or + analyzableExpr(def.(AssignOperation)) and + v = def.getAVariable() + or + analyzableExpr(def.(CrementOperation)) and + v = def.getAVariable() + or + phiDependsOnDef(def, v, _, _) + } + + predicate canBoundExpr(Expr e) { + exists(RangeSsaDefinition def, StackVariable v | e = def.getAUse(v) | analyzableDef(def, v)) + or + analyzableExpr(e) + or + exists(getGuardedUpperBound(e)) + or + lowerBoundFromGuard(e, _, _, _) + } + + /** + * Computes a normal form of `x` where -0.0 has changed to +0.0. This can be + * needed on the lesser side of a floating-point comparison or on both sides of + * a floating point equality because QL does not follow IEEE in floating-point + * comparisons but instead defines -0.0 to be less than and distinct from 0.0. + */ + bindingset[x] + private float normalizeFloatUp(float x) { result = x + 0.0 } + + /** + * Computes `x + y`, rounded towards +Inf. This is the general case where both + * `x` and `y` may be large numbers. + */ + bindingset[x, y] + private float addRoundingUp(float x, float y) { + if normalizeFloatUp((x + y) - x) < y or normalizeFloatUp((x + y) - y) < x + then result = (x + y).nextUp() + else result = (x + y) + } + + /** + * Computes `x + y`, rounded towards -Inf. This is the general case where both + * `x` and `y` may be large numbers. + */ + bindingset[x, y] + private float addRoundingDown(float x, float y) { + if (x + y) - x > normalizeFloatUp(y) or (x + y) - y > normalizeFloatUp(x) + then result = (x + y).nextDown() + else result = (x + y) + } + + /** + * Computes `x + small`, rounded towards +Inf, where `small` is a small + * constant. + */ + bindingset[x, small] + private float addRoundingUpSmall(float x, float small) { + if (x + small) - x < small then result = (x + small).nextUp() else result = (x + small) + } + + /** + * Computes `x + small`, rounded towards -Inf, where `small` is a small + * constant. + */ + bindingset[x, small] + private float addRoundingDownSmall(float x, float small) { + if (x + small) - x > small then result = (x + small).nextDown() else result = (x + small) + } + + private predicate lowerBoundableExpr(Expr expr) { + (analyzableExpr(expr) or dividesNonzeroByZero(expr)) and + getUpperBoundsImpl(expr) <= Util::exprMaxVal(expr) and + not exists(getValue(expr).toFloat()) + } + + /** + * Gets the lower bounds of the expression. + * + * Most of the work of computing the lower bounds is done by + * `getLowerBoundsImpl`. However, the lower bounds computed by + * `getLowerBoundsImpl` may not be representable by the result type of the + * expression. For example, if `x` and `y` are of type `int32` and each + * have lower bound -2147483648, then getLowerBoundsImpl` will compute a + * lower bound -4294967296 for the expression `x+y`, even though + * -4294967296 cannot be represented as an `int32`. Such unrepresentable + * bounds are replaced with `exprMinVal(expr)`. This predicate also adds + * `exprMinVal(expr)` as a lower bound if the expression might overflow + * positively, or if it is unanalyzable. + * + * Note: most callers should use `getFullyConvertedLowerBounds` rather than + * this predicate. + */ + private float getTruncatedLowerBounds(Expr expr) { + // If the expression evaluates to a constant, then there is no + // need to call getLowerBoundsImpl. + analyzableExpr(expr) and + result = getValue(expr).toFloat() + or + // Some of the bounds computed by getLowerBoundsImpl might + // overflow, so we replace invalid bounds with exprMinVal. + exists(float newLB | newLB = normalizeFloatUp(getLowerBoundsImpl(expr)) | + if Util::exprMinVal(expr) <= newLB and newLB <= Util::exprMaxVal(expr) + then + // Apply widening where we might get a combinatorial explosion. + if applyWideningToBinary(expr) + then + result = + max(float widenLB | + widenLB = wideningLowerBounds(expr.getUnspecifiedType()) and + not widenLB > newLB + ) + else result = newLB + else result = Util::exprMinVal(expr) + ) and + lowerBoundableExpr(expr) + or + // The expression might overflow and wrap. If so, the + // lower bound is exprMinVal. + analyzableExpr(expr) and + exprMightOverflowPositively(expr) and + not result = getValue(expr).toFloat() and + result = Util::exprMinVal(expr) + or + // The expression is not analyzable, so its lower bound is + // unknown. Note that the call to exprMinVal restricts the + // expressions to just those with arithmetic types. There is no + // need to return results for non-arithmetic expressions. + not analyzableExpr(expr) and + result = exprMinVal(expr) + } + + /** + * Gets the upper bounds of the expression. + * + * Most of the work of computing the upper bounds is done by + * `getUpperBoundsImpl`. However, the upper bounds computed by + * `getUpperBoundsImpl` may not be representable by the result type of the + * expression. For example, if `x` and `y` are of type `int32` and each + * have upper bound 2147483647, then getUpperBoundsImpl` will compute an + * upper bound 4294967294 for the expression `x+y`, even though 4294967294 + * cannot be represented as an `int32`. Such unrepresentable bounds are + * replaced with `exprMaxVal(expr)`. This predicate also adds + * `exprMaxVal(expr)` as an upper bound if the expression might overflow + * negatively, or if it is unanalyzable. + * + * Note: most callers should use `getFullyConvertedUpperBounds` rather than + * this predicate. + */ + private float getTruncatedUpperBounds(Expr expr) { + (analyzableExpr(expr) or dividesNonzeroByZero(expr)) and + ( + // If the expression evaluates to a constant, then there is no + // need to call getUpperBoundsImpl. + if + exists(getValue(expr).toFloat()) and + not getValue(expr) = "NaN" + then result = getValue(expr).toFloat() + else ( + // Some of the bounds computed by `getUpperBoundsImpl` + // might overflow, so we replace invalid bounds with + // `exprMaxVal`. + exists(float newUB | newUB = normalizeFloatUp(getUpperBoundsImpl(expr)) | + if Util::exprMinVal(expr) <= newUB and newUB <= Util::exprMaxVal(expr) + then + // Apply widening where we might get a combinatorial explosion. + if applyWideningToBinary(expr) + then + result = + min(float widenUB | + widenUB = wideningUpperBounds(expr.getUnspecifiedType()) and + not widenUB < newUB + ) + else result = newUB + else result = Util::exprMaxVal(expr) + ) + or + // The expression might overflow negatively and wrap. If so, + // the upper bound is `exprMaxVal`. + exprMightOverflowNegatively(expr) and + result = Util::exprMaxVal(expr) + ) + ) + or + not analyzableExpr(expr) and + // The expression is not analyzable, so its upper bound is + // unknown. Note that the call to exprMaxVal restricts the + // expressions to just those with arithmetic types. There is no + // need to return results for non-arithmetic expressions. + result = exprMaxVal(expr) + } + + /** Only to be called by `getTruncatedLowerBounds`. */ + private float getLowerBoundsImpl(Expr expr) { + ( + exists(Expr operand, float operandLow, float positive | + effectivelyMultipliesByPositive(expr, operand, positive) and + operandLow = getFullyConvertedLowerBounds(operand) and + result = positive * operandLow + ) + or + exists(Expr operand, float operandHigh, float negative | + effectivelyMultipliesByNegative(expr, operand, negative) and + operandHigh = getFullyConvertedUpperBounds(operand) and + result = negative * operandHigh + ) + or + exists(Expr operand, float operandLow, float positive | + dividesByPositive(expr, operand, positive) and + operandLow = getFullyConvertedLowerBounds(operand) and + result = operandLow / positive + ) + or + exists(Expr operand, float operandLow, float negative | + dividesByNegative(expr, operand, negative) and + operandLow = getFullyConvertedUpperBounds(operand) and + result = operandLow / negative + ) + or + exists(DivExpr div | expr = div | + dividesNonzeroByZero(expr) and + result = getFullyConvertedLowerBounds(div.getLeftOperand()) / 0 + ) + or + exists(SupportedFunctionCall sfc | sfc.getFunctionCall() = expr | + result = sfc.getLowerBound() + ) + or + exists(MinExpr minExpr | + expr = minExpr and + // Return the union of the lower bounds from both children. + result = getFullyConvertedLowerBounds(minExpr.getAnOperand()) + ) + or + exists(MaxExpr maxExpr | + expr = maxExpr and + // Compute the cross product of the bounds from both children. We are + // using this mathematical property: + // + // max (minimum{X}, minimum{Y}) + // = minimum { max(x,y) | x in X, y in Y } + exists(float x, float y | + x = getFullyConvertedLowerBounds(maxExpr.getLeftOperand()) and + y = getFullyConvertedLowerBounds(maxExpr.getRightOperand()) and + if x >= y then result = x else result = y + ) + ) + or + // ConditionalExpr (true branch) + exists(ConditionalExpr condExpr | + expr = condExpr and + // Use `boolConversionUpperBound` to determine whether the condition + // might evaluate to `true`. + boolConversionUpperBound(condExpr.getCondition().getFullyConverted()) = 1 and + result = getFullyConvertedLowerBounds(condExpr.getThen()) + ) + or + // ConditionalExpr (false branch) + exists(ConditionalExpr condExpr | + expr = condExpr and + // Use `boolConversionLowerBound` to determine whether the condition + // might evaluate to `false`. + boolConversionLowerBound(condExpr.getCondition().getFullyConverted()) = 0 and + result = getFullyConvertedLowerBounds(condExpr.getElse()) + ) + or + exists(AddExpr addExpr, float xLow, float yLow | + expr = addExpr and + xLow = getFullyConvertedLowerBounds(addExpr.getLeftOperand()) and + yLow = getFullyConvertedLowerBounds(addExpr.getRightOperand()) and + result = addRoundingDown(xLow, yLow) + ) + or + exists(SubExpr subExpr, float xLow, float yHigh | + expr = subExpr and + xLow = getFullyConvertedLowerBounds(subExpr.getLeftOperand()) and + yHigh = getFullyConvertedUpperBounds(subExpr.getRightOperand()) and + result = addRoundingDown(xLow, -yHigh) + ) + or + exists(UnsignedMulExpr mulExpr, float xLow, float yLow | + expr = mulExpr and + xLow = getFullyConvertedLowerBounds(mulExpr.getLeftOperand()) and + yLow = getFullyConvertedLowerBounds(mulExpr.getRightOperand()) and + result = xLow * yLow + ) + or + exists(AssignExpr assign | + expr = assign and + result = getFullyConvertedLowerBounds(assign.getRValue()) + ) + or + exists(AssignAddExpr addExpr, float xLow, float yLow | + expr = addExpr and + xLow = getFullyConvertedLowerBounds(addExpr.getLValue()) and + yLow = getFullyConvertedLowerBounds(addExpr.getRValue()) and + result = addRoundingDown(xLow, yLow) + ) + or + exists(AssignSubExpr subExpr, float xLow, float yHigh | + expr = subExpr and + xLow = getFullyConvertedLowerBounds(subExpr.getLValue()) and + yHigh = getFullyConvertedUpperBounds(subExpr.getRValue()) and + result = addRoundingDown(xLow, -yHigh) + ) + or + exists(UnsignedAssignMulExpr mulExpr, float xLow, float yLow | + expr = mulExpr and + xLow = getFullyConvertedLowerBounds(mulExpr.getLValue()) and + yLow = getFullyConvertedLowerBounds(mulExpr.getRValue()) and + result = xLow * yLow + ) + or + exists(AssignMulByPositiveConstantExpr mulExpr, float xLow | + expr = mulExpr and + xLow = getFullyConvertedLowerBounds(mulExpr.getLValue()) and + result = xLow * mulExpr.getConstant() + ) + or + exists(AssignMulByNegativeConstantExpr mulExpr, float xHigh | + expr = mulExpr and + xHigh = getFullyConvertedUpperBounds(mulExpr.getLValue()) and + result = xHigh * mulExpr.getConstant() + ) + or + exists(PrefixIncrExpr incrExpr, float xLow | + expr = incrExpr and + xLow = getFullyConvertedLowerBounds(incrExpr.getOperand()) and + result = xLow + 1 + ) + or + exists(PrefixDecrExpr decrExpr, float xLow | + expr = decrExpr and + xLow = getFullyConvertedLowerBounds(decrExpr.getOperand()) and + result = addRoundingDownSmall(xLow, -1) + ) + or + // `PostfixIncrExpr` and `PostfixDecrExpr` return the value of their + // operand. The incrementing/decrementing behavior is handled in + // `getDefLowerBoundsImpl`. + exists(PostfixIncrExpr incrExpr | + expr = incrExpr and + result = getFullyConvertedLowerBounds(incrExpr.getOperand()) + ) + or + exists(PostfixDecrExpr decrExpr | + expr = decrExpr and + result = getFullyConvertedLowerBounds(decrExpr.getOperand()) + ) + or + exists(RemExpr remExpr | expr = remExpr | + // If both inputs are positive then the lower bound is zero. + result = 0 + or + // If either input could be negative then the output could be + // negative. If so, the lower bound of `x%y` is `-abs(y) + 1`, which is + // equal to `min(-y + 1,y - 1)`. + exists(float childLB | + childLB = getFullyConvertedLowerBounds(remExpr.getAnOperand()) and + not childLB >= 0 + | + result = getFullyConvertedLowerBounds(remExpr.getRightOperand()) - 1 + or + exists(float rhsUB | rhsUB = getFullyConvertedUpperBounds(remExpr.getRightOperand()) | + result = -rhsUB + 1 + ) + ) + ) + or + // If the conversion is to an arithmetic type then we just return the + // lower bound of the child. We do not need to handle truncation and + // overflow here, because that is done in `getTruncatedLowerBounds`. + // Conversions to `bool` need to be handled specially because they test + // whether the value of the expression is equal to 0. + exists(Conversion convExpr | expr = convExpr | + if convExpr.getUnspecifiedType() instanceof BoolType + then result = boolConversionLowerBound(convExpr.getExpr()) + else result = getTruncatedLowerBounds(convExpr.getExpr()) + ) + or + // Use SSA to get the lower bounds for a variable use. + exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) | + result = getDefLowerBounds(def, v) + ) + or + // unsigned `&` (tighter bounds may exist) + exists(UnsignedBitwiseAndExpr andExpr | + andExpr = expr and + result = 0.0 + ) + or + // `>>` by a constant + exists(RShiftExpr rsExpr, float left, int right | + rsExpr = expr and + left = getFullyConvertedLowerBounds(rsExpr.getLeftOperand()) and + right = getValue(rsExpr.getRightOperand().getFullyConverted()).toInt() and + result = safeFloor(left / 2.pow(right)) + ) + ) + } + + /** Only to be called by `getTruncatedUpperBounds`. */ + private float getUpperBoundsImpl(Expr expr) { + ( + exists(Expr operand, float operandHigh, float positive | + effectivelyMultipliesByPositive(expr, operand, positive) and + operandHigh = getFullyConvertedUpperBounds(operand) and + result = positive * operandHigh + ) + or + exists(Expr operand, float operandLow, float negative | + effectivelyMultipliesByNegative(expr, operand, negative) and + operandLow = getFullyConvertedLowerBounds(operand) and + result = negative * operandLow + ) + or + exists(Expr operand, float operandHigh, float positive | + dividesByPositive(expr, operand, positive) and + operandHigh = getFullyConvertedUpperBounds(operand) and + result = operandHigh / positive + ) + or + exists(Expr operand, float operandHigh, float negative | + dividesByNegative(expr, operand, negative) and + operandHigh = getFullyConvertedLowerBounds(operand) and + result = operandHigh / negative + ) + or + exists(DivExpr div | expr = div | + dividesNonzeroByZero(expr) and + result = getFullyConvertedUpperBounds(div.getLeftOperand()) / 0 + ) + or + exists(SupportedFunctionCall sfc | sfc.getFunctionCall() = expr | + result = sfc.getUpperBound() + ) + or + exists(MaxExpr maxExpr | + expr = maxExpr and + // Return the union of the upper bounds from both children. + result = getFullyConvertedUpperBounds(maxExpr.getAnOperand()) + ) + or + exists(MinExpr minExpr | + expr = minExpr and + // Compute the cross product of the bounds from both children. We are + // using this mathematical property: + // + // min (maximum{X}, maximum{Y}) + // = maximum { min(x,y) | x in X, y in Y } + exists(float x, float y | + x = getFullyConvertedUpperBounds(minExpr.getLeftOperand()) and + y = getFullyConvertedUpperBounds(minExpr.getRightOperand()) and + if x <= y then result = x else result = y + ) + ) + or + // ConditionalExpr (true branch) + exists(ConditionalExpr condExpr | + expr = condExpr and + // Use `boolConversionUpperBound` to determine whether the condition + // might evaluate to `true`. + boolConversionUpperBound(condExpr.getCondition().getFullyConverted()) = 1 and + result = getFullyConvertedUpperBounds(condExpr.getThen()) + ) + or + // ConditionalExpr (false branch) + exists(ConditionalExpr condExpr | + expr = condExpr and + // Use `boolConversionLowerBound` to determine whether the condition + // might evaluate to `false`. + boolConversionLowerBound(condExpr.getCondition().getFullyConverted()) = 0 and + result = getFullyConvertedUpperBounds(condExpr.getElse()) + ) + or + exists(AddExpr addExpr, float xHigh, float yHigh | + expr = addExpr and + xHigh = getFullyConvertedUpperBounds(addExpr.getLeftOperand()) and + yHigh = getFullyConvertedUpperBounds(addExpr.getRightOperand()) and + result = addRoundingUp(xHigh, yHigh) + ) + or + exists(SubExpr subExpr, float xHigh, float yLow | + expr = subExpr and + xHigh = getFullyConvertedUpperBounds(subExpr.getLeftOperand()) and + yLow = getFullyConvertedLowerBounds(subExpr.getRightOperand()) and + result = addRoundingUp(xHigh, -yLow) + ) + or + exists(UnsignedMulExpr mulExpr, float xHigh, float yHigh | + expr = mulExpr and + xHigh = getFullyConvertedUpperBounds(mulExpr.getLeftOperand()) and + yHigh = getFullyConvertedUpperBounds(mulExpr.getRightOperand()) and + result = xHigh * yHigh + ) + or + exists(AssignExpr assign | + expr = assign and + result = getFullyConvertedUpperBounds(assign.getRValue()) + ) + or + exists(AssignAddExpr addExpr, float xHigh, float yHigh | + expr = addExpr and + xHigh = getFullyConvertedUpperBounds(addExpr.getLValue()) and + yHigh = getFullyConvertedUpperBounds(addExpr.getRValue()) and + result = addRoundingUp(xHigh, yHigh) + ) + or + exists(AssignSubExpr subExpr, float xHigh, float yLow | + expr = subExpr and + xHigh = getFullyConvertedUpperBounds(subExpr.getLValue()) and + yLow = getFullyConvertedLowerBounds(subExpr.getRValue()) and + result = addRoundingUp(xHigh, -yLow) + ) + or + exists(UnsignedAssignMulExpr mulExpr, float xHigh, float yHigh | + expr = mulExpr and + xHigh = getFullyConvertedUpperBounds(mulExpr.getLValue()) and + yHigh = getFullyConvertedUpperBounds(mulExpr.getRValue()) and + result = xHigh * yHigh + ) + or + exists(AssignMulByPositiveConstantExpr mulExpr, float xHigh | + expr = mulExpr and + xHigh = getFullyConvertedUpperBounds(mulExpr.getLValue()) and + result = xHigh * mulExpr.getConstant() + ) + or + exists(AssignMulByNegativeConstantExpr mulExpr, float xLow | + expr = mulExpr and + xLow = getFullyConvertedLowerBounds(mulExpr.getLValue()) and + result = xLow * mulExpr.getConstant() + ) + or + exists(PrefixIncrExpr incrExpr, float xHigh | + expr = incrExpr and + xHigh = getFullyConvertedUpperBounds(incrExpr.getOperand()) and + result = addRoundingUpSmall(xHigh, 1) + ) + or + exists(PrefixDecrExpr decrExpr, float xHigh | + expr = decrExpr and + xHigh = getFullyConvertedUpperBounds(decrExpr.getOperand()) and + result = xHigh - 1 + ) + or + // `PostfixIncrExpr` and `PostfixDecrExpr` return the value of their operand. + // The incrementing/decrementing behavior is handled in + // `getDefUpperBoundsImpl`. + exists(PostfixIncrExpr incrExpr | + expr = incrExpr and + result = getFullyConvertedUpperBounds(incrExpr.getOperand()) + ) + or + exists(PostfixDecrExpr decrExpr | + expr = decrExpr and + result = getFullyConvertedUpperBounds(decrExpr.getOperand()) + ) + or + exists(RemExpr remExpr, float rhsUB | + expr = remExpr and + rhsUB = getFullyConvertedUpperBounds(remExpr.getRightOperand()) + | + result = rhsUB - 1 + or + // If the right hand side could be negative then we need to take its + // absolute value. Since `abs(x) = max(-x,x)` this is equivalent to + // adding `-rhsLB` to the set of upper bounds. + exists(float rhsLB | + rhsLB = getFullyConvertedLowerBounds(remExpr.getRightOperand()) and + not rhsLB >= 0 + | + result = -rhsLB + 1 + ) + ) + or + // If the conversion is to an arithmetic type then we just return the + // upper bound of the child. We do not need to handle truncation and + // overflow here, because that is done in `getTruncatedUpperBounds`. + // Conversions to `bool` need to be handled specially because they test + // whether the value of the expression is equal to 0. + exists(Conversion convExpr | expr = convExpr | + if convExpr.getUnspecifiedType() instanceof BoolType + then result = boolConversionUpperBound(convExpr.getExpr()) + else result = getTruncatedUpperBounds(convExpr.getExpr()) + ) + or + // Use SSA to get the upper bounds for a variable use. + exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) | + result = getDefUpperBounds(def, v) + ) + or + // unsigned `&` (tighter bounds may exist) + exists(UnsignedBitwiseAndExpr andExpr, float left, float right | + andExpr = expr and + left = getFullyConvertedUpperBounds(andExpr.getLeftOperand()) and + right = getFullyConvertedUpperBounds(andExpr.getRightOperand()) and + result = left.minimum(right) + ) + or + // `>>` by a constant + exists(RShiftExpr rsExpr, float left, int right | + rsExpr = expr and + left = getFullyConvertedUpperBounds(rsExpr.getLeftOperand()) and + right = getValue(rsExpr.getRightOperand().getFullyConverted()).toInt() and + result = safeFloor(left / 2.pow(right)) + ) + ) + } + + /** + * Holds if `expr` is converted to `bool` or if it is the child of a + * logical operation. + * + * The purpose of this predicate is to optimize `boolConversionLowerBound` + * and `boolConversionUpperBound` by preventing them from computing + * unnecessary results. In other words, `exprIsUsedAsBool(expr)` holds if + * `expr` is an expression that might be passed as an argument to + * `boolConversionLowerBound` or `boolConversionUpperBound`. + */ + private predicate exprIsUsedAsBool(Expr expr) { + expr = any(BinaryLogicalOperation op).getAnOperand().getFullyConverted() + or + expr = any(UnaryLogicalOperation op).getOperand().getFullyConverted() + or + expr = any(ConditionalExpr c).getCondition().getFullyConverted() + or + exists(Conversion cast | cast.getUnspecifiedType() instanceof BoolType | expr = cast.getExpr()) + } + + /** + * Gets the lower bound of the conversion `(bool)expr`. If we can prove that + * the value of `expr` is never 0 then `lb = 1`. Otherwise `lb = 0`. + */ + private float boolConversionLowerBound(Expr expr) { + // Case 1: if the range for `expr` includes the value 0, + // then `result = 0`. + exprIsUsedAsBool(expr) and + exists(float lb | lb = getTruncatedLowerBounds(expr) and not lb > 0) and + exists(float ub | ub = getTruncatedUpperBounds(expr) and not ub < 0) and + result = 0 + or + // Case 2a: if the range for `expr` does not include the value 0, + // then `result = 1`. + exprIsUsedAsBool(expr) and getTruncatedLowerBounds(expr) > 0 and result = 1 + or + // Case 2b: if the range for `expr` does not include the value 0, + // then `result = 1`. + exprIsUsedAsBool(expr) and getTruncatedUpperBounds(expr) < 0 and result = 1 + or + // Case 3: the type of `expr` is not arithmetic. For example, it might + // be a pointer. + exprIsUsedAsBool(expr) and not exists(Util::exprMinVal(expr)) and result = 0 + } + + /** + * Gets the upper bound of the conversion `(bool)expr`. If we can prove that + * the value of `expr` is always 0 then `ub = 0`. Otherwise `ub = 1`. + */ + private float boolConversionUpperBound(Expr expr) { + // Case 1a: if the upper bound of the operand is <= 0, then the upper + // bound might be 0. + exprIsUsedAsBool(expr) and getTruncatedUpperBounds(expr) <= 0 and result = 0 + or + // Case 1b: if the upper bound of the operand is not <= 0, then the upper + // bound is 1. + exprIsUsedAsBool(expr) and + exists(float ub | ub = getTruncatedUpperBounds(expr) and not ub <= 0) and + result = 1 + or + // Case 2a: if the lower bound of the operand is >= 0, then the upper + // bound might be 0. + exprIsUsedAsBool(expr) and getTruncatedLowerBounds(expr) >= 0 and result = 0 + or + // Case 2b: if the lower bound of the operand is not >= 0, then the upper + // bound is 1. + exprIsUsedAsBool(expr) and + exists(float lb | lb = getTruncatedLowerBounds(expr) and not lb >= 0) and + result = 1 + or + // Case 3: the type of `expr` is not arithmetic. For example, it might + // be a pointer. + exprIsUsedAsBool(expr) and not exists(Util::exprMaxVal(expr)) and result = 1 + } + + /** + * This predicate computes the lower bounds of a phi definition. If the + * phi definition corresponds to a guard, then the guard is used to + * deduce a better lower bound. + * For example: + * + * def: x = y % 10; + * guard: if (x >= 2) { + * block: f(x) + * } + * + * In this example, the lower bound of x is 0, but we can + * use the guard to deduce that the lower bound is 2 inside the block. + */ + private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) { + exists(VariableAccess access, Expr guard, boolean branch, float defLB, float guardLB | + phi.isGuardPhi(v, access, guard, branch) and + lowerBoundFromGuard(guard, access, guardLB, branch) and + defLB = getFullyConvertedLowerBounds(access) + | + // Compute the maximum of `guardLB` and `defLB`. + if guardLB > defLB then result = guardLB else result = defLB + ) + or + exists(VariableAccess access, float neConstant, float lower | + isNEPhi(v, phi, access, neConstant) and + lower = getTruncatedLowerBounds(access) and + if lower = neConstant then result = lower + 1 else result = lower + ) + or + exists(VariableAccess access | + isUnsupportedGuardPhi(v, phi, access) and + result = getTruncatedLowerBounds(access) + ) + or + result = getDefLowerBounds(phi.getAPhiInput(v), v) + } + + /** See comment for `getPhiLowerBounds`, above. */ + private float getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) { + exists(VariableAccess access, Expr guard, boolean branch, float defUB, float guardUB | + phi.isGuardPhi(v, access, guard, branch) and + upperBoundFromGuard(guard, access, guardUB, branch) and + defUB = getFullyConvertedUpperBounds(access) + | + // Compute the minimum of `guardUB` and `defUB`. + if guardUB < defUB then result = guardUB else result = defUB + ) + or + exists(VariableAccess access, float neConstant, float upper | + isNEPhi(v, phi, access, neConstant) and + upper = getTruncatedUpperBounds(access) and + if upper = neConstant then result = upper - 1 else result = upper + ) + or + exists(VariableAccess access | + isUnsupportedGuardPhi(v, phi, access) and + result = getTruncatedUpperBounds(access) + ) + or + result = getDefUpperBounds(phi.getAPhiInput(v), v) + } + + /** Only to be called by `getDefLowerBounds`. */ + private float getDefLowerBoundsImpl(RangeSsaDefinition def, StackVariable v) { + // Definitions with a defining value. + exists(Expr expr | assignmentDef(def, v, expr) | result = getFullyConvertedLowerBounds(expr)) + or + // Assignment operations with a defining value + exists(AssignOperation assignOp | + def = assignOp and + assignOp.getLValue() = v.getAnAccess() and + result = getTruncatedLowerBounds(assignOp) + ) + or + exists(IncrementOperation incr, float newLB | + def = incr and + incr.getOperand() = v.getAnAccess() and + newLB = getFullyConvertedLowerBounds(incr.getOperand()) and + result = newLB + 1 + ) + or + exists(DecrementOperation decr, float newLB | + def = decr and + decr.getOperand() = v.getAnAccess() and + newLB = getFullyConvertedLowerBounds(decr.getOperand()) and + result = addRoundingDownSmall(newLB, -1) + ) + or + // Phi nodes. + result = getPhiLowerBounds(v, def) + or + // Unanalyzable definitions. + unanalyzableDefBounds(def, v, result, _) + } + + /** Only to be called by `getDefUpperBounds`. */ + private float getDefUpperBoundsImpl(RangeSsaDefinition def, StackVariable v) { + // Definitions with a defining value. + exists(Expr expr | assignmentDef(def, v, expr) | result = getFullyConvertedUpperBounds(expr)) + or + // Assignment operations with a defining value + exists(AssignOperation assignOp | + def = assignOp and + assignOp.getLValue() = v.getAnAccess() and + result = getTruncatedUpperBounds(assignOp) + ) + or + exists(IncrementOperation incr, float newUB | + def = incr and + incr.getOperand() = v.getAnAccess() and + newUB = getFullyConvertedUpperBounds(incr.getOperand()) and + result = addRoundingUpSmall(newUB, 1) + ) + or + exists(DecrementOperation decr, float newUB | + def = decr and + decr.getOperand() = v.getAnAccess() and + newUB = getFullyConvertedUpperBounds(decr.getOperand()) and + result = newUB - 1 + ) + or + // Phi nodes. + result = getPhiUpperBounds(v, def) + or + // Unanalyzable definitions. + unanalyzableDefBounds(def, v, _, result) + } + + /** + * Helper for `getDefLowerBounds` and `getDefUpperBounds`. Find the set of + * unanalyzable definitions (such as function parameters) and make their + * bounds unknown. + */ + private predicate unanalyzableDefBounds( + RangeSsaDefinition def, StackVariable v, float lb, float ub + ) { + v = def.getAVariable() and + not analyzableDef(def, v) and + lb = varMinVal(v) and + ub = varMaxVal(v) + } + + /** + * Holds if in the `branch` branch of a guard `guard` involving `v`, + * we know that `v` is not NaN, and therefore it is safe to make range + * inferences about `v`. + */ + bindingset[guard, v, branch] + predicate nonNanGuardedVariable(Expr guard, VariableAccess v, boolean branch) { + Util::getVariableRangeType(v.getTarget()) instanceof IntegralType + or + Util::getVariableRangeType(v.getTarget()) instanceof FloatingPointType and + v instanceof NonNanVariableAccess + or + // The reason the following case is here is to ensure that when we say + // `if (x > 5) { ...then... } else { ...else... }` + // it is ok to conclude that `x > 5` in the `then`, (though not safe + // to conclude that x <= 5 in `else`) even if we had no prior + // knowledge of `x` not being `NaN`. + nanExcludingComparison(guard, branch) + } + + /** + * If the guard is a comparison of the form `p*v + q r`, then this + * predicate uses the bounds information for `r` to compute a lower bound + * for `v`. + */ + private predicate lowerBoundFromGuard(Expr guard, VariableAccess v, float lb, boolean branch) { + exists(float childLB, Util::RelationStrictness strictness | + boundFromGuard(guard, v, childLB, true, strictness, branch) + | + if nonNanGuardedVariable(guard, v, branch) + then + if + strictness = Util::Nonstrict() or + not Util::getVariableRangeType(v.getTarget()) instanceof IntegralType + then lb = childLB + else lb = childLB + 1 + else lb = varMinVal(v.getTarget()) + ) + } + + /** + * If the guard is a comparison of the form `p*v + q r`, then this + * predicate uses the bounds information for `r` to compute a upper bound + * for `v`. + */ + private predicate upperBoundFromGuard(Expr guard, VariableAccess v, float ub, boolean branch) { + exists(float childUB, Util::RelationStrictness strictness | + boundFromGuard(guard, v, childUB, false, strictness, branch) + | + if nonNanGuardedVariable(guard, v, branch) + then + if + strictness = Util::Nonstrict() or + not Util::getVariableRangeType(v.getTarget()) instanceof IntegralType + then ub = childUB + else ub = childUB - 1 + else ub = varMaxVal(v.getTarget()) + ) + } + + /** + * This predicate simplifies the results returned by + * `linearBoundFromGuard`. + */ + private predicate boundFromGuard( + Expr guard, VariableAccess v, float boundValue, boolean isLowerBound, + Util::RelationStrictness strictness, boolean branch + ) { + exists(float p, float q, float r, boolean isLB | + linearBoundFromGuard(guard, v, p, q, r, isLB, strictness, branch) and + boundValue = (r - q) / p + | + // If the multiplier is negative then the direction of the comparison + // needs to be flipped. + p > 0 and isLowerBound = isLB + or + p < 0 and isLowerBound = isLB.booleanNot() + ) + or + // When `!e` is true, we know that `0 <= e <= 0` + exists(float p, float q, Expr e | + Util::linearAccess(e, v, p, q) and + Util::eqZeroWithNegate(guard, e, true, branch) and + boundValue = (0.0 - q) / p and + isLowerBound = [false, true] and + strictness = Util::Nonstrict() + ) + } + + /** + * This predicate finds guards of the form `p*v + q < r or p*v + q == r` + * and decomposes them into a tuple of values which can be used to deduce a + * lower or upper bound for `v`. + */ + private predicate linearBoundFromGuard( + ComparisonOperation guard, VariableAccess v, float p, float q, float boundValue, + boolean isLowerBound, // Is this a lower or an upper bound? + Util::RelationStrictness strictness, boolean branch // Which control-flow branch is this bound valid on? + ) { + // For the comparison x < RHS, we create two bounds: + // + // 1. x < upperbound(RHS) + // 2. x >= typeLowerBound(RHS.getUnspecifiedType()) + // + exists(Expr lhs, Expr rhs, Util::RelationDirection dir, Util::RelationStrictness st | + Util::linearAccess(lhs, v, p, q) and + Util::relOpWithSwapAndNegate(guard, lhs, rhs, dir, st, branch) + | + isLowerBound = Util::directionIsGreater(dir) and + strictness = st and + getBounds(rhs, boundValue, isLowerBound) + or + isLowerBound = Util::directionIsLesser(dir) and + strictness = Util::Nonstrict() and + exprTypeBounds(rhs, boundValue, isLowerBound) + ) + or + // For x == RHS, we create the following bounds: + // + // 1. x <= upperbound(RHS) + // 2. x >= lowerbound(RHS) + // + exists(Expr lhs, Expr rhs | + Util::linearAccess(lhs, v, p, q) and + Util::eqOpWithSwapAndNegate(guard, lhs, rhs, true, branch) and + getBounds(rhs, boundValue, isLowerBound) and + strictness = Util::Nonstrict() + ) + // x != RHS and !x are handled elsewhere + } + + /** Utility for `linearBoundFromGuard`. */ + private predicate getBounds(Expr expr, float boundValue, boolean isLowerBound) { + isLowerBound = true and boundValue = getFullyConvertedLowerBounds(expr) + or + isLowerBound = false and boundValue = getFullyConvertedUpperBounds(expr) + } + + /** Utility for `linearBoundFromGuard`. */ + private predicate exprTypeBounds(Expr expr, float boundValue, boolean isLowerBound) { + isLowerBound = true and boundValue = exprMinVal(expr.getFullyConverted()) + or + isLowerBound = false and boundValue = exprMaxVal(expr.getFullyConverted()) + } + + /** + * Holds if `(v, phi)` ensures that `access` is not equal to `neConstant`. For + * example, the condition `if (x + 1 != 3)` ensures that `x` is not equal to 2. + * Only integral types are supported. + */ + private predicate isNEPhi( + Variable v, RangeSsaDefinition phi, VariableAccess access, float neConstant + ) { + exists( + ComparisonOperation cmp, boolean branch, Expr linearExpr, Expr rExpr, float p, float q, + float r + | + phi.isGuardPhi(v, access, cmp, branch) and + Util::eqOpWithSwapAndNegate(cmp, linearExpr, rExpr, false, branch) and + v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!=` is too imprecise + r = getValue(rExpr).toFloat() and + Util::linearAccess(linearExpr, access, p, q) and + neConstant = (r - q) / p + ) + or + exists(Expr op, boolean branch, Expr linearExpr, float p, float q | + phi.isGuardPhi(v, access, op, branch) and + Util::eqZeroWithNegate(op, linearExpr, false, branch) and + v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!` is too imprecise + Util::linearAccess(linearExpr, access, p, q) and + neConstant = (0.0 - q) / p + ) + } + + /** + * Holds if `(v, phi)` constrains the value of `access` but in a way that + * doesn't allow this library to constrain the upper or lower bounds of + * `access`. An example is `if (x != y)` if neither `x` nor `y` is a + * compile-time constant. + */ + private predicate isUnsupportedGuardPhi(Variable v, RangeSsaDefinition phi, VariableAccess access) { + exists(Expr cmp, boolean branch | + Util::eqOpWithSwapAndNegate(cmp, _, _, false, branch) + or + Util::eqZeroWithNegate(cmp, _, false, branch) + | + phi.isGuardPhi(v, access, cmp, branch) and + not isNEPhi(v, phi, access, _) + ) + } + + /** + * Gets the upper bound of the expression, if the expression is guarded. + * An upper bound can only be found, if a guard phi node can be found, and the + * expression has only one immediate predecessor. + */ + private float getGuardedUpperBound(VariableAccess guardedAccess) { + exists( + RangeSsaDefinition def, StackVariable v, VariableAccess guardVa, Expr guard, boolean branch + | + def.isGuardPhi(v, guardVa, guard, branch) and + // If the basic block for the variable access being examined has + // more than one predecessor, the guard phi node could originate + // from one of the predecessors. This is because the guard phi + // node is attached to the block at the end of the edge and not on + // the actual edge. It is therefore not possible to determine which + // edge the guard phi node belongs to. The predicate below ensures + // that there is one predecessor, albeit somewhat conservative. + exists(unique(BasicBlock b | b = def.(BasicBlock).getAPredecessor())) and + guardedAccess = def.getAUse(v) and + result = max(float ub | upperBoundFromGuard(guard, guardVa, ub, branch)) and + not convertedExprMightOverflow(guard.getAChild+()) + ) + } + + cached + private module SimpleRangeAnalysisCached { + /** + * Gets the lower bound of the expression. + * + * Note: expressions in C/C++ are often implicitly or explicitly cast to a + * different result type. Such casts can cause the value of the expression + * to overflow or to be truncated. This predicate computes the lower bound + * of the expression without including the effect of the casts. To compute + * the lower bound of the expression after all the casts have been applied, + * call `lowerBound` like this: + * + * `lowerBound(expr.getFullyConverted())` + */ + cached + float lowerBound(Expr expr) { + // Combine the lower bounds returned by getTruncatedLowerBounds into a + // single minimum value. + result = min(float lb | lb = getTruncatedLowerBounds(expr) | lb) + } + + /** + * Gets the upper bound of the expression. + * + * Note: expressions in C/C++ are often implicitly or explicitly cast to a + * different result type. Such casts can cause the value of the expression + * to overflow or to be truncated. This predicate computes the upper bound + * of the expression without including the effect of the casts. To compute + * the upper bound of the expression after all the casts have been applied, + * call `upperBound` like this: + * + * `upperBound(expr.getFullyConverted())` + */ + cached + float upperBound(Expr expr) { + // Combine the upper bounds returned by getTruncatedUpperBounds and + // getGuardedUpperBound into a single maximum value + result = min([max(getTruncatedUpperBounds(expr)), getGuardedUpperBound(expr)]) + } + + /** Holds if the upper bound of `expr` may have been widened. This means the upper bound is in practice likely to be overly wide. */ + cached + predicate upperBoundMayBeWidened(Expr e) { + isRecursiveExpr(e) and + // Widening is not a problem if the post-analysis in `getGuardedUpperBound` has overridden the widening. + // Note that the RHS of `<` may be multi-valued. + not getGuardedUpperBound(e) < getTruncatedUpperBounds(e) + } + + /** + * Holds if `expr` has a provably empty range. For example: + * + * 10 < expr and expr < 5 + * + * The range of an expression can only be empty if it can never be + * executed. For example: + * + * if (10 < x) { + * if (x < 5) { + * // Unreachable code + * return x; // x has an empty range: 10 < x && x < 5 + * } + * } + */ + cached + predicate exprWithEmptyRange(Expr expr) { + analyzableExpr(expr) and + ( + not exists(lowerBound(expr)) or + not exists(upperBound(expr)) or + lowerBound(expr) > upperBound(expr) + ) + } + + /** Holds if the definition might overflow negatively. */ + cached + predicate defMightOverflowNegatively(RangeSsaDefinition def, StackVariable v) { + getDefLowerBoundsImpl(def, v) < Util::varMinVal(v) + } + + /** Holds if the definition might overflow positively. */ + cached + predicate defMightOverflowPositively(RangeSsaDefinition def, StackVariable v) { + getDefUpperBoundsImpl(def, v) > Util::varMaxVal(v) + } + + /** + * Holds if the definition might overflow (either positively or + * negatively). + */ + cached + predicate defMightOverflow(RangeSsaDefinition def, StackVariable v) { + defMightOverflowNegatively(def, v) or + defMightOverflowPositively(def, v) + } + + /** + * Holds if `e` is an expression where the concept of overflow makes sense. + * This predicate is used to filter out some of the unanalyzable expressions + * from `exprMightOverflowPositively` and `exprMightOverflowNegatively`. + */ + pragma[inline] + private predicate exprThatCanOverflow(Expr e) { + e instanceof UnaryArithmeticOperation or + e instanceof BinaryArithmeticOperation or + e instanceof AssignArithmeticOperation or + e instanceof LShiftExpr or + e instanceof AssignLShiftExpr + } + + /** + * Holds if the expression might overflow negatively. This predicate + * does not consider the possibility that the expression might overflow + * due to a conversion. + */ + cached + predicate exprMightOverflowNegatively(Expr expr) { + getLowerBoundsImpl(expr) < Util::exprMinVal(expr) + or + // The lower bound of the expression `x--` is the same as the lower + // bound of `x`, so the standard logic (above) does not work for + // detecting whether it might overflow. + getLowerBoundsImpl(expr.(PostfixDecrExpr)) = Util::exprMinVal(expr) + or + // We can't conclude that any unanalyzable expression might overflow. This + // is because there are many expressions that the range analysis doesn't + // handle, but where the concept of overflow doesn't make sense. + exprThatCanOverflow(expr) and not analyzableExpr(expr) + } + + /** + * Holds if the expression might overflow negatively. Conversions + * are also taken into account. For example the expression + * `(int16)(x+y)` might overflow due to the `(int16)` cast, rather than + * due to the addition. + */ + cached + predicate convertedExprMightOverflowNegatively(Expr expr) { + exprMightOverflowNegatively(expr) or + convertedExprMightOverflowNegatively(expr.getConversion()) + } + + /** + * Holds if the expression might overflow positively. This predicate + * does not consider the possibility that the expression might overflow + * due to a conversion. + */ + cached + predicate exprMightOverflowPositively(Expr expr) { + getUpperBoundsImpl(expr) > Util::exprMaxVal(expr) + or + // The upper bound of the expression `x++` is the same as the upper + // bound of `x`, so the standard logic (above) does not work for + // detecting whether it might overflow. + getUpperBoundsImpl(expr.(PostfixIncrExpr)) = Util::exprMaxVal(expr) + } + + /** + * Holds if the expression might overflow positively. Conversions + * are also taken into account. For example the expression + * `(int16)(x+y)` might overflow due to the `(int16)` cast, rather than + * due to the addition. + */ + cached + predicate convertedExprMightOverflowPositively(Expr expr) { + exprMightOverflowPositively(expr) or + convertedExprMightOverflowPositively(expr.getConversion()) + } + + /** + * Holds if the expression might overflow (either positively or + * negatively). The possibility that the expression might overflow + * due to an implicit or explicit cast is also considered. + */ + cached + predicate convertedExprMightOverflow(Expr expr) { + convertedExprMightOverflowNegatively(expr) or + convertedExprMightOverflowPositively(expr) + } + } + + /** + * Gets the truncated lower bounds of the fully converted expression. + */ + float getFullyConvertedLowerBounds(Expr expr) { + result = getTruncatedLowerBounds(expr.getFullyConverted()) + } + + /** + * Gets the truncated upper bounds of the fully converted expression. + */ + float getFullyConvertedUpperBounds(Expr expr) { + result = getTruncatedUpperBounds(expr.getFullyConverted()) + } + + /** + * Get the lower bounds for a `RangeSsaDefinition`. Most of the work is + * done by `getDefLowerBoundsImpl`, but this is where widening is applied + * to prevent the analysis from exploding due to a recursive definition. + */ + float getDefLowerBounds(RangeSsaDefinition def, StackVariable v) { + exists(float newLB, float truncatedLB | + newLB = getDefLowerBoundsImpl(def, v) and + if Util::varMinVal(v) <= newLB and newLB <= Util::varMaxVal(v) + then truncatedLB = newLB + else truncatedLB = Util::varMinVal(v) + | + // Widening: check whether the new lower bound is from a source which + // depends recursively on the current definition. + if isRecursiveDef(def, v) + then + // The new lower bound is from a recursive source, so we round + // down to one of a limited set of values to prevent the + // recursion from exploding. + result = + max(float widenLB | + widenLB = wideningLowerBounds(Util::getVariableRangeType(v)) and + not widenLB > truncatedLB + | + widenLB + ) + else result = truncatedLB + ) + or + // The definition might overflow positively and wrap. If so, the lower + // bound is `typeLowerBound`. + defMightOverflowPositively(def, v) and result = Util::varMinVal(v) + } + + /** See comment for `getDefLowerBounds`, above. */ + float getDefUpperBounds(RangeSsaDefinition def, StackVariable v) { + exists(float newUB, float truncatedUB | + newUB = getDefUpperBoundsImpl(def, v) and + if Util::varMinVal(v) <= newUB and newUB <= Util::varMaxVal(v) + then truncatedUB = newUB + else truncatedUB = Util::varMaxVal(v) + | + // Widening: check whether the new upper bound is from a source which + // depends recursively on the current definition. + if isRecursiveDef(def, v) + then + // The new upper bound is from a recursive source, so we round + // up to one of a fixed set of values to prevent the recursion + // from exploding. + result = + min(float widenUB | + widenUB = wideningUpperBounds(Util::getVariableRangeType(v)) and + not widenUB < truncatedUB + | + widenUB + ) + else result = truncatedUB + ) + or + // The definition might overflow negatively and wrap. If so, the upper + // bound is `typeUpperBound`. + defMightOverflowNegatively(def, v) and result = Util::varMaxVal(v) + } +} diff --git a/cpp/common/src/codingstandards/cpp/Scope.qll b/cpp/common/src/codingstandards/cpp/Scope.qll index d9a81b98e3..5438c17133 100644 --- a/cpp/common/src/codingstandards/cpp/Scope.qll +++ b/cpp/common/src/codingstandards/cpp/Scope.qll @@ -3,56 +3,86 @@ */ import cpp +import codingstandards.cpp.ConstHelpers /** - * Gets the parent scope of this `Element`, if any. - * A scope is a `Type` (`Class` / `Enum`), a `Namespace`, a `Block`, a `Function`, - * or certain kinds of `Statement`. - * Differs from `Element::getParentScope` when `e` is a `LoopControlVariable` + * a `Variable` that is nonvolatile and const + * and of type `IntegralOrEnumType` */ -private Element getParentScope(Element e) { - /* - * A `Block` cannot have a `ForStmt` as its parent scope so we have to special case - * for loop bodies to ensure that identifiers inside the loop bodies have the for stmt as a parent scope. - * If this is not the case then `i2` in the following example cannot be in `i1`'s potential scope, because - * the parent scope of `i1` is the `ForStmt` while the transitive closure of the parent scope for `i2` doesn't include - * outer scope. Blocks can only have blocks as parent scopes. - * void f() { - * for( int i1; ... ) { - * for (int i2; ...) { - * } - * } - * } - */ +class NonVolatileConstIntegralOrEnumVariable extends Variable { + NonVolatileConstIntegralOrEnumVariable() { + not this.isVolatile() and + this.isConst() and + this.getUnspecifiedType() instanceof IntegralOrEnumType + } +} - exists(Loop loop | loop.getStmt() = e and result = loop) - or - exists(IfStmt ifStmt | - (ifStmt.getThen() = e or ifStmt.getElse() = e) and - result = ifStmt - ) - or - exists(SwitchStmt switchStmt | switchStmt.getStmt() = e and result = switchStmt) - or - not result.(Loop).getStmt() = e and - not result.(IfStmt).getThen() = e and - not result.(IfStmt).getElse() = e and - not result.(SwitchStmt).getStmt() = e and - if exists(e.getParentScope()) - then result = e.getParentScope() - else ( - // Statements do no have a parent scope, so return the enclosing block. - result = e.(Stmt).getEnclosingBlock() +/** + * Internal module, exposed for testing. + */ +module Internal { + /** + * Gets the parent scope of this `Element`, if any. + * A scope is a `Type` (`Class` / `Enum`), a `Namespace`, a `Block`, a `Function`, + * or certain kinds of `Statement`. + * Differs from `Element::getParentScope` when `e` is a `LoopControlVariable` + */ + Element getParentScope(Element e) { + /* + * A `Block` cannot have a `ForStmt` as its parent scope so we have to special case + * for loop bodies to ensure that identifiers inside the loop bodies have the for stmt as a parent scope. + * If this is not the case then `i2` in the following example cannot be in `i1`'s potential scope, because + * the parent scope of `i1` is the `ForStmt` while the transitive closure of the parent scope for `i2` doesn't include + * outer scope. Blocks can only have blocks as parent scopes. + * void f() { + * for( int i1; ... ) { + * for (int i2; ...) { + * } + * } + * } + */ + + exists(Loop loop | loop.getAChild() = e and result = loop) + or + exists(IfStmt ifStmt | + (ifStmt.getThen() = e or ifStmt.getElse() = e) and + result = ifStmt + ) + or + exists(SwitchStmt switchStmt | switchStmt.getStmt() = e and result = switchStmt) + or + // A catch-block parameter, whose parent is the `Handler` + exists(CatchBlock c | c.getParameter() = e and result = c.getParent()) or - result = e.(Expr).getEnclosingBlock() + // A catch-block `Handler`, whose parent is the `TryStmt` + e.(Handler).getParent() = result or - // Catch block parameters don't have an enclosing scope, so attach them to the - // the block itself - exists(CatchBlock cb | - e = cb.getParameter() and - result = cb + // The parent scope of a lambda is the scope in which the lambda expression is defined. + // + // Lambda functions are defined in a generated `Closure` class, as the `operator()` function. We choose the + // enclosing statement of the lambda expression as the parent scope of the lambda function. This is so we can + // determine the order of definition if a variable is defined in the same scope as the lambda expression. + exists(Closure lambdaClosure | + lambdaClosure.getLambdaFunction() = e and + lambdaClosure.getLambdaExpression().getEnclosingStmt() = result ) - ) + or + not exists(Loop loop | loop.getAChild() = e) and + not exists(IfStmt ifStmt | ifStmt.getThen() = e or ifStmt.getElse() = e) and + not exists(SwitchStmt switchStmt | switchStmt.getStmt() = e) and + not exists(CatchBlock c | c.getParameter() = e) and + not e instanceof Handler and + not exists(Closure lambdaClosure | lambdaClosure.getLambdaFunction() = e) and + if exists(e.getParentScope()) + then result = e.getParentScope() + else ( + // Statements do not have a parent scope, so return the enclosing block. + result = e.(Stmt).getEnclosingBlock() + or + // Expressions do not have a parent scope, so return the enclosing block. + result = e.(Expr).getEnclosingBlock() + ) + } } /** A variable which is defined by the user, rather than being from a third party or compiler generated. */ @@ -68,19 +98,29 @@ class UserVariable extends Variable { /** An element which is the parent scope of at least one other element in the program. */ class Scope extends Element { - Scope() { this = getParentScope(_) } + Scope() { this = Internal::getParentScope(_) } - UserVariable getAVariable() { getParentScope(result) = this } + UserVariable getAVariable() { Internal::getParentScope(result) = this } + + /** + * Gets the `Variable` with the given `name` that is declared in this scope. + */ + UserVariable getVariable(string name) { + result = getAVariable() and + result.getName() = name + } int getNumberOfVariables() { result = count(getAVariable()) } Scope getAnAncestor() { result = this.getStrictParent+() } - Scope getStrictParent() { result = getParentScope(this) } + Scope getAChildScope() { result.getStrictParent() = this } + + Scope getStrictParent() { result = Internal::getParentScope(this) } - Declaration getADeclaration() { getParentScope(result) = this } + Declaration getADeclaration() { Internal::getParentScope(result) = this } - Expr getAnExpr() { this = getParentScope(result) } + Expr getAnExpr() { this = Internal::getParentScope(result) } private predicate getLocationInfo( PreprocessorBranchDirective pbd, string file1, string file2, int startline1, int startline2 @@ -112,43 +152,136 @@ class Scope extends Element { predicate isGenerated() { this instanceof GeneratedBlockStmt } int getDepth() { - exists(Scope parent | parent = getParentScope(this) and result = 1 + parent.getDepth()) + exists(Scope parent | + parent = Internal::getParentScope(this) and result = 1 + parent.getDepth() + ) or - not exists(getParentScope(this)) and result = 0 + not exists(Internal::getParentScope(this)) and result = 0 } -} -class GeneratedBlockStmt extends BlockStmt { - GeneratedBlockStmt() { this.getLocation() instanceof UnknownLocation } -} + /** + * Holds if `name` is declared in this scope, or in a nested scope. + */ + private predicate isNameDeclaredInThisOrNestedScope(string name) { + name = getAVariable().getName() + or + isNameDeclaredInNestedScope(name) + } + + /** + * Holds if `name` is declared in a nested scope. + */ + private predicate isNameDeclaredInNestedScope(string name) { + this.getAChildScope().isNameDeclaredInThisOrNestedScope(name) + } + + /** + * Holds if `name` is declared in this scope and is hidden in a child scope. + */ + private predicate isDeclaredNameHiddenByChild(string name) { + isNameDeclaredInNestedScope(name) and + name = getAVariable().getName() + } + + /** + * Gets a variable with `name` which is potentially hidden in at least one nested scope. + */ + private UserVariable getAPotentiallyHiddenVariable(string name) { + result = getAVariable() and + result.getName() = name and + isDeclaredNameHiddenByChild(name) + } -/** Gets a variable that is in the potential scope of variable `v`. */ -private UserVariable getPotentialScopeOfVariable_candidate(UserVariable v) { - exists(Scope s | - result = s.getAVariable() and + /** + * Holds if `name` is declared above this scope and hidden by this or a nested scope. + */ + UserVariable getAVariableHiddenByThisOrNestedScope(string name) { + exists(Scope parent | parent = this.getStrictParent() | + result = parent.getAPotentiallyHiddenVariable(name) or + result = parent.getAVariableHiddenByThisOrNestedScope(name) + ) and + isNameDeclaredInThisOrNestedScope(name) + } + + /** + * Holds if `hiddenVariable` and `hidingVariable` are a candidate hiding pair at this scope. + */ + private predicate hidesCandidate( + UserVariable hiddenVariable, UserVariable hidingVariable, string name + ) { ( - // Variable in an ancestor scope, but only if there are less than 100 variables in this scope - v = s.getAnAncestor().getAVariable() and - s.getNumberOfVariables() < 100 + // Declared in this scope + hidingVariable = getVariable(name) and + hiddenVariable = getAVariableHiddenByThisOrNestedScope(name) or - // In the same scope, but not the same variable, and choose just one to report - v = s.getAVariable() and - not result = v and - v.getName() <= result.getName() + // Declared in a child scope + exists(Scope child | + getAChildScope() = child and + child.hidesCandidate(hiddenVariable, hidingVariable, name) + ) ) - ) + } + + /** + * Holds if `hiddenVariable` is declared in this scope and hidden by `hidingVariable`. + */ + predicate hides(UserVariable hiddenVariable, UserVariable hidingVariable, Scope childScope) { + exists(string name | + hiddenVariable = getAPotentiallyHiddenVariable(name) and + childScope = getAChildScope() and + childScope.hidesCandidate(hiddenVariable, hidingVariable, name) + ) + } } -/** Gets a variable that is in the potential scope of variable `v`. */ -private UserVariable getOuterScopesOfVariable_candidate(UserVariable v) { - exists(Scope s | - result = s.getAVariable() and - ( - // Variable in an ancestor scope, but only if there are less than 100 variables in this scope - v = s.getAnAncestor().getAVariable() and - s.getNumberOfVariables() < 100 +/** + * A scope representing the generated `operator()` of a lambda function. + */ +class LambdaScope extends Scope { + Closure closure; + + LambdaScope() { this = closure.getLambdaFunction() } + + override UserVariable getAVariableHiddenByThisOrNestedScope(string name) { + // Handle special cases for lambdas + exists(UserVariable hiddenVariable, LambdaExpression lambdaExpr | + // Find the variable that is potentially hidden inside the lambda + hiddenVariable = super.getAVariableHiddenByThisOrNestedScope(name) and + result = hiddenVariable and + lambdaExpr = closure.getLambdaExpression() + | + // A definition can be hidden if it is in scope and it is captured by the lambda, + exists(LambdaCapture cap | + lambdaExpr.getACapture() = cap and + // The outer declaration is captured by the lambda + hiddenVariable.getAnAccess() = cap.getInitializer() + ) + or + // it is is non-local, + hiddenVariable instanceof GlobalVariable + or + // it has static or thread local storage duration, + (hiddenVariable.isThreadLocal() or hiddenVariable.isStatic()) + or + //it is a reference that has been initialized with a constant expression. + hiddenVariable.getType().stripTopLevelSpecifiers() instanceof ReferenceType and + hiddenVariable.getInitializer().getExpr() instanceof Literal + or + // //it const non-volatile integral or enumeration type and has been initialized with a constant expression + hiddenVariable instanceof NonVolatileConstIntegralOrEnumVariable and + hiddenVariable.getInitializer().getExpr() instanceof Literal + or + //it is constexpr and has no mutable members + hiddenVariable.isConstexpr() and + not exists(Class c | + c = hiddenVariable.getType() and not c.getAMember() instanceof MutableVariable + ) ) - ) + } +} + +class GeneratedBlockStmt extends BlockStmt { + GeneratedBlockStmt() { this.getLocation() instanceof UnknownLocation } } /** Holds if there exists a translation unit that includes both `f1` and `f2`. */ @@ -161,21 +294,17 @@ predicate inSameTranslationUnit(File f1, File f2) { } /** - * Gets a user variable which occurs in the "potential scope" of variable `v`. - */ -cached -UserVariable getPotentialScopeOfVariable(UserVariable v) { - result = getPotentialScopeOfVariable_candidate(v) and - inSameTranslationUnit(v.getFile(), result.getFile()) -} - -/** - * Gets a user variable which occurs in the "outer scope" of variable `v`. + * Holds if there exists a translation unit that includes both `f1` and `f2`. + * + * This version is late bound. */ -cached -UserVariable getPotentialScopeOfVariableStrict(UserVariable v) { - result = getOuterScopesOfVariable_candidate(v) and - inSameTranslationUnit(v.getFile(), result.getFile()) +bindingset[f1, f2] +pragma[inline_late] +predicate inSameTranslationUnitLate(File f1, File f2) { + exists(TranslationUnit c | + c.getAUserFile() = f1 and + c.getAUserFile() = f2 + ) } /** A file that is a C/C++ source file */ @@ -203,67 +332,27 @@ class TranslationUnit extends SourceFile { } } -/** Holds if `v2` may hide `v1`. */ -private predicate hides_candidate(UserVariable v1, UserVariable v2) { - not v1 = v2 and - v2 = getPotentialScopeOfVariable(v1) and - v1.getName() = v2.getName() and - // Member variables cannot hide other variables nor be hidden because the can be referenced through their qualified name. - not (v1.isMember() or v2.isMember()) -} - -/** Holds if `v2` may hide `v1`. */ -private predicate hides_candidateStrict(UserVariable v1, UserVariable v2) { - not v1 = v2 and - v2 = getPotentialScopeOfVariableStrict(v1) and - v1.getName() = v2.getName() and - // Member variables cannot hide other variables nor be hidden because the can be referenced through their qualified name. - not (v1.isMember() or v2.isMember()) and - ( - // If v1 is a local variable, ensure that v1 is declared before v2 +/** Holds if `v2` strictly (`v2` is in an inner scope compared to `v1`) hides `v1`. */ +predicate hides_candidateStrict(UserVariable v1, UserVariable v2) { + exists(Scope parentScope, Scope childScope | parentScope.hides(v1, v2, childScope) | + // If v1 is a local variable defined in a `DeclStmt` ensure that it is declared before `v2`, + // otherwise it would not be hidden ( - v1 instanceof LocalVariable and - // Ignore variables declared in conditional expressions, as they apply to - // the nested scope - not v1 = any(ConditionDeclExpr cde).getVariable() and - // Ignore variables declared in loops - not exists(Loop l | l.getADeclaration() = v1) + parentScope instanceof BlockStmt and + exists(DeclStmt ds | ds.getADeclaration() = v1) and + exists(parentScope.(BlockStmt).getIndexOfStmt(childScope)) ) implies exists(BlockStmt bs, DeclStmt v1Stmt, Stmt v2Stmt | - v1 = v1Stmt.getADeclaration() and - getEnclosingStmt(v2).getParentStmt*() = v2Stmt + bs = parentScope and + v2Stmt = childScope and + v1Stmt.getADeclaration() = v1 | bs.getIndexOfStmt(v1Stmt) <= bs.getIndexOfStmt(v2Stmt) ) - ) -} - -/** - * Gets the enclosing statement of the given variable, if any. - */ -private Stmt getEnclosingStmt(LocalScopeVariable v) { - result.(DeclStmt).getADeclaration() = v - or - exists(ConditionDeclExpr cde | - cde.getVariable() = v and - result = cde.getEnclosingStmt() - ) - or - exists(CatchBlock cb | - cb.getParameter() = v and - result = cb.getEnclosingStmt() - ) -} - -/** Holds if `v2` hides `v1`. */ -predicate hides(UserVariable v1, UserVariable v2) { - hides_candidate(v1, v2) and - // Confirm that there's no closer candidate variable which `v2` hides - not exists(UserVariable mid | - hides_candidate(v1, mid) and - hides_candidate(mid, v2) - ) + ) and + inSameTranslationUnitLate(v1.getFile(), v2.getFile()) and + not (v1.isMember() or v2.isMember()) } /** Holds if `v2` strictly (`v2` is in an inner scope compared to `v1`) hides `v1`. */ @@ -291,6 +380,8 @@ predicate hasBlockScope(Declaration decl) { exists(BlockStmt b | b.getADeclarati /** * identifiers in nested (named/nonglobal) namespaces are exceptions to hiding due to being able access via fully qualified ids */ +bindingset[outerDecl, innerDecl] +pragma[inline_late] predicate excludedViaNestedNamespaces(UserVariable outerDecl, UserVariable innerDecl) { exists(Namespace inner, Namespace outer | outer.getAChildNamespace+() = inner and diff --git a/cpp/common/src/codingstandards/cpp/SideEffect.qll b/cpp/common/src/codingstandards/cpp/SideEffect.qll index 08cd9394d3..883004e513 100644 --- a/cpp/common/src/codingstandards/cpp/SideEffect.qll +++ b/cpp/common/src/codingstandards/cpp/SideEffect.qll @@ -1,7 +1,7 @@ /** A module to reason about side effects. */ import cpp -import codingstandards.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow private import exceptions.ExceptionFlow private import codingstandards.cpp.Expr private import codingstandards.cpp.Variable @@ -190,6 +190,8 @@ Expr getAnEffect(Expr base) { or exists(PointerDereferenceExpr e | e.getOperand() = base | result = getAnEffect(e)) or + exists(CrementOperation c | c.getOperand() = base | result = getAnEffect(c)) + or // local alias analysis, assume alias when data flows to derived type (pointer/reference) // auto ptr = &base; exists(VariableAccess va, AddressOfExpr addressOf | diff --git a/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll b/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll index 469fe9a738..5144f63dc2 100644 --- a/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll +++ b/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll @@ -151,6 +151,40 @@ private class CastEnumToIntegerSimpleRange extends SimpleRangeAnalysisExpr, Cast override predicate dependsOnChild(Expr child) { child = getExpr() } } +/** + * A range analysis extension that supports `%=`. + */ +private class RemAssignSimpleRange extends SimpleRangeAnalysisExpr, AssignRemExpr { + override float getLowerBounds() { + exists(float maxDivisorNegated, float dividendLowerBounds | + // Find the max divisor, negated e.g. `%= 32` would be `-31` + maxDivisorNegated = (getFullyConvertedUpperBounds(getRValue()).abs() - 1) * -1 and + // Find the lower bounds of the dividend + dividendLowerBounds = getFullyConvertedLowerBounds(getLValue()) and + // The lower bound is calculated in two steps: + // 1. Determine the maximum of the dividend lower bound and maxDivisorNegated. + // When the dividend is negative this will result in a negative result + // 2. Find the minimum with 0. If the divided is always >0 this will produce 0 + // otherwise it will produce the lowest negative number that can be held + // after the modulo. + result = 0.minimum(dividendLowerBounds.maximum(maxDivisorNegated)) + ) + } + + override float getUpperBounds() { + exists(float maxDivisor, float maxDividend | + // The maximum divisor value is the absolute value of the divisor minus 1 + maxDivisor = getFullyConvertedUpperBounds(getRValue()).abs() - 1 and + // value if > 0 otherwise 0 + maxDividend = getFullyConvertedUpperBounds(getLValue()).maximum(0) and + // In the case the numerator is definitely less than zero, the result could be negative + result = maxDividend.minimum(maxDivisor) + ) + } + + override predicate dependsOnChild(Expr expr) { expr = getAChild() } +} + /** * functions that read a character from the STDIN, * or return EOF if it fails to do so. diff --git a/cpp/common/src/codingstandards/cpp/SmartPointers.qll b/cpp/common/src/codingstandards/cpp/SmartPointers.qll index dda645a399..a643b0bc2b 100644 --- a/cpp/common/src/codingstandards/cpp/SmartPointers.qll +++ b/cpp/common/src/codingstandards/cpp/SmartPointers.qll @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow // Local cached version of localExprFlow to avoid bad magic cached diff --git a/cpp/common/src/codingstandards/cpp/StdFunctionOrMacro.qll b/cpp/common/src/codingstandards/cpp/StdFunctionOrMacro.qll new file mode 100644 index 0000000000..ec4873d20e --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/StdFunctionOrMacro.qll @@ -0,0 +1,200 @@ +/** + * This module intends to reduce the difficulty of handling the pattern where implementations + * implement a function as a macro: the class `StdFunctionOrMacro<...>::Call` matches both std + * function calls as well as std function macro expansions. + * + * For instance, `atomic_init` may be implemented as a function, but is also implemented as a + * complicated macro on some platforms. This module aids in finding calls to any standard function + * which may be a macro. + * + * Since a macro can be defined to expand to any expression, we cannot know generally which + * expanded expressions in `f(x, y)` correspond to arguments `x` or `y`. To handle this, implement + * the module `InferMacroExpansionArguments`. + * + * To match a function of a particular name create a predicate for the name you wish to match. For + * instance: + * + * ```codeql + * private string atomicInit() { result = "atomic_init" } + * + * from StdFunctionOrMacro::Call c + * select c.getArgument(0) + * ``` + */ + +import cpp as cpp + +private string atomicInit() { result = "atomic_init" } + +class AtomicInitCall = StdFunctionOrMacro::Call; + +/** Specify the name of your function as a predicate */ +private signature string getName(); + +/** Signature module to implement custom argument resolution behavior in expanded macros */ +private signature module InferMacroExpansionArguments { + bindingset[mi, argumentIdx] + cpp::Expr inferArgument(cpp::MacroInvocation mi, int argumentIdx); +} + +private module InferAtomicMacroArgs implements InferMacroExpansionArguments { + bindingset[pattern] + private cpp::Expr getMacroVarInitializer(cpp::MacroInvocation mi, string pattern) { + exists(cpp::VariableDeclarationEntry decl | + mi.getAGeneratedElement() = decl and + decl.getName().matches(pattern) and + result = decl.getDeclaration().getInitializer().getExpr() + ) + } + + bindingset[mi, argumentIdx] + cpp::Expr inferArgument(cpp::MacroInvocation mi, int argumentIdx) { + result = mi.getExpr().(cpp::FunctionCall).getArgument(argumentIdx) + or + if + argumentIdx = 0 and + exists(getMacroVarInitializer(mi, "__atomic_%_ptr")) + then result = getMacroVarInitializer(mi, "__atomic_%_ptr") + else + if + argumentIdx = [1, 2] and + exists(getMacroVarInitializer(mi, "__atomic_%_tmp")) + then result = getMacroVarInitializer(mi, "__atomic_%_tmp") + else + exists(cpp::FunctionCall fc | + fc = mi.getAnExpandedElement() and + fc.getTarget().getName().matches("%atomic_%") and + result = fc.getArgument(argumentIdx) + ) + } +} + +private string atomicReadOrWriteName() { + result = + [ + "atomic_load", + "atomic_store", + "atomic_fetch_" + ["add", "sub", "or", "xor", "and"], + "atomic_exchange", + "atomic_compare_exchange_" + ["strong", "weak"] + ] + ["", "_explicit"] +} + +class AtomicReadOrWriteCall = + StdFunctionOrMacro::Call; + +private string atomicallySequencedName() { + result = + [ + "atomic_thread_fence", + "atomic_signal_fence", + "atomic_flag_clear_explicit", + "atomic_flag_test_and_set_explicit", + ] + or + result = atomicReadOrWriteName() and + result.matches("%_explicit") +} + +/** A `stdatomic.h` function which accepts a `memory_order` value as a parameter. */ +class AtomicallySequencedCall extends StdFunctionOrMacro::Call +{ + cpp::Expr getAMemoryOrderArgument() { + if getName() = "atomic_compare_exchange_" + ["strong", "weak"] + "_explicit" + then result = getArgument(getNumberOfArguments() - [1, 2]) + else result = getArgument(getNumberOfArguments() - 1) + } +} + +/** + * A module to find calls to standard functions, or expansions of macros with the same name. + * + * To use this module, specify a name predicate and an inference strategy for correlating macro + * expansions to macro arguments. + * + * For example: + * + * ```codeql + * private string atomicInit() { result = "atomic_init" } + * from StdFunctionOrMacro::Call c + * select c.getArgument(0) + * ``` + */ +private module StdFunctionOrMacro +{ + final private class Expr = cpp::Expr; + + final private class FunctionCall = cpp::FunctionCall; + + final private class MacroInvocation = cpp::MacroInvocation; + + private newtype TStdCall = + TStdFunctionCall(FunctionCall fc) { fc.getTarget().hasName(getStdName()) } or + TStdMacroInvocation(MacroInvocation mi) { mi.getMacro().hasName(getStdName()) } + + /** + * A call to a standard function or an expansion of a macro with the same name. + */ + class Call extends TStdCall { + bindingset[this, argumentIdx] + Expr getArgument(int argumentIdx) { + exists(FunctionCall fc | + this = TStdFunctionCall(fc) and + result = fc.getArgument(argumentIdx) + ) + or + exists(MacroInvocation mi | + this = TStdMacroInvocation(mi) and + result = InferExpansion::inferArgument(mi, argumentIdx) + ) + } + + Expr getAnArgument() { + exists(int i | + i = [0 .. getNumberOfArguments()] and + result = getArgument(i) + ) + } + + string getName() { + exists(FunctionCall fc | + this = TStdFunctionCall(fc) and + result = fc.getTarget().getName() + ) + or + exists(MacroInvocation mi | + this = TStdMacroInvocation(mi) and + result = mi.getMacroName() + ) + } + + string toString() { + this = TStdFunctionCall(_) and + result = "Standard function call" + or + this = TStdMacroInvocation(_) and + result = "Invocation of a standard function implemented as a macro" + } + + int getNumberOfArguments() { + exists(FunctionCall fc | + this = TStdFunctionCall(fc) and + result = fc.getTarget().getNumberOfParameters() + ) + or + exists(MacroInvocation mi | + this = TStdMacroInvocation(mi) and + result = count(int i | i = [0 .. 10] and exists(InferExpansion::inferArgument(mi, i))) + ) + } + + Expr getExpr() { + this = TStdFunctionCall(result) + or + exists(MacroInvocation mi | + this = TStdMacroInvocation(mi) and + result = mi.getExpr() + ) + } + } +} diff --git a/cpp/common/src/codingstandards/cpp/Type.qll b/cpp/common/src/codingstandards/cpp/Type.qll index 4199b4a12d..052096559a 100644 --- a/cpp/common/src/codingstandards/cpp/Type.qll +++ b/cpp/common/src/codingstandards/cpp/Type.qll @@ -1,72 +1,2 @@ -/** - * A module for representing different `Type`s. - */ - -import cpp - -/** - * A fundamental type, as defined by `[basic.fundamental]`. - */ -class FundamentalType extends BuiltInType { - FundamentalType() { - // A fundamental type is any `BuiltInType` except types indicating errors during extraction, or - // "unknown" types inserted into uninstantiated templates - not this instanceof ErroneousType and - not this instanceof UnknownType - } -} - -/** - * A type that is incomplete. - */ -class IncompleteType extends Class { - IncompleteType() { not hasDefinition() } -} - -/** - * A type that implements the BitmaskType trait. - * https://en.cppreference.com/w/cpp/named_req/BitmaskType - */ -abstract class BitmaskType extends Type { } - -/** - * Holds if `enum` implements required overload `overload` to implement - * the BitmaskType trait. - */ -private predicate isRequiredEnumOverload(Enum enum, Function overload) { - overload.getName().regexpMatch("operator([&|^~]|&=|\\|=)") and - forex(Parameter p | p = overload.getAParameter() | - ( - p.getType() = enum - or - p.getType().(ReferenceType).getBaseType() = enum - ) - ) -} - -private class EnumBitmaskType extends BitmaskType, Enum { - EnumBitmaskType() { - // Implements all the required overload - count(Function overload | isRequiredEnumOverload(this, overload)) = 6 - } -} - -/** - * A type without `const` and `volatile` specifiers. - */ -Type stripSpecifiers(Type type) { - if type instanceof SpecifiedType - then result = stripSpecifiers(type.(SpecifiedType).getBaseType()) - else result = type -} - -/** - * Get the precision of an integral type, where precision is defined as the number of bits - * that can be used to represent the numeric value. - * https://wiki.sei.cmu.edu/confluence/display/c/INT35-C.+Use+correct+integer+precisions - */ -int getPrecision(IntegralType type) { - type.isExplicitlyUnsigned() and result = type.getSize() * 8 - or - type.isExplicitlySigned() and result = type.getSize() * 8 - 1 -} +import codingstandards.cpp.types.Type +import codingstandards.cpp.types.Uses diff --git a/cpp/common/src/codingstandards/cpp/Variable.qll b/cpp/common/src/codingstandards/cpp/Variable.qll index dba7af480a..47c6ca7f6c 100644 --- a/cpp/common/src/codingstandards/cpp/Variable.qll +++ b/cpp/common/src/codingstandards/cpp/Variable.qll @@ -5,3 +5,17 @@ import semmle.code.cpp.PODType03 class ScalarVariable extends Variable { ScalarVariable() { isScalarType03(this.getType()) } } + +/** + * Returns the target variable of a `VariableAccess`. + * If the access is a field access, then the target is the `Variable` of the qualifier. + * If the access is an array access, then the target is the array base. + */ +Variable getAddressOfExprTargetBase(AddressOfExpr expr) { + result = expr.getOperand().(ValueFieldAccess).getQualifier().(VariableAccess).getTarget() + or + not expr.getOperand() instanceof ValueFieldAccess and + result = expr.getOperand().(VariableAccess).getTarget() + or + result = expr.getOperand().(ArrayExpr).getArrayBase().(VariableAccess).getTarget() +} diff --git a/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll b/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll new file mode 100644 index 0000000000..b41de3ef9a --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll @@ -0,0 +1,426 @@ +import codingstandards.cpp.AlertReporting + +/** + * A configuration for deduplicating query results inside of macros. + * + * See doc comment on `DeduplicateMacroResults` module. + */ +signature module DeduplicateMacroConfigSig { + /** + * Stringify the `ResultElement`. All `ResultElement`s that share an "identity" should stringify + * to the same string to get proper results. + */ + string describe(ResultElement re); +} + +/** + * A configuration for generating reports from reports that may or may not be duplicated across + * macro expansions. + * + * See doc comment on `DeduplicateMacroResults` module. + * + * This signature is used to parameterize the module `DeduplicateMacroResults::Report`. + */ +signature module MacroReportConfigSig { + /* Create a message to describe this macro, with a string describing its `ResultElement`. */ + bindingset[description] + string getMessageSameResultInAllExpansions(Macro m, string description); + + /* Create a message to describe this macro, using '$@' to describe an example `ResultElement`. */ + string getMessageVariedResultInAllExpansions(Macro m); + + /** + * Create a message to describe this macro expansion which produces a `ResultElement`, using '$@' + * to describe the relevant macro. + */ + string getMessageResultInIsolatedExpansion(ResultElement element); + + /** + * Create a message to describe a `ResultElement` which is not generated by a macro expansion. + */ + string getMessageNotInMacro(ResultElement element, Locatable optExtraLoc1, string optExtraStr1); +} + +/** + * A module for taking the results of `MacroUnwrapper` and consolidating them. + * + * The module `MacroUnwrapper` is great for simple alerts such as usage of banned functions. In + * such cases, reporting "call to 'foo()' in macro 'M'" will only have one result even if the macro + * is expanded multiple times. + * + * However, other queries may have a dynamic message which can vary per macro call site due to + * token manipulation (`a ## b`), for instance, "Macro 'M' defines unused object 'generated_name_x'" + * which will lead to hundreds of results if there are hundreds of such generated names. + * + * This module can be used to find and easily report non-compliant behavior, grouped by the macro + * it originates in, regardless of whether the messages will exactly match. + * + * ## General Usage + * + * To use this macro, define a class for the relevant behavior, and a means of stringifying + * relevant elements as a config, to parameterize the `DeduplicateMacroResults` module. + * + * ``` + * class InvalidFoo extends Foo { + * InvalidFoo() { ... } + * } + * + * module DeduplicateFooInMacrosConfig implements DeduplicateMacroConfigSig { + * string describe(InvalidFoo foo) { result = ... } + * } + * + * import DeduplicateMacroResults as DeduplicateFooInMacros; + * ``` + * + * This module exposes the following classes: + * - `PrimaryMacroSameResultElementInAllInvocations extends Macro`: Every invocation of this macro + * generates an `InvalidFoo` which stringifies to the same thing. Use the method + * `getResultElementDescription()` to get that shared string. + * - `PrimaryMacroDifferentResultElementInAllInvocations extends Macro`: Every invocation of this + * macro generates an `InvalidFoo`, but they do not all stringify to the same thing. Use the + * method `getExampleResultElement()` to get an *single* example `InvalidFoo` to help users fix + * and understand the issue. + * - `IsolatedMacroExpansionWithResultElement extends MacroInvocation`: An invocation of a macro + * which in this particular instance generates an `InvalidFoo`, while other invocations of the + * same macro do not. + * + * The three above classes all attempt to resolve to the most *specific* macro to the issue at + * hand. For instance, if macro `M1` calls macro `M2` which expands to an `InvalidFoo`, then the + * problem may be with `M2` (it is the most specific macro call here), or the problem may be with + * `M2` (if all expansions of `M2` generate an `InvalidFoo` but not all expansions of `M1` do so). + * + * ## Generating Report Objects + * + * This module also can be used to more easily report issues across these cases, by implementing + * `MacroReportConfigSig` and importing `DeduplicateMacroResults::Report::ReportResult`. + * + * ``` + * module InvalidFooInMacroReportConfig implements MacroReportConfigSig { + * + * // ***Take care that usage of $@ is correct in the following predicates***!!!! + * bindingset[description] + * string getMessageSameResultInAllExpansions(Macro m, string description) { + * result = "Macro " + m.getName() + " always has invalid foo " + description + * } + * + * string getMessageVariedResultInAllExpansions(Macro m) { + * result = "Macro " + m.getName() + " always has invalid foo, for example '$@'." + * } + * + * string getMessageResultInIsolatedExpansion(InvalidFoo foo) { + * result = "Invocation of macro $@ has invalid foo '" + foo.getName() + "'." + * } + * + * string getMessageNotInMacro(ResultElement element) { + * result = "Invalid foo '" + element.getName() + "'." + * } + * } + * + * import DeduplicateFooInMacros::Report as Report; + * + * from Report::ReportResult report + * where not excluded(report.getPrimaryElement(), ...) + * select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocatable(), + * report.getOptionalPlaceholderMessage() + * ``` + * + * Note that this does *not* (currently) generate a result for elements not contained by a macro. + * To do report such cases, either add support for that in this module, or write a separate query + * that reports `InvalidFoo` cases where not `.isInMacroExpansion()`. + */ +module DeduplicateMacroResults< + ResultType ResultElement, DeduplicateMacroConfigSig Config> +{ + /* A final class so that we may extend Macro. */ + final private class FinalMacro = Macro; + + /* Helper final class import so that we may reference/extend it. */ + final private class ResultMacroExpansion = MacroUnwrapper::ResultMacroExpansion; + + /** + * A macro for which all of its invocations produce an element that is described the same way. + * + * This is not necessarily the "primary" / most specific macro for these result elements. + * This difference is captured in `PrimarySameResultElementInAllMacroInvocations`, and the two + * classes are only separate to avoid non-monotonic recursion. + */ + private class SameResultElementInAllMacroInvocations extends FinalMacro { + string resultElementDescription; + + SameResultElementInAllMacroInvocations() { + forex(MacroInvocation mi | mi = getAnInvocation() | + Config::describe(mi.(ResultMacroExpansion).getResultElement()) = resultElementDescription + ) + } + + string getResultElementDescription() { result = resultElementDescription } + + ResultElement getAResultElement() { + result = getAnInvocation().(ResultMacroExpansion).getResultElement() + } + } + + /** + * A macro for which all of its invocations produce an element that is described the same way. + * + * This is the necessarily the "primary" / most specific macro for these result elements. + */ + class PrimaryMacroSameResultElementInAllInvocations extends SameResultElementInAllMacroInvocations + { + PrimaryMacroSameResultElementInAllInvocations() { + not exists(MacroInvocation inner | + inner.getParentInvocation() = getAnInvocation() and + inner.getMacro() instanceof SameResultElementInAllMacroInvocations + ) + } + } + + /** + * A expansion that generates a `ResultElement` that is uniquely described by the config. + * + * This is used so that we can find a single example invocation site to report as an example for + * macros which generate an array of different `ResultElement`s that are described differently. + * + * For example, two macro invocations may be given the same arguments, and generate the same + * `ResultElement`, while a third macro invocation is unique and generates a unique + * `ResultElement`. We wish to direct the user to that unique example or we will show the user + * two different reports for one underlying issue. + */ + private class UniqueResultMacroExpansion extends ResultMacroExpansion { + UniqueResultMacroExpansion() { + not exists(ResultMacroExpansion other | + not this = other and + this.getMacroName() = other.getMacroName() and + Config::describe(this.getResultElement()) = Config::describe(other.getResultElement()) + ) + } + } + + /** + * A macro for which all of its invocations produce an element, but they are not all described the + * same way. + * + * This is not necessarily the "primary" / most specific macro for these result elements. + * This difference is captured in `PrimaryDiferentResultElementInAllMacroInvocations`, and the two + * classes are only separate to avoid non-monotonic recursion. + */ + private class DifferentResultElementInAllMacroInvocations extends FinalMacro { + ResultElement exampleResultElement; + + DifferentResultElementInAllMacroInvocations() { + forex(MacroInvocation mi | mi = getAnInvocation() | mi instanceof ResultMacroExpansion) and + count(getAnInvocation().(ResultMacroExpansion).getResultElement()) > 1 and + exists(string description | + description = + rank[1](Config::describe(getAnInvocation().(UniqueResultMacroExpansion).getResultElement()) + ) and + Config::describe(exampleResultElement) = description and + exampleResultElement = getAnInvocation().(ResultMacroExpansion).getResultElement() + ) + } + + ResultElement getExampleResultElement() { result = exampleResultElement } + + ResultElement getAResultElement() { + result = getAnInvocation().(ResultMacroExpansion).getResultElement() + } + } + + /** + * A macro for which all of its invocations produce an element, but they are not all described the + * same way. + * + * This is "primary" / most specific macro for these result elements. + */ + class PrimaryMacroDifferentResultElementInAllInvocations extends DifferentResultElementInAllMacroInvocations + { + PrimaryMacroDifferentResultElementInAllInvocations() { + not exists(MacroInvocation inner | + inner.getParentInvocation() = getAnInvocation() and + inner.getMacro() instanceof DifferentResultElementInAllMacroInvocations + ) + } + } + + /** + * Convenience predicate to know when invalid macro expansions have been reported at their macro + * definition. + */ + private predicate reported(Macro macro) { + macro instanceof PrimaryMacroSameResultElementInAllInvocations or + macro instanceof PrimaryMacroDifferentResultElementInAllInvocations + } + + /** + * A macro invocation for which the target macro does not always produce a `ResultElement`, but + * this specific invocation of it does. + * + * This is the "primary" / most specific macro for these result elements. It also does not match + * `MacroInvocation`s inside of a `MacroInvocation` of a `Macro` which always produces a + * `ResultElement`, indicating that the real problem lies with that other `Macro` instead of with + * this particular invocation. + */ + class IsolatedMacroExpansionWithResultElement extends ResultMacroExpansion { + IsolatedMacroExpansionWithResultElement() { + not reported(getParentInvocation*().getMacro()) and + not exists(MacroInvocation inner | + reported(inner.getMacro()) and + inner.getParentInvocation*() = this + ) and + not exists(ResultMacroExpansion moreSpecific | + moreSpecific.getResultElement() = getResultElement() and + moreSpecific.getParentInvocation+() = this + ) + } + } + + /** + * A module for generating reports across the various cases of problematic macros, problematic + * macro invocations. + * + * See the doc comment for the `DeduplicateMacroResults` module for more info. + */ + module Report ReportConfig> { + newtype TReportResult = + TReportMacroResultWithSameName(PrimaryMacroSameResultElementInAllInvocations def) or + TReportMacroResultWithVariedName(PrimaryMacroDifferentResultElementInAllInvocations def) or + TReportIsolatedMacroResult(IsolatedMacroExpansionWithResultElement def) or + TReportNotInMacro(ResultElement def) { + not exists(ResultMacroExpansion macroExpansion | macroExpansion.getResultElement() = def) + } + + /** + * An instance of a `ResultElement` to be reported to a user. + * + * To show a report, use the following methods: + * - `report.getPrimaryElement()` + * - `report.getMessage()` + * - `report.getOptionalPlaceholderLocatable()` + * - `report.getOptionalPlaceholderMessage()` + * + * The values returned by these methods are configured by the `MacroReportConfigSig` + * signature parameter. + */ + class ReportResult extends TReportResult { + string toString() { + this = TReportMacroResultWithVariedName(_) and + result = + "Macro that always expands to a result element with invocation-dependent description" + or + this = TReportMacroResultWithSameName(_) and + result = "Macro that always expands to a result element with a constant description" + or + this = TReportIsolatedMacroResult(_) and + result = + "Specific macro expansion which produces a result element, but not all expansions do" + or + this = TReportNotInMacro(_) and + result = "Result element that is not in a macro" + } + + string getMessage() { + exists(PrimaryMacroDifferentResultElementInAllInvocations def | + this = TReportMacroResultWithVariedName(def) and + result = ReportConfig::getMessageVariedResultInAllExpansions(def) + ) + or + exists(PrimaryMacroSameResultElementInAllInvocations def | + this = TReportMacroResultWithSameName(def) and + result = + ReportConfig::getMessageSameResultInAllExpansions(def, def.getResultElementDescription()) + ) + or + exists(IsolatedMacroExpansionWithResultElement def | + this = TReportIsolatedMacroResult(def) and + result = ReportConfig::getMessageResultInIsolatedExpansion(def.getResultElement()) + ) + or + exists(ResultElement def | + this = TReportNotInMacro(def) and + result = ReportConfig::getMessageNotInMacro(def, _, _) + ) + } + + Element getPrimaryElement() { + this = TReportMacroResultWithSameName(result) + or + this = TReportMacroResultWithVariedName(result) + or + this = TReportIsolatedMacroResult(result) + or + this = TReportNotInMacro(result) + } + + Locatable getOptionalPlaceholderLocatable() { + exists(PrimaryMacroDifferentResultElementInAllInvocations def | + this = TReportMacroResultWithVariedName(def) and + result = def.getExampleResultElement() + ) + or + exists(PrimaryMacroSameResultElementInAllInvocations def | + this = TReportMacroResultWithSameName(def) and + result = def + ) + or + exists(IsolatedMacroExpansionWithResultElement def | + this = TReportIsolatedMacroResult(def) and + result = def.getMacro() + ) + or + exists(ResultElement def | + this = TReportNotInMacro(def) and + exists(ReportConfig::getMessageNotInMacro(def, result, _)) + ) + } + + string getOptionalPlaceholderMessage() { + exists(PrimaryMacroDifferentResultElementInAllInvocations def | + this = TReportMacroResultWithVariedName(def) and + result = Config::describe(def.getExampleResultElement()) + ) + or + this = TReportMacroResultWithSameName(_) and + result = "(ignored)" + or + this = TReportIsolatedMacroResult(_) and + result = getMacro().getName() + or + exists(ResultElement def | + this = TReportNotInMacro(def) and + exists(ReportConfig::getMessageNotInMacro(def, _, result)) + ) + } + + Macro getMacro() { + this = TReportMacroResultWithVariedName(result) + or + this = TReportMacroResultWithSameName(result) + or + exists(IsolatedMacroExpansionWithResultElement def | + this = TReportIsolatedMacroResult(def) and + result = def.getMacro() + ) + } + + ResultMacroExpansion getAResultMacroExpansion() { + exists(PrimaryMacroDifferentResultElementInAllInvocations def | + this = TReportMacroResultWithVariedName(def) and + result = def.getAnInvocation() + ) + or + exists(PrimaryMacroSameResultElementInAllInvocations def | + this = TReportMacroResultWithSameName(def) and + result = def.getAnInvocation() + ) + or + this = TReportIsolatedMacroResult(result) + } + + ResultElement getAResultElement() { + result = getAResultMacroExpansion().getResultElement() + or + this = TReportNotInMacro(result) + } + } + } +} diff --git a/cpp/common/src/codingstandards/cpp/alertreporting/HoldsForAllCopies.qll b/cpp/common/src/codingstandards/cpp/alertreporting/HoldsForAllCopies.qll new file mode 100644 index 0000000000..1d47e833dc --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/alertreporting/HoldsForAllCopies.qll @@ -0,0 +1,117 @@ +/** + * A module for considering whether a result occurs in all copies of the code at a given location. + * + * Multiple copies of an element at the same location can occur for two main reasons: + * 1. Instantiations of a template + * 2. Re-compilation of a file under a different context + * This module helps ensure that a particular condition holds for all copies of a particular logical + * element. For example, this can be used to determine whether a line of code is dead in all copies + * of a piece of code. + * + * This module is parameterized by a set of _candidate_ elements in the program. For each candidate + * element, we determine whether all other elements in the same element set that occur at the same + * location in the program are also part of the same set, ignoring any results generated by macros. + * + * We do so by reporting a new type of result, `LogicalResultElement`, which represents a logical result + * where all instances of a element at a given location are considered to be part of the same set. + */ + +import cpp + +/** + * Holds if the `Element` `e` is not within a macro expansion, i.e. generated by a macro, but not + * the outermost `Element` or `Expr` generated by the macro. + */ +predicate isNotWithinMacroExpansion(Element e) { + not e.isInMacroExpansion() + or + exists(MacroInvocation mi | + mi.getStmt() = e + or + mi.getExpr() = e + or + mi.getStmt().(ExprStmt).getExpr() = e + | + not exists(mi.getParentInvocation()) + ) +} + +/** + * A type representing a set of Element's in the program that satisfy some condition. + * + * `HoldsForAllCopies::LogicalResultElement` will represent an element in this set + * iff all copies of that element satisfy the condition. + */ +signature class CandidateElementSig extends Element; + +/** The super set of relevant elements. */ +signature class ElementSetSig extends Element; + +/** + * A module for considering whether a result occurs in all copies of the code at a given location. + */ +module HoldsForAllCopies { + private predicate hasLocation( + ElementSet s, string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + s.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } + + final private class MyElement = ElementSet; + + /** + * A `Element` that appears at the same location as a candidate element. + */ + private class RelevantElement extends MyElement { + CandidateElement e; + + RelevantElement() { + exists(string filepath, int startline, int startcolumn, int endline, int endcolumn | + hasLocation(this, filepath, startline, startcolumn, endline, endcolumn) and + hasLocation(e, filepath, startline, startcolumn, endline, endcolumn) + ) and + // Not within a macro expansion, as we cannot match up instances by location in that + // case + isNotWithinMacroExpansion(this) and + // Ignore catch handlers, as they occur at the same location as the catch block + not this instanceof Handler + } + + CandidateElement getCandidateElement() { result = e } + } + + newtype TResultElements = + TLogicalResultElement( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + exists(CandidateElement s | + hasLocation(s, filepath, startline, startcolumn, endline, endcolumn) and + // All relevant elements that occur at the same location are candidates + forall(RelevantElement relevantElement | s = relevantElement.getCandidateElement() | + relevantElement instanceof CandidateElement + ) + ) + } + + /** + * A logical result element representing all copies of an element that occur at the same + * location, iff they all belong to the `CandidateElement` set. + */ + class LogicalResultElement extends TLogicalResultElement { + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this = TLogicalResultElement(filepath, startline, startcolumn, endline, endcolumn) + } + + /** Gets a copy instance of this logical result element. */ + CandidateElement getAnElementInstance() { + exists(string filepath, int startline, int startcolumn, int endline, int endcolumn | + this = TLogicalResultElement(filepath, startline, startcolumn, endline, endcolumn) and + hasLocation(result, filepath, startline, startcolumn, endline, endcolumn) + ) + } + + string toString() { result = getAnElementInstance().toString() } + } +} diff --git a/cpp/common/src/codingstandards/cpp/allocations/PlacementNew.qll b/cpp/common/src/codingstandards/cpp/allocations/PlacementNew.qll index 5547f2e151..2c9139d0ae 100644 --- a/cpp/common/src/codingstandards/cpp/allocations/PlacementNew.qll +++ b/cpp/common/src/codingstandards/cpp/allocations/PlacementNew.qll @@ -22,7 +22,7 @@ import cpp import codingstandards.cpp.Conversion -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /* * TODO You can also have alignas on types diff --git a/cpp/common/src/codingstandards/cpp/ast/Increment.qll b/cpp/common/src/codingstandards/cpp/ast/Increment.qll new file mode 100644 index 0000000000..00c893baae --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/ast/Increment.qll @@ -0,0 +1,76 @@ +/** + * Provides a library for working with expressions that update the value + * of a numeric variable by incrementing or decrementing it by a certain + * amount. + */ + +import cpp + +private class AssignAddOrSubExpr extends AssignArithmeticOperation { + AssignAddOrSubExpr() { + this instanceof AssignAddExpr or + this instanceof AssignSubExpr + } +} + +private class AddOrSubExpr extends BinaryArithmeticOperation { + AddOrSubExpr() { + this instanceof AddExpr or + this instanceof SubExpr + } +} + +/** + * An expression that updates a numeric variable by adding to or subtracting + * from it a certain amount. + */ +abstract class StepCrementUpdateExpr extends Expr { + /** + * The expression in the abstract syntax tree that represents the amount of + * value by which the variable is updated. + */ + abstract Expr getAmountExpr(); +} + +/** + * An increment or decrement operator application, either postfix or prefix. + */ +class PostfixOrPrefixCrementExpr extends CrementOperation, StepCrementUpdateExpr { + override Expr getAmountExpr() { none() } +} + +/** + * An add-then-assign or subtract-then-assign expression in a shortened form, + * i.e. `+=` or `-=`. + */ +class AssignAddOrSubUpdateExpr extends AssignAddOrSubExpr, StepCrementUpdateExpr { + override Expr getAmountExpr() { result = this.getRValue() } +} + +/** + * An add-then-assign expression or a subtract-then-assign expression, i.e. + * `x = x + E` or `x = x - E`, where `x` is some variable and `E` an + * arbitrary expression. + */ +class AddOrSubThenAssignExpr extends AssignExpr, StepCrementUpdateExpr { + /** The `x` as in the left-hand side of `x = x + E`. */ + VariableAccess lvalueVariable; + /** The `x + E` as in `x = x + E`. */ + AddOrSubExpr addOrSubExpr; + /** The `E` as in `x = x + E`. */ + Expr amountExpr; + + AddOrSubThenAssignExpr() { + this.getLValue() = lvalueVariable and + this.getRValue() = addOrSubExpr and + exists(VariableAccess lvalueVariableAsRvalue | + lvalueVariableAsRvalue = addOrSubExpr.getAnOperand() and + amountExpr = addOrSubExpr.getAnOperand() and + lvalueVariableAsRvalue != amountExpr + | + lvalueVariable.getTarget() = lvalueVariableAsRvalue.(VariableAccess).getTarget() + ) + } + + override Expr getAmountExpr() { result = amountExpr } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/Atomic.qll b/cpp/common/src/codingstandards/cpp/concurrency/Atomic.qll new file mode 100644 index 0000000000..44101f08bb --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/Atomic.qll @@ -0,0 +1,43 @@ +import cpp + +/** + * Models calls to routines `atomic_compare_exchange_weak` and + * `atomic_compare_exchange_weak_explicit` in the `stdatomic` library. + * Note that these are typically implemented as macros within Clang and + * GCC's standard libraries. + */ +class AtomicCompareExchange extends MacroInvocation { + AtomicCompareExchange() { + getMacroName() = "atomic_compare_exchange_weak" + or + // some compilers model `atomic_compare_exchange_weak` as a macro that + // expands to `atomic_compare_exchange_weak_explicit` so this defeats that + // and other similar modeling. + getMacroName() = "atomic_compare_exchange_weak_explicit" and + not exists(MacroInvocation m | + m.getMacroName() = "atomic_compare_exchange_weak" and + m.getAnExpandedElement() = getAnExpandedElement() + ) + } +} + +/** + * Models calls to routines `atomic_store` and + * `atomic_store_explicit` in the `stdatomic` library. + * Note that these are typically implemented as macros within Clang and + * GCC's standard libraries. + */ +class AtomicStore extends MacroInvocation { + AtomicStore() { + getMacroName() = "atomic_store" + or + // some compilers model `atomic_compare_exchange_weak` as a macro that + // expands to `atomic_compare_exchange_weak_explicit` so this defeats that + // and other similar modeling. + getMacroName() = "atomic_store_explicit" and + not exists(MacroInvocation m | + m.getMacroName() = "atomic_store" and + m.getAnExpandedElement() = getAnExpandedElement() + ) + } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/CConditionOperation.qll b/cpp/common/src/codingstandards/cpp/concurrency/CConditionOperation.qll new file mode 100644 index 0000000000..adf230f08d --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/CConditionOperation.qll @@ -0,0 +1,31 @@ +import cpp + +/** + * Models a function which uses a c condition variable. Not integrated into the thread aware CFG. + */ +class CConditionOperation extends FunctionCall { + CConditionOperation() { + getTarget().hasName(["cnd_broadcast", "cnd_signal", "cnd_timedwait", "cnd_wait", "cnd_init"]) + } + + predicate isInit() { getTarget().hasName("cnd_init") } + + predicate isUse() { not isInit() } + + Expr getConditionExpr() { result = getArgument(0) } + + /* Note: only holds for `cnd_wait()` and `cnd_timedwait()` */ + Expr getMutexExpr() { result = getArgument(1) } +} + +/** + * Models C style condition destruction via `cnd_destroy`. + */ +class C11ConditionDestroyer extends FunctionCall { + C11ConditionDestroyer() { getTarget().getName() = "cnd_destroy" } + + /** + * Returns the `Expr` being destroyed. + */ + Expr getConditionExpr() { result = getArgument(0) } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/ConditionalWait.qll b/cpp/common/src/codingstandards/cpp/concurrency/ConditionalWait.qll new file mode 100644 index 0000000000..e69ea2fee5 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/ConditionalWait.qll @@ -0,0 +1,26 @@ +import cpp + +/** + * Models a function that conditionally waits. + */ +abstract class ConditionalWait extends FunctionCall { } + +/** + * Models a function in CPP that will conditionally wait. + */ +class CPPConditionalWait extends ConditionalWait { + CPPConditionalWait() { + exists(MemberFunction mf | + mf = getTarget() and + mf.getDeclaringType().hasQualifiedName("std", "condition_variable") and + mf.getName() in ["wait", "wait_for", "wait_until"] + ) + } +} + +/** + * Models a function in C that will conditionally wait. + */ +class CConditionalWait extends ConditionalWait { + CConditionalWait() { getTarget().getName() in ["cnd_wait"] } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/ControlFlow.qll b/cpp/common/src/codingstandards/cpp/concurrency/ControlFlow.qll new file mode 100644 index 0000000000..15f8ab5a61 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/ControlFlow.qll @@ -0,0 +1,101 @@ +import cpp +private import codingstandards.cpp.concurrency.ThreadedFunction + +/** + * Models a control flow node within a function that may be executed by some + * thread. + */ +class ThreadedCFN extends ControlFlowNode { + ThreadedCFN() { + exists(ThreadedFunction tf | this = getAThreadContextAwareSuccessor(tf.getEntryPoint())) + } +} + +/** + * Models CFG nodes which should be added to a thread context. + */ +abstract class ThreadedCFGPathExtension extends ControlFlowNode { + /** + * Returns the next `ControlFlowNode` in this thread context. + */ + abstract ControlFlowNode getNext(); +} + +/** + * Models a `FunctionCall` invoked from a threaded context. + */ +class ThreadContextFunctionCall extends FunctionCall, ThreadedCFGPathExtension { + override ControlFlowNode getNext() { getTarget().getEntryPoint() = result } +} + +/** + * Models a specialized `FunctionCall` that may create a thread. + */ +abstract class ThreadCreationFunction extends FunctionCall, ThreadedCFGPathExtension { + /** + * Returns the function that will be invoked. + */ + abstract Function getFunction(); +} + +/** + * The thread-aware predecessor function is defined in terms of the thread aware + * successor function. This is because it is simpler to construct the forward + * paths of a thread's execution than the backwards paths. For this reason we + * require a `start` and `end` node. + * + * The logic of this function is that a thread aware predecessor is one that + * follows a `start` node, is not equal to the ending node, and does not follow + * the `end` node. Such nodes can only be predecessors of `end`. + * + * For this reason this function requires a `start` node from which to start + * considering something a predecessor of `end`. + */ +pragma[inline] +ControlFlowNode getAThreadContextAwarePredecessor(ControlFlowNode start, ControlFlowNode end) { + result = getAThreadContextAwareSuccessor(start) and + not result = getAThreadContextAwareSuccessor(end) and + not result = end +} + +/** + * A predicate for finding successors of `ControlFlowNode`s that are aware of + * the objects that my flow into a thread's context. This is achieved by adding + * additional edges to thread entry points and function calls. + */ +ControlFlowNode getAThreadContextAwareSuccessorR(ControlFlowNode cfn) { + result = cfn.getASuccessor() + or + result = cfn.(ThreadedCFGPathExtension).getNext() +} + +ControlFlowNode getAThreadContextAwareSuccessor(ControlFlowNode m) { + result = getAThreadContextAwareSuccessorR*(m) and + // for performance reasons we handle back edges by enforcing a lexical + // ordering restriction on these nodes if they are both in + // the same loop. One way of doing this is as follows: + // + // ````and ( + // exists(Loop loop | + // loop.getAChild*() = m and + // loop.getAChild*() = result + // ) + // implies + // not result.getLocation().isBefore(m.getLocation()) + // )``` + // In this implementation we opt for the more generic form below + // which seems to have reasonable performance. + ( + m.getEnclosingStmt().getParentStmt*() = result.getEnclosingStmt().getParentStmt*() + implies + not exists(Location l1, Location l2 | + l1 = result.getLocation() and + l2 = m.getLocation() + | + l1.getEndLine() < l2.getStartLine() + or + l1.getStartLine() = l2.getEndLine() and + l1.getEndColumn() < l2.getStartColumn() + ) + ) +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/LockProtectedControlFlow.qll b/cpp/common/src/codingstandards/cpp/concurrency/LockProtectedControlFlow.qll new file mode 100644 index 0000000000..5def491fb2 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/LockProtectedControlFlow.qll @@ -0,0 +1,50 @@ +import cpp +private import codingstandards.cpp.concurrency.ControlFlow +private import codingstandards.cpp.concurrency.LockingOperation + +/** + * Models a `ControlFlowNode` that is protected by some sort of lock. + */ +class LockProtectedControlFlowNode extends ThreadedCFN { + FunctionCall lockingFunction; + + LockProtectedControlFlowNode() { + exists(LockingOperation lock | + // there is a node that is a lock + lockingFunction = lock and + lock.isLock() and + // this node should be a successor of this lock + this = getAThreadContextAwareSuccessor(lock) and + // and there should not exist a predecessor of this + // node that is an unlock. Since we are doing thread context + // aware tracking it is easier to go forwards than backwards + // in constructing the call graph. Thus we can define predecessor + // in terms of a node that is a successor of the lock but NOT a + // successor of the current node. + not exists(ControlFlowNode unlock | + // it's an unlock + unlock = getAThreadContextAwarePredecessor(lock, this) and + unlock.(MutexFunctionCall).isUnlock() and + // note that we don't check that it's the same lock -- this is left + // to the caller to enforce this condition. + // Because of the way that `getAThreadContextAwarePredecessor` works, it is possible + // for operations PAST it to be technically part of the predecessors. + // Thus, we need to make sure that this node is a + // successor of the unlock in the CFG + getAThreadContextAwareSuccessor(unlock) = this + ) and + (lock instanceof MutexFunctionCall implies not this.(MutexFunctionCall).isUnlock()) + ) + } + + /** + * The LockingOperation (for instance, a `MutexFunctionCall`, or RAII-style lock constructor) + * holding the lock that locks this node. + */ + LockingOperation coveredByLock() { result = lockingFunction } + + /** + * The lock underlying this `LockProtectedControlFlowNode`. + */ + Variable getAProtectingLock() { result = lockingFunction.(LockingOperation).getLock() } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/LockingOperation.qll b/cpp/common/src/codingstandards/cpp/concurrency/LockingOperation.qll new file mode 100644 index 0000000000..cfa263792e --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/LockingOperation.qll @@ -0,0 +1,256 @@ +import cpp +private import semmle.code.cpp.dataflow.TaintTracking + +abstract class LockingOperation extends FunctionCall { + /** + * Returns the target of the lock underlying this RAII-style lock. + */ + abstract Variable getLock(); + + /** + * Returns the lock underlying this RAII-style lock. + */ + abstract Expr getLockExpr(); + + /** + * Holds if this is a lock operation + */ + abstract predicate isLock(); + + /** + * Holds if this is an unlock operation + */ + abstract predicate isUnlock(); + + /** + * Holds if this locking operation can leak the lock. For example, RAII-style locks cannot leak. + */ + abstract predicate canLeak(); + + /** + * Holds if this locking operation is really a locking operation within a + * designated locking operation. This library assumes the underlying locking + * operations are implemented correctly in that calling a `LockingOperation` + * results in the creation of a singular lock. + */ + predicate isLockingOperationWithinLockingOperation(LockingOperation inner) { + exists(LockingOperation outer | outer.getTarget() = inner.getEnclosingFunction()) + } +} + +/** + * A locking operation that can leak the lock. + * + * RAII style locks cannot leak, but other kinds of locks can. + */ +abstract class LeakableLockingOperation extends LockingOperation { + override predicate canLeak() { any() } +} + +/** + * A locking operation that cannot leak the lock, such as RAII-style locks. + */ +abstract class NonLeakableLockingOperation extends LockingOperation { + override predicate canLeak() { none() } +} + +/** + * Common base class providing an interface into function call + * based mutex locks. + */ +abstract class MutexFunctionCall extends LeakableLockingOperation { + abstract predicate isRecursive(); + + abstract predicate isSpeculativeLock(); + + abstract predicate unlocks(MutexFunctionCall fc); +} + +/** + * Models calls to various mutex types found in CPP. + */ +class CPPMutexFunctionCall extends MutexFunctionCall { + VariableAccess var; + + CPPMutexFunctionCall() { + getTarget() + .(MemberFunction) + .getDeclaringType() + .hasQualifiedName("std", + ["mutex", "timed_mutex", "shared_timed_mutex", "recursive_mutex", "recursive_timed_mutex"]) and + var = getQualifier() + } + + /** + * Holds if this mutex is a recursive mutex. + */ + override predicate isRecursive() { + getTarget() + .(MemberFunction) + .getDeclaringType() + .hasQualifiedName("std", ["recursive_mutex", "recursive_timed_mutex"]) + } + + /** + * Holds if this `CPPMutexFunctionCall` is a lock. + */ + override predicate isLock() { + not isLockingOperationWithinLockingOperation(this) and + getTarget().getName() = "lock" + } + + /** + * Holds if this `CPPMutexFunctionCall` is a speculative lock, defined as calling + * one of the speculative locking functions such as `try_lock`. + */ + override predicate isSpeculativeLock() { + getTarget().getName() in [ + "try_lock", "try_lock_for", "try_lock_until", "try_lock_shared_for", "try_lock_shared_until" + ] + } + + /** + * Returns the lock to which this `CPPMutexFunctionCall` refers to. + */ + override Variable getLock() { result = getQualifier().(VariableAccess).getTarget() } + + /** + * Returns the qualifier for this `CPPMutexFunctionCall`. + */ + override Expr getLockExpr() { result = var } + + /** + * Holds if this is a `unlock` and *may* unlock the previously locked `MutexFunctionCall`. + * This predicate does not check that the mutex is currently locked. + */ + override predicate unlocks(MutexFunctionCall fc) { + isUnlock() and + fc.getQualifier().(VariableAccess).getTarget() = getQualifier().(VariableAccess).getTarget() + } + + /** + * Holds if this is an unlock call. + */ + override predicate isUnlock() { getTarget().getName() = "unlock" } +} + +/** + * Models calls to various mutex types specialized to C code. + */ +class CMutexFunctionCall extends MutexFunctionCall { + Expr arg; + + CMutexFunctionCall() { + // the non recursive kinds + getTarget().getName() = ["mtx_lock", "mtx_unlock", "mtx_timedlock", "mtx_trylock"] and + arg = getArgument(0) + } + + /** + * Holds if this mutex is a recursive mutex. + */ + override predicate isRecursive() { none() } + + /** + * Holds if this `CMutexFunctionCall` is a lock. + */ + override predicate isLock() { + not isLockingOperationWithinLockingOperation(this) and + getTarget().getName() = ["mtx_lock", "mtx_timedlock", "mtx_trylock"] + } + + /** + * Holds if this `CMutexFunctionCall` is a speculative lock, defined as calling + * one of the speculative locking functions such as `try_lock`. + */ + override predicate isSpeculativeLock() { + getTarget().getName() in ["mtx_timedlock", "mtx_trylock"] + } + + /** + * Returns the `Variable` to which this `CMutexFunctionCall` refers to. For this + * style of lock it can reference a number of different variables. + */ + override Variable getLock() { + exists(VariableAccess va | + TaintTracking::localTaint(DataFlow::exprNode(va), DataFlow::exprNode(getLockExpr())) and + result = va.getTarget() + ) + } + + /** + * Returns the expression for this `CMutexFunctionCall`. + */ + override Expr getLockExpr() { result = arg } + + /** + * Holds if this is a `unlock` and *may* unlock the previously locked `CMutexFunctionCall`. + * This predicate does not check that the mutex is currently locked. + */ + override predicate unlocks(MutexFunctionCall fc) { + isUnlock() and + fc.getLock() = getLock() + } + + /** + * Holds if this is an unlock call. + */ + override predicate isUnlock() { getTarget().getName() = "mtx_unlock" } +} + +/** + * Models a RAII-Style lock. + */ +class RAIIStyleLock extends NonLeakableLockingOperation { + VariableAccess lock; + + RAIIStyleLock() { + ( + getTarget().getDeclaringType().hasQualifiedName("std", "lock_guard") or + getTarget().getDeclaringType().hasQualifiedName("std", "unique_lock") or + getTarget().getDeclaringType().hasQualifiedName("std", "scoped_lock") + ) and + ( + lock = getArgument(0).getAChild*() + or + this instanceof DestructorCall and + exists(RAIIStyleLock constructor | + constructor = getQualifier().(VariableAccess).getTarget().getInitializer().getExpr() and + lock = constructor.getArgument(0).getAChild*() + ) + ) + } + + /** + * Holds if this is a lock operation + */ + override predicate isLock() { + not isLockingOperationWithinLockingOperation(this) and + this instanceof ConstructorCall and + lock = getArgument(0).getAChild*() and + // defer_locks don't cause a lock + not exists(Expr exp | + exp = getArgument(1) and + exp.(VariableAccess) + .getTarget() + .getUnderlyingType() + .(Class) + .hasQualifiedName("std", "defer_lock_t") + ) + } + + /** + * Holds if this is an unlock operation + */ + override predicate isUnlock() { this instanceof DestructorCall } + + /** + * Returns the target of the lock underlying this RAII-style lock. + */ + override Variable getLock() { result = lock.getTarget() } + + /** + * Returns the lock underlying this RAII-style lock. + */ + override Expr getLockExpr() { result = lock } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/MutexDestroyer.qll b/cpp/common/src/codingstandards/cpp/concurrency/MutexDestroyer.qll new file mode 100644 index 0000000000..915efc6077 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/MutexDestroyer.qll @@ -0,0 +1,73 @@ +import cpp + +/** + * Models expressions that destroy mutexes. + */ +abstract class MutexDestroyer extends StmtParent { + /** + * Gets the expression that references the mutex being destroyed. + */ + abstract Expr getMutexExpr(); +} + +/** + * Models C style mutex destruction via `mtx_destroy`. + */ +class C11MutexDestroyer extends MutexDestroyer, FunctionCall { + C11MutexDestroyer() { getTarget().getName() = "mtx_destroy" } + + /** + * Returns the `Expr` being destroyed. + */ + override Expr getMutexExpr() { result = getArgument(0) } +} + +/** + * Models a delete expression -- note it is necessary to add this in + * addition to destructors to handle certain implementations of the + * standard library which obscure the destructors of mutexes. + */ +class DeleteMutexDestroyer extends MutexDestroyer { + DeleteMutexDestroyer() { this instanceof DeleteExpr } + + override Expr getMutexExpr() { this.(DeleteExpr).getExpr() = result } +} + +/** + * Models a possible mutex variable that if it goes + * out of scope would destroy an underlying mutex. + */ +class LocalMutexDestroyer extends MutexDestroyer { + Expr assignedValue; + + LocalMutexDestroyer() { + exists(LocalVariable lv | + // static types aren't destroyers + not lv.isStatic() and + // neither are pointers + not lv.getType() instanceof PointerType and + lv.getAnAssignedValue() = assignedValue and + // map the location to the return statements of the + // enclosing function + exists(ReturnStmt rs | + rs.getEnclosingFunction() = assignedValue.getEnclosingFunction() and + rs = this + ) + ) + } + + override Expr getMutexExpr() { result = assignedValue } +} + +/** + * Models implicit or explicit calls to the destructor of a mutex, either via + * a `delete` statement or a variable going out of scope. + */ +class DestructorMutexDestroyer extends MutexDestroyer, DestructorCall { + DestructorMutexDestroyer() { getTarget().getDeclaringType().hasQualifiedName("std", "mutex") } + + /** + * Returns the `Expr` being deleted. + */ + override Expr getMutexExpr() { getQualifier() = result } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/ThreadCreation.qll b/cpp/common/src/codingstandards/cpp/concurrency/ThreadCreation.qll new file mode 100644 index 0000000000..4499b993ad --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/ThreadCreation.qll @@ -0,0 +1,62 @@ +import cpp +private import codingstandards.cpp.concurrency.ControlFlow + +/** + * Models a call to a thread constructor via `std::thread`. + */ +class ThreadConstructorCall extends ConstructorCall, ThreadCreationFunction { + Function f; + + ThreadConstructorCall() { + getTarget().getDeclaringType().hasQualifiedName("std", "thread") and + f = getArgument(0).(FunctionAccess).getTarget() + } + + /** + * Returns the function that will be invoked by this `std::thread`. + */ + override Function getFunction() { result = f } + + override ControlFlowNode getNext() { result = getFunction().getEntryPoint() } +} + +/** + * Models a call to a thread creation via `thrd_create` or `pthread_create`. + */ +class CThreadCreateCall extends FunctionCall { + Function f; + int fArgIdx; + + CThreadCreateCall() { + ( + getTarget().getName() = "thrd_create" and + fArgIdx = 1 + or + getTarget().getName() = "pthread_create" and + fArgIdx = 2 + ) and + ( + f = getArgument(fArgIdx).(FunctionAccess).getTarget() or + f = getArgument(fArgIdx).(AddressOfExpr).getOperand().(FunctionAccess).getTarget() + ) + } + + /** + * Returns the function that will be invoked by this thread. + */ + Function getFunction() { result = f } +} + +/** + * Models a call to a thread constructor via `thrd_create`. + */ +class C11ThreadCreateCall extends ThreadCreationFunction, CThreadCreateCall { + C11ThreadCreateCall() { getTarget().getName() = "thrd_create" } + + /** + * Returns the function that will be invoked by this thread. + */ + override Function getFunction() { result = f } + + override ControlFlowNode getNext() { result = getFunction().getEntryPoint() } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/ThreadDependentMutex.qll b/cpp/common/src/codingstandards/cpp/concurrency/ThreadDependentMutex.qll new file mode 100644 index 0000000000..f86e94566f --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/ThreadDependentMutex.qll @@ -0,0 +1,246 @@ +import cpp +import semmle.code.cpp.dataflow.TaintTracking +private import codingstandards.cpp.concurrency.ControlFlow +private import codingstandards.cpp.concurrency.ThreadedFunction + +abstract class MutexSource extends FunctionCall { } + +/** + * Models a C++ style mutex. + */ +class CPPMutexSource extends MutexSource, ConstructorCall { + CPPMutexSource() { getTarget().getDeclaringType().hasQualifiedName("std", "mutex") } +} + +/** + * Models a C11 style mutex. + */ +class C11MutexSource extends MutexSource, FunctionCall { + C11MutexSource() { getTarget().hasName("mtx_init") } + + Expr getMutexExpr() { result = getArgument(0) } + + Expr getMutexTypeExpr() { result = getArgument(1) } + + predicate isRecursive() { + exists(EnumConstantAccess recursive | + recursive = getMutexTypeExpr().getAChild*() and + recursive.getTarget().hasName("mtx_recursive") + ) + } +} + +/** + * Models a thread dependent mutex. A thread dependent mutex is a mutex + * that is used by a thread. This dependency is established either by directly + * passing in a mutex or by referencing a mutex that is in the local scope. The utility + * of this class is it captures the `DataFlow::Node` source at which the mutex + * came from. For example, if it is passed in from a local function to a thread. + * This functionality is critical, since it allows one to inspect how the thread + * behaves with respect to the owner of a resource. + * + * To model the myriad ways this can happen, the subclasses of this class are + * responsible for implementing the various usage patterns. + */ +abstract class ThreadDependentMutex extends DataFlow::Node { + DataFlow::Node sink; + + DataFlow::Node getASource() { + // the source is either the thing that declared + // the mutex + result = this + or + // or the thread we are using it in + result = getAThreadSource() + } + + /** + * Gets the dataflow nodes corresponding to thread local usages of the + * dependent mutex. + */ + DataFlow::Node getAThreadSource() { + // here we line up the actual parameter at the thread creation + // site with the formal parameter in the target thread. + // Note that there are differences between the C and C++ versions + // of the argument ordering in the thread creation function. However, + // since the C version only takes one parameter (as opposed to multiple) + // we can simplify this search by considering only the first argument. + exists(FunctionCall fc, Function f, int n | + // Get the argument to which the mutex flowed. + fc.getArgument(n) = sink.asExpr() and + // Get the thread function we are calling. + f = fc.getArgument(0).(FunctionAccess).getTarget() and + // in C++, there is an extra argument to the `std::thread` call + // so we must subtract 1 since this is not passed to the thread. + ( + result = DataFlow::exprNode(f.getParameter(n - 1).getAnAccess()) + or + // In C, only one argument is allowed. Thus IF the flow predicate holds, + // it will be to the first argument + result = DataFlow::exprNode(f.getParameter(0).getAnAccess()) + ) + ) + } + + /** + * Produces the set of dataflow nodes to thread creation for threads + * that are dependent on this mutex. + */ + DataFlow::Node getADependentThreadCreationExpr() { + exists(FunctionCall fc | + fc.getAnArgument() = sink.asExpr() and + result = DataFlow::exprNode(fc) + ) + } + + /** + * Gets a set of usages of this mutex in both the local and thread scope. + * In the case of scoped usage, this also captures typical accesses of variables. + */ + DataFlow::Node getAUsage() { TaintTracking::localTaint(getASource(), result) } +} + +/** + * This class models the type of thread/mutex dependency that is established + * through the typical parameter passing mechanisms found in C++. + */ +class FlowBasedThreadDependentMutex extends ThreadDependentMutex { + FlowBasedThreadDependentMutex() { + // some sort of dataflow, likely through parameter passing. + ThreadDependentMutexFlow::flow(this, sink) + } +} + +/** + * This class models the type of thread/mutex dependency that is established by + * either scope based accesses (e.g., global variables) or block scope differences. + */ +class AccessBasedThreadDependentMutex extends ThreadDependentMutex { + Variable variableSource; + + AccessBasedThreadDependentMutex() { + // encapsulates usages from outside scopes not directly expressed + // in dataflow. + exists(MutexSource mutexSrc, ThreadedFunction f | + DataFlow::exprNode(mutexSrc) = this and + // find a variable that was assigned the mutex + TaintTracking::localTaint(DataFlow::exprNode(mutexSrc), + DataFlow::exprNode(variableSource.getAnAssignedValue())) and + // find all subsequent accesses of that variable that are within a + // function and set those to the sink + exists(VariableAccess va | + va = variableSource.getAnAccess() and + va.getEnclosingFunction() = f and + sink = DataFlow::exprNode(va) + ) + ) + } + + override DataFlow::Node getAUsage() { DataFlow::exprNode(variableSource.getAnAccess()) = result } +} + +/** + * In the typical C thread model, a mutex is a created by a function that is not responsible + * for creating the variable. Thus this class encodes a slightly different semantics + * wherein the usage pattern is that of variables that have been both initialized + * and then subsequently passed into a thread directly. + */ +class DeclarationInitBasedThreadDependentMutex extends ThreadDependentMutex { + Variable variableSource; + + DeclarationInitBasedThreadDependentMutex() { + exists(MutexSource ms, ThreadCreationFunction tcf | + this = DataFlow::exprNode(ms) and + // accessed as a mutex source + TaintTracking::localTaint(DataFlow::exprNode(variableSource.getAnAccess()), + DataFlow::exprNode(ms.getAnArgument())) and + // subsequently passed to a thread creation function (order not strictly + // enforced for performance reasons) + sink = DataFlow::exprNode(tcf.getAnArgument()) and + TaintTracking::localTaint(DataFlow::exprNode(variableSource.getAnAccess()), sink) + ) + } + + override DataFlow::Node getAUsage() { + TaintTracking::localTaint(getASource(), result) or + DataFlow::exprNode(variableSource.getAnAccess()) = result + } + + override DataFlow::Node getASource() { + // the source is either the thing that declared + // the mutex + result = this + or + // or the thread we are using it in + result = getAThreadSource() + } + + DataFlow::Node getSink() { result = sink } + + /** + * Gets the dataflow nodes corresponding to thread local usages of the + * dependent mutex. + */ + override DataFlow::Node getAThreadSource() { + // here we line up the actual parameter at the thread creation + // site with the formal parameter in the target thread. + // Note that there are differences between the C and C++ versions + // of the argument ordering in the thread creation function. However, + // since the C version only takes one parameter (as opposed to multiple) + // we can simplify this search by considering only the first argument. + exists( + FunctionCall fc, Function f, int n // CPP Version + | + fc.getArgument(n) = sink.asExpr() and + f = fc.getArgument(0).(FunctionAccess).getTarget() and + // in C++, there is an extra argument to the `std::thread` call + // so we must subtract 1 since this is not passed to the thread. + result = DataFlow::exprNode(f.getParameter(n - 1).getAnAccess()) + ) + or + exists( + FunctionCall fc, Function f // C Version + | + fc.getAnArgument() = sink.asExpr() and + // in C, the second argument is the function + f = fc.getArgument(1).(FunctionAccess).getTarget() and + // in C, the passed argument is always the zeroth argument + result = DataFlow::exprNode(f.getParameter(0).getAnAccess()) + ) + } +} + +/** + * In the typical C model, another way to use mutexes is to work with global variables + * that can be initialized at various points -- one of which must be inside a thread. + * This class encapsulates this pattern. + */ +class DeclarationInitAccessBasedThreadDependentMutex extends ThreadDependentMutex { + Variable variableSource; + + DeclarationInitAccessBasedThreadDependentMutex() { + exists(MutexSource ms, ThreadedFunction tf, VariableAccess va | + this = DataFlow::exprNode(ms) and + // accessed as a mutex source + TaintTracking::localTaint(DataFlow::exprNode(variableSource.getAnAccess()), + DataFlow::exprNode(ms.getAnArgument())) and + // is accessed somewhere else + va = variableSource.getAnAccess() and + sink = DataFlow::exprNode(va) and + // one of which must be a thread + va.getEnclosingFunction() = tf + ) + } + + override DataFlow::Node getAUsage() { result = DataFlow::exprNode(variableSource.getAnAccess()) } +} + +module ThreadDependentMutexConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { node.asExpr() instanceof MutexSource } + + predicate isSink(DataFlow::Node node) { + exists(ThreadCreationFunction f | f.getAnArgument() = node.asExpr()) + } +} + +module ThreadDependentMutexFlow = TaintTracking::Global; diff --git a/cpp/common/src/codingstandards/cpp/concurrency/ThreadSpecificStorage.qll b/cpp/common/src/codingstandards/cpp/concurrency/ThreadSpecificStorage.qll new file mode 100644 index 0000000000..aa7daf972c --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/ThreadSpecificStorage.qll @@ -0,0 +1,59 @@ +import cpp +private import semmle.code.cpp.dataflow.DataFlow +private import codingstandards.cpp.concurrency.ThreadCreation + +/** + * Models calls to thread specific storage function calls. + */ +abstract class ThreadSpecificStorageFunctionCall extends FunctionCall { + /** + * Gets the key to which this call references. + */ + Expr getKey() { getArgument(0) = result } +} + +/** + * Models calls to `tss_get`. + */ +class TSSGetFunctionCall extends ThreadSpecificStorageFunctionCall { + TSSGetFunctionCall() { getTarget().getName() = "tss_get" } +} + +/** + * Models calls to `tss_set`. + */ +class TSSSetFunctionCall extends ThreadSpecificStorageFunctionCall { + TSSSetFunctionCall() { getTarget().getName() = "tss_set" } +} + +/** + * Models calls to `tss_create` + */ +class TSSCreateFunctionCall extends ThreadSpecificStorageFunctionCall { + TSSCreateFunctionCall() { getTarget().getName() = "tss_create" } + + predicate hasDeallocator() { + not exists(MacroInvocation mi, NullMacro nm | + getArgument(1) = mi.getExpr() and + mi = nm.getAnInvocation() + ) + } +} + +/** + * Models calls to `tss_delete` + */ +class TSSDeleteFunctionCall extends ThreadSpecificStorageFunctionCall { + TSSDeleteFunctionCall() { getTarget().getName() = "tss_delete" } +} + +/** + * Gets a call to `DeallocationExpr` that deallocates memory owned by thread specific + * storage. + */ +predicate getAThreadSpecificStorageDeallocationCall(C11ThreadCreateCall tcc, DeallocationExpr dexp) { + exists(TSSGetFunctionCall tsg | + tcc.getFunction().getEntryPoint().getASuccessor*() = tsg and + DataFlow::localFlow(DataFlow::exprNode(tsg), DataFlow::exprNode(dexp.getFreedExpr())) + ) +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/ThreadWaitDetach.qll b/cpp/common/src/codingstandards/cpp/concurrency/ThreadWaitDetach.qll new file mode 100644 index 0000000000..6898dc54df --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/ThreadWaitDetach.qll @@ -0,0 +1,41 @@ +import cpp + +/** + * Models thread waiting functions. + */ +abstract class ThreadWait extends FunctionCall { } + +/** + * Models a call to a `std::thread` join. + */ +class CPPThreadWait extends ThreadWait { + VariableAccess var; + + CPPThreadWait() { + getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "thread") and + getTarget().getName() = "join" + } +} + +/** + * Models a call to `thrd_join` in C11. + */ +class C11ThreadWait extends ThreadWait { + VariableAccess var; + + C11ThreadWait() { getTarget().getName() = "thrd_join" } +} + +/** + * Models thread detach functions. + */ +abstract class ThreadDetach extends FunctionCall { } + +/** + * Models a call to `thrd_detach` in C11. + */ +class C11ThreadDetach extends ThreadWait { + VariableAccess var; + + C11ThreadDetach() { getTarget().getName() = "thrd_detach" } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/ThreadedFunction.qll b/cpp/common/src/codingstandards/cpp/concurrency/ThreadedFunction.qll new file mode 100644 index 0000000000..a8d2c609c5 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/ThreadedFunction.qll @@ -0,0 +1,37 @@ +import cpp +private import codingstandards.cpp.concurrency.ThreadCreation + +/** + * Models a function that may be executed by some thread. + */ +abstract class ThreadedFunctionBase extends Function { + abstract Expr getSpawnExpr(); + + predicate isMultiplySpawned() { getSpawnExpr().getBasicBlock().inLoop() } +} + +final class ThreadedFunction = ThreadedFunctionBase; + +/** + * Models a function that may be executed by some thread via + * C++ standard classes. + */ +class CPPThreadedFunction extends ThreadedFunctionBase { + ThreadConstructorCall tcc; + + CPPThreadedFunction() { tcc.getFunction() = this } + + override Expr getSpawnExpr() { result = tcc } +} + +/** + * Models a function that may be executed by some thread via + * C11 standard functions. + */ +class C11ThreadedFunction extends ThreadedFunctionBase { + C11ThreadCreateCall cc; + + C11ThreadedFunction() { cc.getFunction() = this } + + override Expr getSpawnExpr() { result = cc } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/Types.qll b/cpp/common/src/codingstandards/cpp/concurrency/Types.qll new file mode 100644 index 0000000000..3b865d5171 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/Types.qll @@ -0,0 +1,29 @@ +import cpp + +class C11MutexType extends TypedefType { + C11MutexType() { this.hasName("mtx_t") } +} + +class C11ThreadType extends TypedefType { + C11ThreadType() { this.hasName("thrd_t") } +} + +class C11ConditionType extends TypedefType { + C11ConditionType() { this.hasName("cnd_t") } +} + +class C11ThreadStorageType extends TypedefType { + C11ThreadStorageType() { this.hasName("tss_t") } +} + +class C11ThreadingObjectType extends TypedefType { + C11ThreadingObjectType() { + this instanceof C11MutexType + or + this instanceof C11ThreadType + or + this instanceof C11ConditionType + or + this instanceof C11ThreadStorageType + } +} diff --git a/cpp/common/src/codingstandards/cpp/dataflow/DataFlow.qll b/cpp/common/src/codingstandards/cpp/dataflow/DataFlow.qll deleted file mode 100644 index c11bf80fc6..0000000000 --- a/cpp/common/src/codingstandards/cpp/dataflow/DataFlow.qll +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Provides a library for local (intra-procedural) and global (inter-procedural) - * data flow analysis: deciding whether data can flow from a _source_ to a - * _sink_. - * - * Unless configured otherwise, _flow_ means that the exact value of - * the source may reach the sink. We do not track flow across pointer - * dereferences or array indexing. To track these types of flow, where the - * exact value may not be preserved, import - * `semmle.code.cpp.dataflow.TaintTracking`. - * - * To use global (interprocedural) data flow, extend the class - * `DataFlow::Configuration` as documented on that class. To use local - * (intraprocedural) data flow between expressions, call - * `DataFlow::localExprFlow`. For more general cases of local data flow, call - * `DataFlow::localFlow` or `DataFlow::localFlowStep` with arguments of type - * `DataFlow::Node`. - * - * NOTE: This is copied from `codeql/cpp-all` to avoid deprecation warnings - * that cannot be avoided in tests. - */ - -import cpp - -/** - * DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow` instead. - * - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ -module DataFlow { - private import semmle.code.cpp.dataflow.internal.DataFlowImplSpecific - private import codeql.dataflow.DataFlow - import DataFlowMake - import semmle.code.cpp.dataflow.internal.DataFlowImpl1 -} diff --git a/cpp/common/src/codingstandards/cpp/dataflow/DataFlow2.qll b/cpp/common/src/codingstandards/cpp/dataflow/DataFlow2.qll deleted file mode 100644 index 83859535d8..0000000000 --- a/cpp/common/src/codingstandards/cpp/dataflow/DataFlow2.qll +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Provides a `DataFlow2` module, which is a copy of the `DataFlow` module. Use - * this class when data-flow configurations must depend on each other. Two - * classes extending `DataFlow::Configuration` should never depend on each - * other, but one of them should instead depend on a - * `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a - * `DataFlow4::Configuration`. - * - * See `semmle.code.cpp.dataflow.DataFlow` for the full documentation. - * - * NOTE: This is copied from `codeql/cpp-all` to avoid deprecation warnings - * that cannot be avoided in tests. - */ - -import cpp - -/** - * DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow2` instead. - * - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ -module DataFlow2 { - import semmle.code.cpp.dataflow.internal.DataFlowImpl2 -} diff --git a/cpp/common/src/codingstandards/cpp/dataflow/TaintTracking.qll b/cpp/common/src/codingstandards/cpp/dataflow/TaintTracking.qll deleted file mode 100644 index 2b43a53ccb..0000000000 --- a/cpp/common/src/codingstandards/cpp/dataflow/TaintTracking.qll +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) taint-tracking analyses. - * - * We define _taint propagation_ informally to mean that a substantial part of - * the information from the source is preserved at the sink. For example, taint - * propagates from `x` to `x + 100`, but it does not propagate from `x` to `x > - * 100` since we consider a single bit of information to be too little. - * - * To use global (interprocedural) taint tracking, extend the class - * `TaintTracking::Configuration` as documented on that class. To use local - * (intraprocedural) taint tracking between expressions, call - * `TaintTracking::localExprTaint`. For more general cases of local taint - * tracking, call `TaintTracking::localTaint` or - * `TaintTracking::localTaintStep` with arguments of type `DataFlow::Node`. - * - * NOTE: This is copied from `codeql/cpp-all` to avoid deprecation warnings - * that cannot be avoided in tests. - */ - -import codingstandards.cpp.dataflow.DataFlow -import codingstandards.cpp.dataflow.DataFlow2 - -/** - * DEPRECATED: Use `semmle.code.cpp.dataflow.new.TaintTracking` instead. - * - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) taint-tracking analyses. - */ -module TaintTracking { - import codingstandards.cpp.dataflow.internal.tainttracking1.TaintTrackingParameter::Public - private import semmle.code.cpp.dataflow.internal.DataFlowImplSpecific - private import semmle.code.cpp.dataflow.internal.TaintTrackingImplSpecific - private import codeql.dataflow.TaintTracking - import TaintFlowMake - import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingImpl -} diff --git a/cpp/common/src/codingstandards/cpp/dataflow/internal/tainttracking1/TaintTrackingParameter.qll b/cpp/common/src/codingstandards/cpp/dataflow/internal/tainttracking1/TaintTrackingParameter.qll deleted file mode 100644 index 63e9c85e22..0000000000 --- a/cpp/common/src/codingstandards/cpp/dataflow/internal/tainttracking1/TaintTrackingParameter.qll +++ /dev/null @@ -1,6 +0,0 @@ -import semmle.code.cpp.dataflow.internal.TaintTrackingUtil as Public - -module Private { - import codingstandards.cpp.dataflow.DataFlow::DataFlow as DataFlow - import semmle.code.cpp.dataflow.internal.DataFlowImpl as DataFlowInternal -} diff --git a/cpp/common/src/codingstandards/cpp/deadcode/UnusedFunctions.qll b/cpp/common/src/codingstandards/cpp/deadcode/UnusedFunctions.qll index b01b80208e..fdd713b436 100644 --- a/cpp/common/src/codingstandards/cpp/deadcode/UnusedFunctions.qll +++ b/cpp/common/src/codingstandards/cpp/deadcode/UnusedFunctions.qll @@ -13,6 +13,7 @@ import cpp import codingstandards.cpp.DynamicCallGraph import codingstandards.cpp.EncapsulatingFunctions import codingstandards.cpp.FunctionEquivalence +import codingstandards.cpp.Class module UnusedFunctions { /** @@ -119,7 +120,12 @@ module UnusedFunctions { class UnusedFunction extends UsableFunction { UnusedFunction() { // This function, or an equivalent function, is not reachable from any entry point - not exists(EntryPoint ep | getAnEquivalentFunction(this) = ep.getAReachableFunction()) + not exists(EntryPoint ep | getAnEquivalentFunction(this) = ep.getAReachableFunction()) and + // and it is not a constexpr. Refer issue #646. + // The usages of constexpr is not well tracked and hence + // to avoid false positives, this is added. In case there is an improvement in + // handling constexpr in CodeQL, we can consider removing it. + not this.isConstexpr() } string getDeadCodeType() { @@ -128,4 +134,7 @@ module UnusedFunctions { else result = "never called." } } + + /** A `SpecialMemberFunction` which is an `UnusedFunction`. */ + class UnusedSplMemberFunction extends UnusedFunction, SpecialMemberFunction { } } diff --git a/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll b/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll new file mode 100644 index 0000000000..94ae16ec4f --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll @@ -0,0 +1,71 @@ +import cpp +import codingstandards.cpp.deadcode.UnusedVariables +import codingstandards.cpp.alertreporting.HoldsForAllCopies +import codingstandards.cpp.alertreporting.DeduplicateMacroResults + +/** + * An unused object definition is an object, meaning a place in memory, whose definition could be + * removed and the program would still compile. + * + * Technically, parameters may be considered objects, but they are covered by their own rule. + * Similarly, members of structs are an addressable place in memory, and may be considered objects. + * However, the member declaration is nothing but a layout offset, which is not an object. + * + * This therefore only reports variables (local or top level) which have a definition, and are + * unused. + */ +class UnusedObjectDefinition extends VariableDeclarationEntry { + UnusedObjectDefinition() { + ( + getVariable() instanceof BasePotentiallyUnusedLocalVariable + or + getVariable() instanceof BasePotentiallyUnusedGlobalOrNamespaceVariable + ) and + not exists(VariableAccess access | access.getTarget() = getVariable()) and + getVariable().getDefinition() = this + } + + /* Dead objects with these attributes are reported in the "strict" queries. */ + predicate hasAttrUnused() { + getVariable().getAnAttribute().hasName(["unused", "used", "maybe_unused", "cleanup"]) + } +} + +/* Configuration to use the `DedupMacroResults` module to reduce alert noise */ +module UnusedObjectDefinitionDedupeConfig implements + DeduplicateMacroConfigSig +{ + string describe(UnusedObjectDefinition def) { result = def.getName() } +} + +import DeduplicateMacroResults as DeduplicateUnusedMacroObjects + +/* Module config to use the `DeduplicateUnusedMacroObjects::Report` module */ +module ReportDeadObjectConfig implements MacroReportConfigSig { + bindingset[description] + string getMessageSameResultInAllExpansions(Macro m, string description) { + result = "Macro '" + m.getName() + "' defines unused object '" + description + "'." + } + + string getMessageVariedResultInAllExpansions(Macro m) { + result = + "Macro '" + m.getName() + + "' defines unused object with an invocation-dependent name, for example, '$@'." + } + + string getMessageResultInIsolatedExpansion(UnusedObjectDefinition unused) { + result = "Invocation of macro '$@' defines unused object '" + unused.getName() + "'." + } + + string getMessageNotInMacro(UnusedObjectDefinition unused, Locatable optLoc1, string optStr1) { + result = "Unused object '" + unused.getName() + "'." and + optLoc1 = unused and + optStr1 = "(ignored)" + } +} + +/* The object to report in queries of dead objects used in macros */ +class ReportDeadObject extends DeduplicateUnusedMacroObjects::Report::ReportResult +{ + predicate hasAttrUnused() { getAResultElement().hasAttrUnused() } +} diff --git a/cpp/common/src/codingstandards/cpp/deadcode/UnusedVariables.qll b/cpp/common/src/codingstandards/cpp/deadcode/UnusedVariables.qll index f4607d82cb..a7accd5252 100644 --- a/cpp/common/src/codingstandards/cpp/deadcode/UnusedVariables.qll +++ b/cpp/common/src/codingstandards/cpp/deadcode/UnusedVariables.qll @@ -36,11 +36,11 @@ predicate declarationHasSideEffects(Variable v) { v.getType() instanceof TemplateDependentType } -/** A `LocalVariable` which is a candidate for being unused. */ -class PotentiallyUnusedLocalVariable extends LocalVariable { - PotentiallyUnusedLocalVariable() { - // Ignore variables declared in macro expansions - not exists(DeclStmt ds | ds.getADeclaration() = this and ds.isInMacroExpansion()) and +/** + * A `LocalVariable` which is a candidate for being unused, and may or may not be defined in a macro. + */ +class BasePotentiallyUnusedLocalVariable extends LocalVariable { + BasePotentiallyUnusedLocalVariable() { // Ignore variables where initializing the variable has side effects not declarationHasSideEffects(this) and // TODO non POD types with initializers? Also, do something different with templates? exists(Function f | f = getFunction() | @@ -56,6 +56,16 @@ class PotentiallyUnusedLocalVariable extends LocalVariable { } } +/** + * A `LocalVariable` which is a candidate for being unused, and not defined in a macro. + */ +class PotentiallyUnusedLocalVariable extends BasePotentiallyUnusedLocalVariable { + PotentiallyUnusedLocalVariable() { + // Ignore variables declared in macro expansions + not exists(DeclStmt ds | ds.getADeclaration() = this and ds.isInMacroExpansion()) + } +} + /** Holds if `mf` is "defined" in this database. */ predicate isDefined(MemberFunction mf) { exists(MemberFunction definedMemberFunction | @@ -105,13 +115,11 @@ class PotentiallyUnusedMemberVariable extends MemberVariable { } } -/** A `GlobalOrNamespaceVariable` which is potentially unused. */ -class PotentiallyUnusedGlobalOrNamespaceVariable extends GlobalOrNamespaceVariable { - PotentiallyUnusedGlobalOrNamespaceVariable() { +/** A `GlobalOrNamespaceVariable` which is potentially unused and may or may not be defined in a macro */ +class BasePotentiallyUnusedGlobalOrNamespaceVariable extends GlobalOrNamespaceVariable { + BasePotentiallyUnusedGlobalOrNamespaceVariable() { // A non-defined variable may never be used hasDefinition() and - // Not declared in a macro expansion - not isInMacroExpansion() and // No side-effects from declaration not declarationHasSideEffects(this) and // exclude uninstantiated template members @@ -121,6 +129,17 @@ class PotentiallyUnusedGlobalOrNamespaceVariable extends GlobalOrNamespaceVariab } } +/** + * A `GlobalOrNamespaceVariable` which is potentially unused, and is not defined in a macro. + */ +class PotentiallyUnusedGlobalOrNamespaceVariable extends BasePotentiallyUnusedGlobalOrNamespaceVariable +{ + PotentiallyUnusedGlobalOrNamespaceVariable() { + // Not declared in a macro expansion + not isInMacroExpansion() + } +} + predicate isUnused(Variable variable) { not exists(variable.getAnAccess()) and variable.getInitializer().fromSource() @@ -150,3 +169,21 @@ predicate maybeACompileTimeTemplateArgument(Variable v) { ) ) } + +/** Gets the constant value of a constexpr/const variable. */ +string getConstExprValue(Variable v) { + result = v.getInitializer().getExpr().getValue() and + (v.isConst() or v.isConstexpr()) +} + +/** + * Counts uses of `Variable` v in a local array of size `n` + */ +int countUsesInLocalArraySize(Variable v) { + result = + count(ArrayType at, LocalVariable arrayVariable | + arrayVariable.getType().resolveTypedefs() = at and + v.(PotentiallyUnusedLocalVariable).getFunction() = arrayVariable.getFunction() and + at.getArraySize().toString() = getConstExprValue(v) + ) +} diff --git a/cpp/common/src/codingstandards/cpp/deadcode/UselessAssignments.qll b/cpp/common/src/codingstandards/cpp/deadcode/UselessAssignments.qll index 465b023f3f..031ad2aa7c 100644 --- a/cpp/common/src/codingstandards/cpp/deadcode/UselessAssignments.qll +++ b/cpp/common/src/codingstandards/cpp/deadcode/UselessAssignments.qll @@ -3,6 +3,7 @@ */ import cpp +import codingstandards.cpp.deadcode.UnusedVariables import codingstandards.cpp.enhancements.ControlFlowGraphEnhancements /** If a variable may escape from the local context */ @@ -47,7 +48,9 @@ class InterestingStackVariable extends StackVariable { // Ignore variables in uninstantiated templates not this.isFromUninstantiatedTemplate(_) and // Ignore compiler generated variables, such as those generated for range based for loops - not this.isCompilerGenerated() + not this.isCompilerGenerated() and + // Explicitly ignore (propagated) constants that may be used to define sizes of local arrays + not countUsesInLocalArraySize(this) > 0 } } diff --git a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll new file mode 100644 index 0000000000..00e02d5712 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll @@ -0,0 +1,428 @@ +/** + * A module for identifying in code markers in code that trigger deviations. + * + * This module supports two different code identifier markers: + * - A C/C++ attribute based syntax + * - A comment-based format + * + * The C/C++ attribute based syntax uses the following format: + * ``` + * [[codeql::_deviation("code-identifier")]] + * ``` + * The deviation will be applied to the selected program element, and any syntactically nested children of that program element. + * + * For the comment format the marker consists of a `code-identifier` with some optional annotations. A deviation will be applied to + * some range of lines in the file containing the comment based on the annotation. The supported marker annotation + * formats are: + * - `` - the deviation applies to results on the current line. + * - `codeql::_deviation()` - same as above. + * - `codeql::_deviation_next_line()` - this deviation applies to results on the next line. + * - `codeql::_deviation_begin()` - marks the beginning of a range of lines where the deviation applies. + * - `codeql::_deviation_end()` - marks the end of a range of lines where the deviation applies. + * + * The valid `code-identifier`s are specified in deviation records, which also specify the query whose results are + * suppressed by the deviation. + * + * For begin/end, we maintain a stack of begin markers. When we encounter an end marker, we pop the stack to determine + * the range of that begin/end marker. If the stack is empty, the end marker is considered unmatched and invalid. If + * the stack is non-empty at the end of the file, all the begin markers are considered unmatched and invalid. + * + * Begin/end markers are not valid across include boundaries, as the stack is not maintained across files. + */ + +import cpp +import Deviations +import codingstandards.cpp.Locations + +string supportedStandard() { result = ["misra", "autosar", "cert"] } + +/** + * Holds if the given comment contains the code identifier. + */ +bindingset[codeIdentifier] +private predicate commentMatches(Comment comment, string codeIdentifier) { + exists(string text | + comment instanceof CppStyleComment and + // strip the beginning slashes + text = comment.getContents().suffix(2).trim() + or + comment instanceof CStyleComment and + // strip both the beginning /* and the end */ the comment + exists(string text0 | + text0 = comment.getContents().suffix(2) and + text = text0.prefix(text0.length() - 2).trim() + ) and + // The /* */ comment must be a single-line comment + not text.matches("%\n%") + | + // Code identifier appears at the start of the comment (modulo whitespace) + text.prefix(codeIdentifier.length()) = codeIdentifier + or + // Code identifier appears at the end of the comment (modulo whitespace) + text.suffix(text.length() - codeIdentifier.length()) = codeIdentifier + ) +} + +/** + * A deviation marker in the code. + */ +abstract class CommentDeviationMarker extends Comment { + DeviationRecord record; + + /** + * Gets the deviation record associated with this deviation marker. + */ + DeviationRecord getRecord() { result = record } +} + +/** + * A deviation marker in a comment that is not a valid deviation marker. + */ +class InvalidCommentDeviationMarker extends Comment { + InvalidCommentDeviationMarker() { + not this instanceof CommentDeviationMarker and + commentMatches(this, "codeql::" + supportedStandard() + "_deviation") + } +} + +/** + * A deviation marker for a deviation that applies to the current line. + */ +class DeviationEndOfLineMarker extends CommentDeviationMarker { + DeviationEndOfLineMarker() { + commentMatches(this, + "codeql::" + supportedStandard() + "_deviation(" + record.getCodeIdentifier() + ")") + } +} + +/** + * A deviation marker for a deviation that applies to the next line. + */ +class DeviationNextLineMarker extends CommentDeviationMarker { + DeviationNextLineMarker() { + commentMatches(this, + "codeql::" + supportedStandard() + "_deviation_next_line(" + record.getCodeIdentifier() + ")") + } +} + +/** + * A deviation marker for a deviation that applies to a range of lines + */ +abstract class CommentDeviationRangeMarker extends CommentDeviationMarker { } + +/** + * A deviation marker for a deviation that begins on this line. + */ +class DeviationBegin extends CommentDeviationRangeMarker { + DeviationBegin() { + commentMatches(this, + "codeql::" + supportedStandard() + "_deviation_begin(" + record.getCodeIdentifier() + ")") + } +} + +/** + * A deviation marker for a deviation that ends on this line. + */ +class DeviationEnd extends CommentDeviationRangeMarker { + DeviationEnd() { + commentMatches(this, + "codeql::" + supportedStandard() + "_deviation_end(" + record.getCodeIdentifier() + ")") + } +} + +private predicate hasDeviationCommentFileOrdering( + DeviationRecord record, CommentDeviationRangeMarker comment, File file, int index +) { + comment = + rank[index](CommentDeviationRangeMarker c | + c.getRecord() = record and + file = c.getFile() + | + c order by c.getLocation().getStartLine(), c.getLocation().getStartColumn() + ) +} + +/** + * Calculate the stack of deviation begin markers related to the given deviation record, in the given file, + * at the given `markerRecordFileIndex` into the list of deviation markers for that record in that file. + */ +private BeginStack calculateBeginStack(DeviationRecord record, File file, int markerRecordFileIndex) { + // Stack is empty at the start + markerRecordFileIndex = 0 and + result = TEmptyBeginStack() and + // Only initialize when there is at least one such comment marker for this file and record + // pairing + exists(CommentDeviationRangeMarker marker | + marker.getRecord() = record and marker.getLocation().getFile() = file + ) + or + // Next token is begin, so push it to the stack + exists(DeviationBegin begin, BeginStack prev | + record = begin.getRecord() and + hasDeviationCommentFileOrdering(record, begin, file, markerRecordFileIndex) and + prev = calculateBeginStack(record, file, markerRecordFileIndex - 1) and + result = TConsBeginStack(begin, prev) + ) + or + // Next token is end + exists(DeviationEnd end, BeginStack prevStack | + record = end.getRecord() and + hasDeviationCommentFileOrdering(record, end, file, markerRecordFileIndex) and + prevStack = calculateBeginStack(record, file, markerRecordFileIndex - 1) + | + // There is, so pop the most recent begin off the stack + prevStack = TConsBeginStack(_, result) + or + // Error, no begin on the stack, ignore the end and continue + prevStack = TEmptyBeginStack() and + result = TEmptyBeginStack() + ) +} + +newtype TBeginStack = + TConsBeginStack(DeviationBegin begin, TBeginStack prev) { + exists(File file, int index | + hasDeviationCommentFileOrdering(begin.getRecord(), begin, file, index) and + prev = calculateBeginStack(begin.getRecord(), file, index - 1) + ) + } or + TEmptyBeginStack() + +/** + * A stack of begin markers that occur in the same file, referring to the same record. + */ +private class BeginStack extends TBeginStack { + /** Gets the top begin marker on the stack. */ + DeviationBegin peek() { this = TConsBeginStack(result, _) } + + string toString() { + exists(DeviationBegin begin, BeginStack prev | this = TConsBeginStack(begin, prev) | + result = "(" + begin + ", " + prev.toString() + ")" + ) + or + this = TEmptyBeginStack() and + result = "()" + } +} + +predicate isDeviationRangePaired(DeviationRecord record, DeviationBegin begin, DeviationEnd end) { + exists(File file, int index | + record = end.getRecord() and + hasDeviationCommentFileOrdering(record, end, file, index) and + begin = calculateBeginStack(record, file, index - 1).peek() + ) +} + +/** + * A standard attribute that either deviates a result. + */ +class DeviationAttribute extends StdAttribute { + DeviationRecord record; + + DeviationAttribute() { + this.hasQualifiedName("codeql", supportedStandard() + "_deviation") and + // Support multiple argument deviations + "\"" + record.getCodeIdentifier() + "\"" = this.getAnArgument().getValueText() + } + + DeviationRecord getADeviationRecord() { result = record } + + /** Gets the element to which this attribute was applied. */ + Element getPrimarySuppressedElement() { + result.(Type).getAnAttribute() = this + or + result.(Stmt).getAnAttribute() = this + or + result.(Variable).getAnAttribute() = this + or + result.(Function).getAnAttribute() = this + } + + pragma[nomagic] + Element getASuppressedElement() { + result = this.getPrimarySuppressedElement() + or + result.(Expr).getEnclosingStmt() = this.getASuppressedElement() + or + result.(Stmt).getParentStmt() = this.getASuppressedElement() + or + result.(Stmt).getEnclosingFunction() = this.getASuppressedElement() + or + result.(LocalVariable) = this.getASuppressedElement().(DeclStmt).getADeclaration() + or + result.(Function).getDeclaringType() = this.getASuppressedElement() + or + result.(Variable).getDeclaringType() = this.getASuppressedElement() + or + exists(LambdaExpression expr | + expr = this.getASuppressedElement() and + result = expr.getLambdaFunction() + ) + or + exists(Function f | + f = this.getASuppressedElement() and + // A suppression on the function should apply to the noexcept expression + result = f.getADeclarationEntry().getNoExceptExpr() + ) + } +} + +/** + * A deviation attribute that is not associated with any deviation record. + */ +class InvalidDeviationAttribute extends StdAttribute { + string unknownCodeIdentifier; + + InvalidDeviationAttribute() { + this.hasQualifiedName("codeql", supportedStandard() + "_deviation") and + "\"" + unknownCodeIdentifier + "\"" = this.getAnArgument().getValueText() and + not exists(DeviationRecord record | record.getCodeIdentifier() = unknownCodeIdentifier) + } + + string getAnUnknownCodeIdentifier() { result = unknownCodeIdentifier } +} + +newtype TCodeIndentifierDeviation = + TSingleLineDeviation(DeviationRecord record, Comment comment, string filepath, int suppressedLine) { + ( + commentMatches(comment, record.getCodeIdentifier()) or + comment.(DeviationEndOfLineMarker).getRecord() = record + ) and + comment.getLocation().hasLocationInfo(filepath, suppressedLine, _, _, _) + or + comment.(DeviationNextLineMarker).getRecord() = record and + comment.getLocation().hasLocationInfo(filepath, suppressedLine - 1, _, _, _) + } or + TMultiLineDeviation( + DeviationRecord record, DeviationBegin beginComment, DeviationEnd endComment, string filepath, + int suppressedStartLine, int suppressedStartColumn, int suppressedEndLine, + int suppressedEndColumn + ) { + isDeviationRangePaired(record, beginComment, endComment) and + beginComment + .getLocation() + .hasLocationInfo(filepath, suppressedStartLine, suppressedStartColumn, _, _) and + endComment.getLocation().hasLocationInfo(filepath, _, _, suppressedEndLine, suppressedEndColumn) + } or + TCodeIdentifierDeviation(DeviationRecord record, DeviationAttribute attribute) { + attribute.getADeviationRecord() = record + } + +class CodeIdentifierDeviation extends TCodeIndentifierDeviation { + /** The deviation record associated with the deviation comment. */ + DeviationRecord getADeviationRecord() { + this = TSingleLineDeviation(result, _, _, _) + or + this = TMultiLineDeviation(result, _, _, _, _, _, _, _) + or + this = TCodeIdentifierDeviation(result, _) + } + + /** + * Holds if the given element is matched by this code identifier deviation. + */ + bindingset[e] + pragma[inline_late] + predicate isElementMatching(Element e) { + exists(string filepath, int elementLocationStart, int elementLocationColumnStart | + e.getLocation() + .hasLocationInfo(filepath, elementLocationStart, elementLocationColumnStart, _, _) + | + exists(int suppressedLine | + this = TSingleLineDeviation(_, _, filepath, suppressedLine) and + suppressedLine = elementLocationStart + ) + or + exists( + int suppressedStartLine, int suppressedStartColumn, int suppressedEndLine, + int suppressedEndColumn + | + this = + TMultiLineDeviation(_, _, _, filepath, suppressedStartLine, suppressedStartColumn, + suppressedEndLine, suppressedEndColumn) and + ( + // Element starts on a line after the begin marker of the suppression + suppressedStartLine < elementLocationStart + or + // Element exists on the same line as the begin marker, and occurs after it + suppressedStartLine = elementLocationStart and + suppressedStartColumn < elementLocationColumnStart + ) and + ( + // Element starts on a line before the end marker of the suppression + suppressedEndLine > elementLocationStart + or + // Element exists on the same line as the end marker of the suppression, and occurs before it + suppressedEndLine = elementLocationStart and + elementLocationColumnStart < suppressedEndColumn + ) + ) + ) + or + exists(DeviationAttribute attribute | + this = TCodeIdentifierDeviation(_, attribute) and + attribute.getASuppressedElement() = e + ) + } + + /** + * Holds for the region matched by this code identifier deviation. + * + * Note: this is not the location of the marker itself. + */ + predicate hasLocationInfo( + string filepath, int suppressedLine, int suppressedColumn, int endline, int endcolumn + ) { + exists(Comment commentMarker | + this = TSingleLineDeviation(_, commentMarker, filepath, suppressedLine) and + suppressedColumn = 1 and + endline = suppressedLine + | + if commentMarker instanceof DeviationEndOfLineMarker + then endcolumn = commentMarker.(DeviationEndOfLineMarker).getLocation().getEndColumn() + else + // Find the last column for a location on the next line + endcolumn = getLastColumnNumber(filepath, suppressedLine) + ) + or + this = + TMultiLineDeviation(_, _, _, filepath, suppressedLine, suppressedColumn, endline, endcolumn) + or + exists(DeviationAttribute attribute | + this = TCodeIdentifierDeviation(_, attribute) and + attribute + .getPrimarySuppressedElement() + .getLocation() + .hasLocationInfo(filepath, suppressedLine, suppressedColumn, endline, endcolumn) + ) + } + + string toString() { + exists(string filepath | + exists(int suppressedLine | + this = TSingleLineDeviation(_, _, filepath, suppressedLine) and + result = + "Deviation of " + getADeviationRecord().getQuery() + " applied to " + filepath + " Line " + + suppressedLine + ) + or + exists( + int suppressedStartLine, int suppressedStartColumn, int suppressedEndLine, + int suppressedEndColumn + | + this = + TMultiLineDeviation(_, _, _, filepath, suppressedStartLine, suppressedStartColumn, + suppressedEndLine, suppressedEndColumn) and + result = + "Deviation of " + getADeviationRecord().getQuery() + " applied to " + filepath + " Line " + + suppressedStartLine + ":" + suppressedStartColumn + ":" + suppressedEndLine + ":" + + suppressedEndColumn + ) + ) + or + exists(DeviationAttribute attribute | + this = TCodeIdentifierDeviation(_, attribute) and + result = "Deviation of " + getADeviationRecord().getQuery() + " applied to " + attribute + ) + } +} diff --git a/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll b/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll index 4dfadd12eb..e8c030cdd4 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll @@ -8,6 +8,7 @@ import cpp import semmle.code.cpp.XML import codingstandards.cpp.exclusions.RuleMetadata import codingstandards.cpp.Config +import CodeIdentifierDeviation predicate applyDeviationsAtQueryLevel() { not exists(CodingStandardsReportDeviatedAlerts reportDeviatedResults | @@ -219,32 +220,8 @@ class DeviationRecord extends XmlElement { else result = getADeviationPermit().getCodeIdentifier() } - /** Gets a comment which starts or ends with the code identifier comment. */ - Comment getACodeIdentifierComment() { - exists(string text | - ( - result instanceof CppStyleComment and - // strip the beginning slashes - text = result.getContents().suffix(2).trim() - or - result instanceof CStyleComment and - // strip both the beginning /* and the end */ the comment - exists(string text0 | - text0 = result.getContents().suffix(2) and - text = text0.prefix(text0.length() - 2).trim() - ) and - // The /* */ comment must be a single-line comment - not text.matches("%\n%") - ) and - ( - // Code identifier appears at the start of the comment (modulo whitespace) - text.prefix(getCodeIdentifier().length()) = getCodeIdentifier() - or - // Code identifier appears at the end of the comment (modulo whitespace) - text.suffix(text.length() - getCodeIdentifier().length()) = getCodeIdentifier() - ) - ) - } + /** Gets a code identifier deviation in code which starts or ends with the code identifier comment. */ + CodeIdentifierDeviation getACodeIdentifierDeviation() { this = result.getADeviationRecord() } /** Gets the `rule-id` specified for this record, if any. */ private string getRawRuleId() { result = getAChild("rule-id").getTextValue() } @@ -363,25 +340,30 @@ class DeviationRecord extends XmlElement { result.getRelativePath() = getAChild("paths").getAChild("paths-entry").getTextValue() } + private string getADeviationPath0() { + if exists(getPathAContainer()) + then + // Use the path, which will be relative to this file, if specified + result = getPathAContainer().getRelativePath() + else ( + // Otherwise, if no code identifier was supplied, it applies to the parent container of the + // file itself + not exists(getCodeIdentifier()) and + result = this.getFile().getParentContainer().getRelativePath() + ) + } + /** Gets a path to which this deviation applies. */ string getADeviationPath() { - ( - if exists(getPathAContainer()) - then - // Use the path, which will be relative to this file, if specified - result = getPathAContainer().getRelativePath() - else ( - // Otherwise, if no code identifier was supplied, it applies to the parent container of the - // file itself - not exists(getCodeIdentifier()) and - result = this.getFile().getParentContainer().getRelativePath() - ) + exists(string res | + res = getADeviationPath0() and + if res = "" then result = "(root)" else result = res ) } cached predicate isDeviated(Query query, string deviationPath) { query = getQuery() and - deviationPath = getADeviationPath() + deviationPath = getADeviationPath0() } } diff --git a/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql b/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql index 9035b7d288..94f45c74b3 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql +++ b/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql @@ -7,29 +7,7 @@ import cpp import Deviations - -/** Holds if `lineNumber` is an indexed line number in file `f`. */ -private predicate isLineNumber(File f, int lineNumber) { - exists(Location l | l.getFile() = f | - l.getStartLine() = lineNumber - or - l.getEndLine() = lineNumber - ) -} - -/** Gets the last line number in `f`. */ -private int getLastLineNumber(File f) { result = max(int lineNumber | isLineNumber(f, lineNumber)) } - -/** Gets the last column number on the last line of `f`. */ -int getLastColumnNumber(File f) { - result = - max(Location l | - l.getFile() = f and - l.getEndLine() = getLastLineNumber(f) - | - l.getEndColumn() - ) -} +import codingstandards.cpp.Locations newtype TDeviationScope = TDeviationRecordFileScope(DeviationRecord dr, File file) { @@ -38,7 +16,9 @@ newtype TDeviationScope = file.getRelativePath().prefix(deviationPath.length()) = deviationPath ) } or - TDeviationRecordCommentScope(DeviationRecord dr, Comment c) { c = dr.getACodeIdentifierComment() } + TDeviationRecordCodeIdentiferDeviationScope(DeviationRecord dr, CodeIdentifierDeviation c) { + c = dr.getACodeIdentifierDeviation() + } /** A deviation scope. */ class DeviationScope extends TDeviationScope { @@ -69,10 +49,9 @@ class DeviationRecordFileScope extends DeviationScope, TDeviationRecordFileScope string filepath, int startline, int startcolumn, int endline, int endcolumn ) { // In an ideal world, we would produce a URL here that informed the AlertSuppression code that - // the whole file was suppressed. However, experimentation suggestions the alert suppression - // code only works with locations with lines and columns, so we generate a location that covers - // the whole "indexed" file, by finding the location indexed in the database with the latest - // line and column number. + // the whole file was suppressed. However, the alert suppression code only works with locations + // with lines and columns, so we generate a location that covers the whole "indexed" file, by + // finding the location indexed in the database with the latest line and column number. exists(File f | f = getFile() | f.getLocation().hasLocationInfo(filepath, _, _, _, _) and startline = 1 and @@ -91,10 +70,16 @@ class DeviationRecordFileScope extends DeviationScope, TDeviationRecordFileScope * A deviation scope derived from a comment corresponding to a "code-identifier" entry for a * `DeviationRecord`. */ -class DeviationRecordCommentScope extends DeviationScope, TDeviationRecordCommentScope { - private DeviationRecord getDeviationRecord() { this = TDeviationRecordCommentScope(result, _) } +class DeviationRecordCommentScope extends DeviationScope, + TDeviationRecordCodeIdentiferDeviationScope +{ + private DeviationRecord getDeviationRecord() { + this = TDeviationRecordCodeIdentiferDeviationScope(result, _) + } - private Comment getComment() { this = TDeviationRecordCommentScope(_, result) } + private CodeIdentifierDeviation getCodeIdentifierDeviation() { + this = TDeviationRecordCodeIdentiferDeviationScope(_, result) + } override Locatable getDeviationDefinitionLocation() { result = getDeviationRecord() } @@ -103,14 +88,11 @@ class DeviationRecordCommentScope extends DeviationScope, TDeviationRecordCommen override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { - getComment().getLocation().hasLocationInfo(filepath, startline, _, endline, endcolumn) and - startcolumn = 1 + getCodeIdentifierDeviation() + .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } - override string toString() { - result = - "Deviation of " + getDeviationRecord().getQuery() + " for comment " + getComment() + "." - } + override string toString() { result = getCodeIdentifierDeviation().toString() } } from DeviationScope deviationScope diff --git a/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.md b/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.md new file mode 100644 index 0000000000..364e1ae915 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.md @@ -0,0 +1,19 @@ +# Invalid deviation code identifier + +## Overview + +Invalid deviation markers in code have no effect on the results but may indicate confusion over which results will be suppressed. + +Deviation code markers are used to suppress CodeQL Coding Standards results, following the process specified in the "MISRA Compliance 2020" document. There are a range of different deviation markers, with specific syntactic requirements. If those syntactic requirements are not met, the marker is invalid and will not be applied, which is likely contrary to developer expectations. + +## Recommendation + +Ensure the following requirements are met: + + * All `codeql::_deviation_begin(..)` markers are paired with a matching `codeql::_deviation_end(..)` marker. + * All instances of `codeql::_deviation` in comments are correctly formatted comment markers, and reference a `code-identifier`s that is specified in a deviation record included in the analysis. + * All deviation attributes reference `code-identifier`s that are specified in a deviation record included in the analysis. + +## References + +* [MISRA Compliance 2020 document - Chapter 4.2 (page 12) - Deviations](https://www.misra.org.uk/app/uploads/2021/06/MISRA-Compliance-2020.pdf) \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.ql b/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.ql new file mode 100644 index 0000000000..87dafbba13 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.ql @@ -0,0 +1,41 @@ +/** + * @id cpp/coding-standards/invalid-deviation-code-identifiers + * @name Invalid deviation code identifiers + * @description Deviation code identifiers must be valid. + * @kind problem + * @problem.severity error + */ + +import cpp +import CodeIdentifierDeviation + +predicate deviationCodeIdentifierError(Element e, string message) { + exists(DeviationEnd end | + e = end and + not isDeviationRangePaired(_, _, end) and + message = "Deviation end block is unmatched." + ) + or + exists(DeviationBegin begin | + e = begin and + not isDeviationRangePaired(_, begin, _) and + message = "Deviation start block is unmatched." + ) + or + exists(InvalidDeviationAttribute b | + e = b and + message = + "Deviation attribute references unknown code identifier " + b.getAnUnknownCodeIdentifier() + + "." + ) + or + exists(InvalidCommentDeviationMarker m | + e = m and + message = + "Deviation marker does not match an expected format, or references an unknown code identifier." + ) +} + +from Element e, string message +where deviationCodeIdentifierError(e, message) +select e, message diff --git a/cpp/common/src/codingstandards/cpp/dominance/BehavioralSet.qll b/cpp/common/src/codingstandards/cpp/dominance/BehavioralSet.qll new file mode 100644 index 0000000000..8609e3213b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/dominance/BehavioralSet.qll @@ -0,0 +1,40 @@ +import cpp +import semmle.code.cpp.controlflow.ControlFlowGraph + +signature class TargetNode extends ControlFlowNode; + +signature module DominatingSetConfigSig { + predicate isTargetBehavior(ControlFlowNode behavior, Target target); + + default predicate isBlockingBehavior(ControlFlowNode behavior, Target target) { none() } +} + +/** + * A module to find whether there exists a dominator set for a node which performs a relevant + * behavior. + * + * For instance, we may wish to see that all paths leading to an `abort()` statement include a + * logging call. In this case, the `abort()` statement is the `Target` node, and the config module + * predicate `isTargetBehavior` logging statements. + * + * Additionally, the config may specify `isBlockingBehavior` to prevent searching too far for the + * relevant behavior. For instance, if analyzing that all paths to an `fflush()` call are preceded + * by a write, we should ignore paths from write operations that have already been flushed through + * an intermediary `fflush()` call. + */ +module DominatingBehavioralSet Config> { + /** + * Holds if this search step can reach the entry or a blocking node, without passing through a + * target behavior, indicating that the target is has no relevant dominator set. + */ + private predicate searchStep(ControlFlowNode node, Target target) { + Config::isBlockingBehavior(node, target) + or + not Config::isTargetBehavior(node, target) and + exists(ControlFlowNode prev | prev = node.getAPredecessor() | searchStep(prev, target)) + } + + predicate isDominatedByBehavior(Target target) { + forex(ControlFlowNode prev | prev = target.getAPredecessor() | not searchStep(prev, target)) + } +} diff --git a/cpp/common/src/codingstandards/cpp/enhancements/ControlFlowGraphEnhancements.qll b/cpp/common/src/codingstandards/cpp/enhancements/ControlFlowGraphEnhancements.qll index 74d7e8e1c1..9dac58377c 100644 --- a/cpp/common/src/codingstandards/cpp/enhancements/ControlFlowGraphEnhancements.qll +++ b/cpp/common/src/codingstandards/cpp/enhancements/ControlFlowGraphEnhancements.qll @@ -10,8 +10,8 @@ import cpp * should be in this relation. */ pragma[noinline] -private predicate isFunction(Element el) { - el instanceof Function +private predicate isFunction(@element el) { + el instanceof @function or el.(Expr).getParent() = el } @@ -22,7 +22,7 @@ private predicate isFunction(Element el) { */ pragma[noopt] private predicate callHasNoTarget(@funbindexpr fc) { - exists(Function f | + exists(@function f | funbind(fc, f) and not isFunction(f) ) diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Alignment.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Alignment.qll new file mode 100644 index 0000000000..9447abf636 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Alignment.qll @@ -0,0 +1,78 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype AlignmentQuery = + TRedeclarationOfObjectWithoutAlignmentQuery() or + TRedeclarationOfObjectWithUnmatchedAlignmentQuery() or + TAlignmentWithSizeZeroQuery() or + TMoreThanOneAlignmentSpecifierOnDeclarationQuery() + +predicate isAlignmentQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `redeclarationOfObjectWithoutAlignment` query + AlignmentPackage::redeclarationOfObjectWithoutAlignmentQuery() and + queryId = + // `@id` for the `redeclarationOfObjectWithoutAlignment` query + "c/misra/redeclaration-of-object-without-alignment" and + ruleId = "RULE-8-15" and + category = "required" + or + query = + // `Query` instance for the `redeclarationOfObjectWithUnmatchedAlignment` query + AlignmentPackage::redeclarationOfObjectWithUnmatchedAlignmentQuery() and + queryId = + // `@id` for the `redeclarationOfObjectWithUnmatchedAlignment` query + "c/misra/redeclaration-of-object-with-unmatched-alignment" and + ruleId = "RULE-8-15" and + category = "required" + or + query = + // `Query` instance for the `alignmentWithSizeZero` query + AlignmentPackage::alignmentWithSizeZeroQuery() and + queryId = + // `@id` for the `alignmentWithSizeZero` query + "c/misra/alignment-with-size-zero" and + ruleId = "RULE-8-16" and + category = "advisory" + or + query = + // `Query` instance for the `moreThanOneAlignmentSpecifierOnDeclaration` query + AlignmentPackage::moreThanOneAlignmentSpecifierOnDeclarationQuery() and + queryId = + // `@id` for the `moreThanOneAlignmentSpecifierOnDeclaration` query + "c/misra/more-than-one-alignment-specifier-on-declaration" and + ruleId = "RULE-8-17" and + category = "advisory" +} + +module AlignmentPackage { + Query redeclarationOfObjectWithoutAlignmentQuery() { + //autogenerate `Query` type + result = + // `Query` type for `redeclarationOfObjectWithoutAlignment` query + TQueryC(TAlignmentPackageQuery(TRedeclarationOfObjectWithoutAlignmentQuery())) + } + + Query redeclarationOfObjectWithUnmatchedAlignmentQuery() { + //autogenerate `Query` type + result = + // `Query` type for `redeclarationOfObjectWithUnmatchedAlignment` query + TQueryC(TAlignmentPackageQuery(TRedeclarationOfObjectWithUnmatchedAlignmentQuery())) + } + + Query alignmentWithSizeZeroQuery() { + //autogenerate `Query` type + result = + // `Query` type for `alignmentWithSizeZero` query + TQueryC(TAlignmentPackageQuery(TAlignmentWithSizeZeroQuery())) + } + + Query moreThanOneAlignmentSpecifierOnDeclarationQuery() { + //autogenerate `Query` type + result = + // `Query` type for `moreThanOneAlignmentSpecifierOnDeclaration` query + TQueryC(TAlignmentPackageQuery(TMoreThanOneAlignmentSpecifierOnDeclarationQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Banned.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Banned.qll index 888e0863a3..f8a4e027bb 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/Banned.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Banned.qll @@ -77,7 +77,7 @@ predicate isBannedQueryMetadata(Query query, string queryId, string ruleId, stri // `@id` for the `standardHeaderFileTgmathhUsed` query "c/misra/standard-header-file-tgmathh-used" and ruleId = "RULE-21-11" and - category = "required" + category = "advisory" or query = // `Query` instance for the `exceptionHandlingFeaturesOfFenvhUsed` query diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Banned2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Banned2.qll new file mode 100644 index 0000000000..024aa9b76c --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Banned2.qll @@ -0,0 +1,26 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Banned2Query = TCallToBannedRandomFunctionQuery() + +predicate isBanned2QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `callToBannedRandomFunction` query + Banned2Package::callToBannedRandomFunctionQuery() and + queryId = + // `@id` for the `callToBannedRandomFunction` query + "c/misra/call-to-banned-random-function" and + ruleId = "RULE-21-24" and + category = "required" +} + +module Banned2Package { + Query callToBannedRandomFunctionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `callToBannedRandomFunction` query + TQueryC(TBanned2PackageQuery(TCallToBannedRandomFunctionQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/BitfieldTypes2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/BitfieldTypes2.qll new file mode 100644 index 0000000000..ca116bb51c --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/BitfieldTypes2.qll @@ -0,0 +1,26 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype BitfieldTypes2Query = TBitFieldDeclaredAsMemberOfAUnionQuery() + +predicate isBitfieldTypes2QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `bitFieldDeclaredAsMemberOfAUnion` query + BitfieldTypes2Package::bitFieldDeclaredAsMemberOfAUnionQuery() and + queryId = + // `@id` for the `bitFieldDeclaredAsMemberOfAUnion` query + "c/misra/bit-field-declared-as-member-of-a-union" and + ruleId = "RULE-6-3" and + category = "required" +} + +module BitfieldTypes2Package { + Query bitFieldDeclaredAsMemberOfAUnionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `bitFieldDeclaredAsMemberOfAUnion` query + TQueryC(TBitfieldTypes2PackageQuery(TBitFieldDeclaredAsMemberOfAUnionQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency6.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency6.qll new file mode 100644 index 0000000000..62d9f362fe --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency6.qll @@ -0,0 +1,112 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Concurrency6Query = + TNotNoDeadlocksBetweenThreadsQuery() or + TThreadCreatedByThreadQuery() or + TBannedDynamicThreadCreationQuery() or + TAtomicAggregateObjectDirectlyAccessedQuery() or + TInvalidMemoryOrderArgumentQuery() or + TThreadPreviouslyJoinedOrDetachedQuery() + +predicate isConcurrency6QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `notNoDeadlocksBetweenThreads` query + Concurrency6Package::notNoDeadlocksBetweenThreadsQuery() and + queryId = + // `@id` for the `notNoDeadlocksBetweenThreads` query + "c/misra/not-no-deadlocks-between-threads" and + ruleId = "DIR-5-2" and + category = "required" + or + query = + // `Query` instance for the `threadCreatedByThread` query + Concurrency6Package::threadCreatedByThreadQuery() and + queryId = + // `@id` for the `threadCreatedByThread` query + "c/misra/thread-created-by-thread" and + ruleId = "DIR-5-3" and + category = "required" + or + query = + // `Query` instance for the `bannedDynamicThreadCreation` query + Concurrency6Package::bannedDynamicThreadCreationQuery() and + queryId = + // `@id` for the `bannedDynamicThreadCreation` query + "c/misra/banned-dynamic-thread-creation" and + ruleId = "DIR-5-3" and + category = "required" + or + query = + // `Query` instance for the `atomicAggregateObjectDirectlyAccessed` query + Concurrency6Package::atomicAggregateObjectDirectlyAccessedQuery() and + queryId = + // `@id` for the `atomicAggregateObjectDirectlyAccessed` query + "c/misra/atomic-aggregate-object-directly-accessed" and + ruleId = "RULE-12-6" and + category = "required" + or + query = + // `Query` instance for the `invalidMemoryOrderArgument` query + Concurrency6Package::invalidMemoryOrderArgumentQuery() and + queryId = + // `@id` for the `invalidMemoryOrderArgument` query + "c/misra/invalid-memory-order-argument" and + ruleId = "RULE-21-25" and + category = "required" + or + query = + // `Query` instance for the `threadPreviouslyJoinedOrDetached` query + Concurrency6Package::threadPreviouslyJoinedOrDetachedQuery() and + queryId = + // `@id` for the `threadPreviouslyJoinedOrDetached` query + "c/misra/thread-previously-joined-or-detached" and + ruleId = "RULE-22-11" and + category = "required" +} + +module Concurrency6Package { + Query notNoDeadlocksBetweenThreadsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `notNoDeadlocksBetweenThreads` query + TQueryC(TConcurrency6PackageQuery(TNotNoDeadlocksBetweenThreadsQuery())) + } + + Query threadCreatedByThreadQuery() { + //autogenerate `Query` type + result = + // `Query` type for `threadCreatedByThread` query + TQueryC(TConcurrency6PackageQuery(TThreadCreatedByThreadQuery())) + } + + Query bannedDynamicThreadCreationQuery() { + //autogenerate `Query` type + result = + // `Query` type for `bannedDynamicThreadCreation` query + TQueryC(TConcurrency6PackageQuery(TBannedDynamicThreadCreationQuery())) + } + + Query atomicAggregateObjectDirectlyAccessedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `atomicAggregateObjectDirectlyAccessed` query + TQueryC(TConcurrency6PackageQuery(TAtomicAggregateObjectDirectlyAccessedQuery())) + } + + Query invalidMemoryOrderArgumentQuery() { + //autogenerate `Query` type + result = + // `Query` type for `invalidMemoryOrderArgument` query + TQueryC(TConcurrency6PackageQuery(TInvalidMemoryOrderArgumentQuery())) + } + + Query threadPreviouslyJoinedOrDetachedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `threadPreviouslyJoinedOrDetached` query + TQueryC(TConcurrency6PackageQuery(TThreadPreviouslyJoinedOrDetachedQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency7.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency7.qll new file mode 100644 index 0000000000..ba492b2a6b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency7.qll @@ -0,0 +1,44 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Concurrency7Query = + TUninitializedAtomicObjectQuery() or + TTimedlockOnInappropriateMutexTypeQuery() + +predicate isConcurrency7QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `uninitializedAtomicObject` query + Concurrency7Package::uninitializedAtomicObjectQuery() and + queryId = + // `@id` for the `uninitializedAtomicObject` query + "c/misra/uninitialized-atomic-object" and + ruleId = "RULE-9-7" and + category = "mandatory" + or + query = + // `Query` instance for the `timedlockOnInappropriateMutexType` query + Concurrency7Package::timedlockOnInappropriateMutexTypeQuery() and + queryId = + // `@id` for the `timedlockOnInappropriateMutexType` query + "c/misra/timedlock-on-inappropriate-mutex-type" and + ruleId = "RULE-21-26" and + category = "required" +} + +module Concurrency7Package { + Query uninitializedAtomicObjectQuery() { + //autogenerate `Query` type + result = + // `Query` type for `uninitializedAtomicObject` query + TQueryC(TConcurrency7PackageQuery(TUninitializedAtomicObjectQuery())) + } + + Query timedlockOnInappropriateMutexTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `timedlockOnInappropriateMutexType` query + TQueryC(TConcurrency7PackageQuery(TTimedlockOnInappropriateMutexTypeQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency8.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency8.qll new file mode 100644 index 0000000000..677b35d12b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency8.qll @@ -0,0 +1,112 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Concurrency8Query = + TNonstandardUseOfThreadingObjectQuery() or + TThreadingObjectWithInvalidStorageDurationQuery() or + TMutexNotInitializedBeforeUseQuery() or + TMutexInitializedInsideThreadQuery() or + TMutexInitWithInvalidMutexTypeQuery() or + TMutexObjectsNotAlwaysUnlockedQuery() + +predicate isConcurrency8QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `nonstandardUseOfThreadingObject` query + Concurrency8Package::nonstandardUseOfThreadingObjectQuery() and + queryId = + // `@id` for the `nonstandardUseOfThreadingObject` query + "c/misra/nonstandard-use-of-threading-object" and + ruleId = "RULE-22-12" and + category = "mandatory" + or + query = + // `Query` instance for the `threadingObjectWithInvalidStorageDuration` query + Concurrency8Package::threadingObjectWithInvalidStorageDurationQuery() and + queryId = + // `@id` for the `threadingObjectWithInvalidStorageDuration` query + "c/misra/threading-object-with-invalid-storage-duration" and + ruleId = "RULE-22-13" and + category = "required" + or + query = + // `Query` instance for the `mutexNotInitializedBeforeUse` query + Concurrency8Package::mutexNotInitializedBeforeUseQuery() and + queryId = + // `@id` for the `mutexNotInitializedBeforeUse` query + "c/misra/mutex-not-initialized-before-use" and + ruleId = "RULE-22-14" and + category = "mandatory" + or + query = + // `Query` instance for the `mutexInitializedInsideThread` query + Concurrency8Package::mutexInitializedInsideThreadQuery() and + queryId = + // `@id` for the `mutexInitializedInsideThread` query + "c/misra/mutex-initialized-inside-thread" and + ruleId = "RULE-22-14" and + category = "mandatory" + or + query = + // `Query` instance for the `mutexInitWithInvalidMutexType` query + Concurrency8Package::mutexInitWithInvalidMutexTypeQuery() and + queryId = + // `@id` for the `mutexInitWithInvalidMutexType` query + "c/misra/mutex-init-with-invalid-mutex-type" and + ruleId = "RULE-22-14" and + category = "mandatory" + or + query = + // `Query` instance for the `mutexObjectsNotAlwaysUnlocked` query + Concurrency8Package::mutexObjectsNotAlwaysUnlockedQuery() and + queryId = + // `@id` for the `mutexObjectsNotAlwaysUnlocked` query + "c/misra/mutex-objects-not-always-unlocked" and + ruleId = "RULE-22-16" and + category = "required" +} + +module Concurrency8Package { + Query nonstandardUseOfThreadingObjectQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nonstandardUseOfThreadingObject` query + TQueryC(TConcurrency8PackageQuery(TNonstandardUseOfThreadingObjectQuery())) + } + + Query threadingObjectWithInvalidStorageDurationQuery() { + //autogenerate `Query` type + result = + // `Query` type for `threadingObjectWithInvalidStorageDuration` query + TQueryC(TConcurrency8PackageQuery(TThreadingObjectWithInvalidStorageDurationQuery())) + } + + Query mutexNotInitializedBeforeUseQuery() { + //autogenerate `Query` type + result = + // `Query` type for `mutexNotInitializedBeforeUse` query + TQueryC(TConcurrency8PackageQuery(TMutexNotInitializedBeforeUseQuery())) + } + + Query mutexInitializedInsideThreadQuery() { + //autogenerate `Query` type + result = + // `Query` type for `mutexInitializedInsideThread` query + TQueryC(TConcurrency8PackageQuery(TMutexInitializedInsideThreadQuery())) + } + + Query mutexInitWithInvalidMutexTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `mutexInitWithInvalidMutexType` query + TQueryC(TConcurrency8PackageQuery(TMutexInitWithInvalidMutexTypeQuery())) + } + + Query mutexObjectsNotAlwaysUnlockedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `mutexObjectsNotAlwaysUnlocked` query + TQueryC(TConcurrency8PackageQuery(TMutexObjectsNotAlwaysUnlockedQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency9.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency9.qll new file mode 100644 index 0000000000..b013bbdabb --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency9.qll @@ -0,0 +1,146 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Concurrency9Query = + TPossibleDataRaceBetweenThreadsQuery() or + TThreadResourceDisposedBeforeThreadsJoinedQuery() or + TInvalidOperationOnUnlockedMutexQuery() or + TNonRecursiveMutexRecursivelyLockedQuery() or + TNonRecursiveMutexRecursivelyLockedAuditQuery() or + TConditionVariableUsedWithMultipleMutexesQuery() or + TThreadStorageNotInitializedBeforeUseQuery() or + TThreadStoragePointerInitializedInsideThreadQuery() + +predicate isConcurrency9QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `possibleDataRaceBetweenThreads` query + Concurrency9Package::possibleDataRaceBetweenThreadsQuery() and + queryId = + // `@id` for the `possibleDataRaceBetweenThreads` query + "c/misra/possible-data-race-between-threads" and + ruleId = "DIR-5-1" and + category = "required" + or + query = + // `Query` instance for the `threadResourceDisposedBeforeThreadsJoined` query + Concurrency9Package::threadResourceDisposedBeforeThreadsJoinedQuery() and + queryId = + // `@id` for the `threadResourceDisposedBeforeThreadsJoined` query + "c/misra/thread-resource-disposed-before-threads-joined" and + ruleId = "RULE-22-15" and + category = "required" + or + query = + // `Query` instance for the `invalidOperationOnUnlockedMutex` query + Concurrency9Package::invalidOperationOnUnlockedMutexQuery() and + queryId = + // `@id` for the `invalidOperationOnUnlockedMutex` query + "c/misra/invalid-operation-on-unlocked-mutex" and + ruleId = "RULE-22-17" and + category = "required" + or + query = + // `Query` instance for the `nonRecursiveMutexRecursivelyLocked` query + Concurrency9Package::nonRecursiveMutexRecursivelyLockedQuery() and + queryId = + // `@id` for the `nonRecursiveMutexRecursivelyLocked` query + "c/misra/non-recursive-mutex-recursively-locked" and + ruleId = "RULE-22-18" and + category = "required" + or + query = + // `Query` instance for the `nonRecursiveMutexRecursivelyLockedAudit` query + Concurrency9Package::nonRecursiveMutexRecursivelyLockedAuditQuery() and + queryId = + // `@id` for the `nonRecursiveMutexRecursivelyLockedAudit` query + "c/misra/non-recursive-mutex-recursively-locked-audit" and + ruleId = "RULE-22-18" and + category = "required" + or + query = + // `Query` instance for the `conditionVariableUsedWithMultipleMutexes` query + Concurrency9Package::conditionVariableUsedWithMultipleMutexesQuery() and + queryId = + // `@id` for the `conditionVariableUsedWithMultipleMutexes` query + "c/misra/condition-variable-used-with-multiple-mutexes" and + ruleId = "RULE-22-19" and + category = "required" + or + query = + // `Query` instance for the `threadStorageNotInitializedBeforeUse` query + Concurrency9Package::threadStorageNotInitializedBeforeUseQuery() and + queryId = + // `@id` for the `threadStorageNotInitializedBeforeUse` query + "c/misra/thread-storage-not-initialized-before-use" and + ruleId = "RULE-22-20" and + category = "mandatory" + or + query = + // `Query` instance for the `threadStoragePointerInitializedInsideThread` query + Concurrency9Package::threadStoragePointerInitializedInsideThreadQuery() and + queryId = + // `@id` for the `threadStoragePointerInitializedInsideThread` query + "c/misra/thread-storage-pointer-initialized-inside-thread" and + ruleId = "RULE-22-20" and + category = "mandatory" +} + +module Concurrency9Package { + Query possibleDataRaceBetweenThreadsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `possibleDataRaceBetweenThreads` query + TQueryC(TConcurrency9PackageQuery(TPossibleDataRaceBetweenThreadsQuery())) + } + + Query threadResourceDisposedBeforeThreadsJoinedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `threadResourceDisposedBeforeThreadsJoined` query + TQueryC(TConcurrency9PackageQuery(TThreadResourceDisposedBeforeThreadsJoinedQuery())) + } + + Query invalidOperationOnUnlockedMutexQuery() { + //autogenerate `Query` type + result = + // `Query` type for `invalidOperationOnUnlockedMutex` query + TQueryC(TConcurrency9PackageQuery(TInvalidOperationOnUnlockedMutexQuery())) + } + + Query nonRecursiveMutexRecursivelyLockedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nonRecursiveMutexRecursivelyLocked` query + TQueryC(TConcurrency9PackageQuery(TNonRecursiveMutexRecursivelyLockedQuery())) + } + + Query nonRecursiveMutexRecursivelyLockedAuditQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nonRecursiveMutexRecursivelyLockedAudit` query + TQueryC(TConcurrency9PackageQuery(TNonRecursiveMutexRecursivelyLockedAuditQuery())) + } + + Query conditionVariableUsedWithMultipleMutexesQuery() { + //autogenerate `Query` type + result = + // `Query` type for `conditionVariableUsedWithMultipleMutexes` query + TQueryC(TConcurrency9PackageQuery(TConditionVariableUsedWithMultipleMutexesQuery())) + } + + Query threadStorageNotInitializedBeforeUseQuery() { + //autogenerate `Query` type + result = + // `Query` type for `threadStorageNotInitializedBeforeUse` query + TQueryC(TConcurrency9PackageQuery(TThreadStorageNotInitializedBeforeUseQuery())) + } + + Query threadStoragePointerInitializedInsideThreadQuery() { + //autogenerate `Query` type + result = + // `Query` type for `threadStoragePointerInitializedInsideThread` query + TQueryC(TConcurrency9PackageQuery(TThreadStoragePointerInitializedInsideThreadQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts.qll new file mode 100644 index 0000000000..174e7769b7 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts.qll @@ -0,0 +1,78 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype ContractsQuery = + TDoNotViolateInLineLinkageConstraintsQuery() or + TCheckMathLibraryFunctionParametersQuery() or + TLowPrecisionPeriodicTrigonometricFunctionCallQuery() or + TFunctionErrorInformationUntestedQuery() + +predicate isContractsQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `doNotViolateInLineLinkageConstraints` query + ContractsPackage::doNotViolateInLineLinkageConstraintsQuery() and + queryId = + // `@id` for the `doNotViolateInLineLinkageConstraints` query + "c/cert/do-not-violate-in-line-linkage-constraints" and + ruleId = "MSC40-C" and + category = "rule" + or + query = + // `Query` instance for the `checkMathLibraryFunctionParameters` query + ContractsPackage::checkMathLibraryFunctionParametersQuery() and + queryId = + // `@id` for the `checkMathLibraryFunctionParameters` query + "c/misra/check-math-library-function-parameters" and + ruleId = "DIR-4-11" and + category = "required" + or + query = + // `Query` instance for the `lowPrecisionPeriodicTrigonometricFunctionCall` query + ContractsPackage::lowPrecisionPeriodicTrigonometricFunctionCallQuery() and + queryId = + // `@id` for the `lowPrecisionPeriodicTrigonometricFunctionCall` query + "c/misra/low-precision-periodic-trigonometric-function-call" and + ruleId = "DIR-4-11" and + category = "required" + or + query = + // `Query` instance for the `functionErrorInformationUntested` query + ContractsPackage::functionErrorInformationUntestedQuery() and + queryId = + // `@id` for the `functionErrorInformationUntested` query + "c/misra/function-error-information-untested" and + ruleId = "DIR-4-7" and + category = "required" +} + +module ContractsPackage { + Query doNotViolateInLineLinkageConstraintsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `doNotViolateInLineLinkageConstraints` query + TQueryC(TContractsPackageQuery(TDoNotViolateInLineLinkageConstraintsQuery())) + } + + Query checkMathLibraryFunctionParametersQuery() { + //autogenerate `Query` type + result = + // `Query` type for `checkMathLibraryFunctionParameters` query + TQueryC(TContractsPackageQuery(TCheckMathLibraryFunctionParametersQuery())) + } + + Query lowPrecisionPeriodicTrigonometricFunctionCallQuery() { + //autogenerate `Query` type + result = + // `Query` type for `lowPrecisionPeriodicTrigonometricFunctionCall` query + TQueryC(TContractsPackageQuery(TLowPrecisionPeriodicTrigonometricFunctionCallQuery())) + } + + Query functionErrorInformationUntestedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `functionErrorInformationUntested` query + TQueryC(TContractsPackageQuery(TFunctionErrorInformationUntestedQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts6.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts6.qll index bd897bd79f..eed78ae507 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts6.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts6.qll @@ -25,7 +25,7 @@ predicate isContracts6QueryMetadata(Query query, string queryId, string ruleId, // `@id` for the `arrayFunctionArgumentNumberOfElements` query "c/misra/array-function-argument-number-of-elements" and ruleId = "RULE-17-5" and - category = "advisory" + category = "required" or query = // `Query` instance for the `valueReturnedByAFunctionNotUsed` query diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/DeadCode2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/DeadCode2.qll new file mode 100644 index 0000000000..611062a5ac --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/DeadCode2.qll @@ -0,0 +1,44 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype DeadCode2Query = + TUnusedObjectDefinitionQuery() or + TUnusedObjectDefinitionStrictQuery() + +predicate isDeadCode2QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `unusedObjectDefinition` query + DeadCode2Package::unusedObjectDefinitionQuery() and + queryId = + // `@id` for the `unusedObjectDefinition` query + "c/misra/unused-object-definition" and + ruleId = "RULE-2-8" and + category = "advisory" + or + query = + // `Query` instance for the `unusedObjectDefinitionStrict` query + DeadCode2Package::unusedObjectDefinitionStrictQuery() and + queryId = + // `@id` for the `unusedObjectDefinitionStrict` query + "c/misra/unused-object-definition-strict" and + ruleId = "RULE-2-8" and + category = "advisory" +} + +module DeadCode2Package { + Query unusedObjectDefinitionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unusedObjectDefinition` query + TQueryC(TDeadCode2PackageQuery(TUnusedObjectDefinitionQuery())) + } + + Query unusedObjectDefinitionStrictQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unusedObjectDefinitionStrict` query + TQueryC(TDeadCode2PackageQuery(TUnusedObjectDefinitionStrictQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations9.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations9.qll new file mode 100644 index 0000000000..8a63e50ed4 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations9.qll @@ -0,0 +1,26 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Declarations9Query = TAtomicQualifierAppliedToVoidQuery() + +predicate isDeclarations9QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `atomicQualifierAppliedToVoid` query + Declarations9Package::atomicQualifierAppliedToVoidQuery() and + queryId = + // `@id` for the `atomicQualifierAppliedToVoid` query + "c/misra/atomic-qualifier-applied-to-void" and + ruleId = "RULE-11-10" and + category = "required" +} + +module Declarations9Package { + Query atomicQualifierAppliedToVoidQuery() { + //autogenerate `Query` type + result = + // `Query` type for `atomicQualifierAppliedToVoid` query + TQueryC(TDeclarations9PackageQuery(TAtomicQualifierAppliedToVoidQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/EssentialTypes2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/EssentialTypes2.qll new file mode 100644 index 0000000000..e1dd8d5636 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/EssentialTypes2.qll @@ -0,0 +1,44 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype EssentialTypes2Query = + TTgMathArgumentWithInvalidEssentialTypeQuery() or + TTgMathArgumentsWithDifferingStandardTypeQuery() + +predicate isEssentialTypes2QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `tgMathArgumentWithInvalidEssentialType` query + EssentialTypes2Package::tgMathArgumentWithInvalidEssentialTypeQuery() and + queryId = + // `@id` for the `tgMathArgumentWithInvalidEssentialType` query + "c/misra/tg-math-argument-with-invalid-essential-type" and + ruleId = "RULE-21-22" and + category = "mandatory" + or + query = + // `Query` instance for the `tgMathArgumentsWithDifferingStandardType` query + EssentialTypes2Package::tgMathArgumentsWithDifferingStandardTypeQuery() and + queryId = + // `@id` for the `tgMathArgumentsWithDifferingStandardType` query + "c/misra/tg-math-arguments-with-differing-standard-type" and + ruleId = "RULE-21-23" and + category = "required" +} + +module EssentialTypes2Package { + Query tgMathArgumentWithInvalidEssentialTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `tgMathArgumentWithInvalidEssentialType` query + TQueryC(TEssentialTypes2PackageQuery(TTgMathArgumentWithInvalidEssentialTypeQuery())) + } + + Query tgMathArgumentsWithDifferingStandardTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `tgMathArgumentsWithDifferingStandardType` query + TQueryC(TEssentialTypes2PackageQuery(TTgMathArgumentsWithDifferingStandardTypeQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Expressions2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Expressions2.qll new file mode 100644 index 0000000000..e7dffc30bb --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Expressions2.qll @@ -0,0 +1,26 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Expressions2Query = TDoNotCompareFunctionPointersToConstantValuesQuery() + +predicate isExpressions2QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `doNotCompareFunctionPointersToConstantValues` query + Expressions2Package::doNotCompareFunctionPointersToConstantValuesQuery() and + queryId = + // `@id` for the `doNotCompareFunctionPointersToConstantValues` query + "c/cert/do-not-compare-function-pointers-to-constant-values" and + ruleId = "EXP16-C" and + category = "recommendation" +} + +module Expressions2Package { + Query doNotCompareFunctionPointersToConstantValuesQuery() { + //autogenerate `Query` type + result = + // `Query` type for `doNotCompareFunctionPointersToConstantValues` query + TQueryC(TExpressions2PackageQuery(TDoNotCompareFunctionPointersToConstantValuesQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/FloatingTypes2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/FloatingTypes2.qll new file mode 100644 index 0000000000..0dbc6cc22d --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/FloatingTypes2.qll @@ -0,0 +1,44 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype FloatingTypes2Query = + TPossibleMisuseOfUndetectedInfinityQuery() or + TPossibleMisuseOfUndetectedNaNQuery() + +predicate isFloatingTypes2QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `possibleMisuseOfUndetectedInfinity` query + FloatingTypes2Package::possibleMisuseOfUndetectedInfinityQuery() and + queryId = + // `@id` for the `possibleMisuseOfUndetectedInfinity` query + "c/misra/possible-misuse-of-undetected-infinity" and + ruleId = "DIR-4-15" and + category = "required" + or + query = + // `Query` instance for the `possibleMisuseOfUndetectedNaN` query + FloatingTypes2Package::possibleMisuseOfUndetectedNaNQuery() and + queryId = + // `@id` for the `possibleMisuseOfUndetectedNaN` query + "c/misra/possible-misuse-of-undetected-nan" and + ruleId = "DIR-4-15" and + category = "required" +} + +module FloatingTypes2Package { + Query possibleMisuseOfUndetectedInfinityQuery() { + //autogenerate `Query` type + result = + // `Query` type for `possibleMisuseOfUndetectedInfinity` query + TQueryC(TFloatingTypes2PackageQuery(TPossibleMisuseOfUndetectedInfinityQuery())) + } + + Query possibleMisuseOfUndetectedNaNQuery() { + //autogenerate `Query` type + result = + // `Query` type for `possibleMisuseOfUndetectedNaN` query + TQueryC(TFloatingTypes2PackageQuery(TPossibleMisuseOfUndetectedNaNQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/FunctionTypes.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/FunctionTypes.qll new file mode 100644 index 0000000000..3d6faadb42 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/FunctionTypes.qll @@ -0,0 +1,26 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype FunctionTypesQuery = TFunctionAddressesShouldAddressOperatorQuery() + +predicate isFunctionTypesQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `functionAddressesShouldAddressOperator` query + FunctionTypesPackage::functionAddressesShouldAddressOperatorQuery() and + queryId = + // `@id` for the `functionAddressesShouldAddressOperator` query + "c/misra/function-addresses-should-address-operator" and + ruleId = "RULE-17-12" and + category = "advisory" +} + +module FunctionTypesPackage { + Query functionAddressesShouldAddressOperatorQuery() { + //autogenerate `Query` type + result = + // `Query` type for `functionAddressesShouldAddressOperator` query + TQueryC(TFunctionTypesPackageQuery(TFunctionAddressesShouldAddressOperatorQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Generics.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Generics.qll new file mode 100644 index 0000000000..05e3402c19 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Generics.qll @@ -0,0 +1,163 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype GenericsQuery = + TGenericSelectionNotExpandedFromAMacroQuery() or + TGenericSelectionDoesntDependOnMacroArgumentQuery() or + TGenericSelectionNotFromMacroWithSideEffectsQuery() or + TGenericWithoutNonDefaultAssociationQuery() or + TGenericAssociationWithUnselectableTypeQuery() or + TDangerousDefaultSelectionForPointerInGenericQuery() or + TGenericExpressionWithIncorrectEssentialTypeQuery() or + TInvalidGenericMacroArgumentEvaluationQuery() or + TDefaultGenericSelectionNotFirstOrLastQuery() + +predicate isGenericsQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `genericSelectionNotExpandedFromAMacro` query + GenericsPackage::genericSelectionNotExpandedFromAMacroQuery() and + queryId = + // `@id` for the `genericSelectionNotExpandedFromAMacro` query + "c/misra/generic-selection-not-expanded-from-a-macro" and + ruleId = "RULE-23-1" and + category = "advisory" + or + query = + // `Query` instance for the `genericSelectionDoesntDependOnMacroArgument` query + GenericsPackage::genericSelectionDoesntDependOnMacroArgumentQuery() and + queryId = + // `@id` for the `genericSelectionDoesntDependOnMacroArgument` query + "c/misra/generic-selection-doesnt-depend-on-macro-argument" and + ruleId = "RULE-23-1" and + category = "advisory" + or + query = + // `Query` instance for the `genericSelectionNotFromMacroWithSideEffects` query + GenericsPackage::genericSelectionNotFromMacroWithSideEffectsQuery() and + queryId = + // `@id` for the `genericSelectionNotFromMacroWithSideEffects` query + "c/misra/generic-selection-not-from-macro-with-side-effects" and + ruleId = "RULE-23-2" and + category = "required" + or + query = + // `Query` instance for the `genericWithoutNonDefaultAssociation` query + GenericsPackage::genericWithoutNonDefaultAssociationQuery() and + queryId = + // `@id` for the `genericWithoutNonDefaultAssociation` query + "c/misra/generic-without-non-default-association" and + ruleId = "RULE-23-3" and + category = "advisory" + or + query = + // `Query` instance for the `genericAssociationWithUnselectableType` query + GenericsPackage::genericAssociationWithUnselectableTypeQuery() and + queryId = + // `@id` for the `genericAssociationWithUnselectableType` query + "c/misra/generic-association-with-unselectable-type" and + ruleId = "RULE-23-4" and + category = "required" + or + query = + // `Query` instance for the `dangerousDefaultSelectionForPointerInGeneric` query + GenericsPackage::dangerousDefaultSelectionForPointerInGenericQuery() and + queryId = + // `@id` for the `dangerousDefaultSelectionForPointerInGeneric` query + "c/misra/dangerous-default-selection-for-pointer-in-generic" and + ruleId = "RULE-23-5" and + category = "advisory" + or + query = + // `Query` instance for the `genericExpressionWithIncorrectEssentialType` query + GenericsPackage::genericExpressionWithIncorrectEssentialTypeQuery() and + queryId = + // `@id` for the `genericExpressionWithIncorrectEssentialType` query + "c/misra/generic-expression-with-incorrect-essential-type" and + ruleId = "RULE-23-6" and + category = "required" + or + query = + // `Query` instance for the `invalidGenericMacroArgumentEvaluation` query + GenericsPackage::invalidGenericMacroArgumentEvaluationQuery() and + queryId = + // `@id` for the `invalidGenericMacroArgumentEvaluation` query + "c/misra/invalid-generic-macro-argument-evaluation" and + ruleId = "RULE-23-7" and + category = "advisory" + or + query = + // `Query` instance for the `defaultGenericSelectionNotFirstOrLast` query + GenericsPackage::defaultGenericSelectionNotFirstOrLastQuery() and + queryId = + // `@id` for the `defaultGenericSelectionNotFirstOrLast` query + "c/misra/default-generic-selection-not-first-or-last" and + ruleId = "RULE-23-8" and + category = "required" +} + +module GenericsPackage { + Query genericSelectionNotExpandedFromAMacroQuery() { + //autogenerate `Query` type + result = + // `Query` type for `genericSelectionNotExpandedFromAMacro` query + TQueryC(TGenericsPackageQuery(TGenericSelectionNotExpandedFromAMacroQuery())) + } + + Query genericSelectionDoesntDependOnMacroArgumentQuery() { + //autogenerate `Query` type + result = + // `Query` type for `genericSelectionDoesntDependOnMacroArgument` query + TQueryC(TGenericsPackageQuery(TGenericSelectionDoesntDependOnMacroArgumentQuery())) + } + + Query genericSelectionNotFromMacroWithSideEffectsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `genericSelectionNotFromMacroWithSideEffects` query + TQueryC(TGenericsPackageQuery(TGenericSelectionNotFromMacroWithSideEffectsQuery())) + } + + Query genericWithoutNonDefaultAssociationQuery() { + //autogenerate `Query` type + result = + // `Query` type for `genericWithoutNonDefaultAssociation` query + TQueryC(TGenericsPackageQuery(TGenericWithoutNonDefaultAssociationQuery())) + } + + Query genericAssociationWithUnselectableTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `genericAssociationWithUnselectableType` query + TQueryC(TGenericsPackageQuery(TGenericAssociationWithUnselectableTypeQuery())) + } + + Query dangerousDefaultSelectionForPointerInGenericQuery() { + //autogenerate `Query` type + result = + // `Query` type for `dangerousDefaultSelectionForPointerInGeneric` query + TQueryC(TGenericsPackageQuery(TDangerousDefaultSelectionForPointerInGenericQuery())) + } + + Query genericExpressionWithIncorrectEssentialTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `genericExpressionWithIncorrectEssentialType` query + TQueryC(TGenericsPackageQuery(TGenericExpressionWithIncorrectEssentialTypeQuery())) + } + + Query invalidGenericMacroArgumentEvaluationQuery() { + //autogenerate `Query` type + result = + // `Query` type for `invalidGenericMacroArgumentEvaluation` query + TQueryC(TGenericsPackageQuery(TInvalidGenericMacroArgumentEvaluationQuery())) + } + + Query defaultGenericSelectionNotFirstOrLastQuery() { + //autogenerate `Query` type + result = + // `Query` type for `defaultGenericSelectionNotFirstOrLast` query + TQueryC(TGenericsPackageQuery(TDefaultGenericSelectionNotFirstOrLastQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/InvalidMemory3.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/InvalidMemory3.qll new file mode 100644 index 0000000000..c4e39882ec --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/InvalidMemory3.qll @@ -0,0 +1,61 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype InvalidMemory3Query = + TPointersToVariablyModifiedArrayTypesUsedQuery() or + TArrayToPointerConversionOfTemporaryObjectQuery() or + TModifiableLValueSubscriptedWithTemporaryLifetimeQuery() + +predicate isInvalidMemory3QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `pointersToVariablyModifiedArrayTypesUsed` query + InvalidMemory3Package::pointersToVariablyModifiedArrayTypesUsedQuery() and + queryId = + // `@id` for the `pointersToVariablyModifiedArrayTypesUsed` query + "c/misra/pointers-to-variably-modified-array-types-used" and + ruleId = "RULE-18-10" and + category = "mandatory" + or + query = + // `Query` instance for the `arrayToPointerConversionOfTemporaryObject` query + InvalidMemory3Package::arrayToPointerConversionOfTemporaryObjectQuery() and + queryId = + // `@id` for the `arrayToPointerConversionOfTemporaryObject` query + "c/misra/array-to-pointer-conversion-of-temporary-object" and + ruleId = "RULE-18-9" and + category = "required" + or + query = + // `Query` instance for the `modifiableLValueSubscriptedWithTemporaryLifetime` query + InvalidMemory3Package::modifiableLValueSubscriptedWithTemporaryLifetimeQuery() and + queryId = + // `@id` for the `modifiableLValueSubscriptedWithTemporaryLifetime` query + "c/misra/modifiable-l-value-subscripted-with-temporary-lifetime" and + ruleId = "RULE-18-9" and + category = "required" +} + +module InvalidMemory3Package { + Query pointersToVariablyModifiedArrayTypesUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `pointersToVariablyModifiedArrayTypesUsed` query + TQueryC(TInvalidMemory3PackageQuery(TPointersToVariablyModifiedArrayTypesUsedQuery())) + } + + Query arrayToPointerConversionOfTemporaryObjectQuery() { + //autogenerate `Query` type + result = + // `Query` type for `arrayToPointerConversionOfTemporaryObject` query + TQueryC(TInvalidMemory3PackageQuery(TArrayToPointerConversionOfTemporaryObjectQuery())) + } + + Query modifiableLValueSubscriptedWithTemporaryLifetimeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `modifiableLValueSubscriptedWithTemporaryLifetime` query + TQueryC(TInvalidMemory3PackageQuery(TModifiableLValueSubscriptedWithTemporaryLifetimeQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Language4.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Language4.qll new file mode 100644 index 0000000000..b4391ff5c2 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Language4.qll @@ -0,0 +1,163 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Language4Query = + TMissingStaticSpecifierFuncRedeclarationObsoleteQuery() or + TMissingStaticSpecifierObjectRedeclarationObsoleteQuery() or + TFunctionTypesNotInPrototypeFormObsoleteQuery() or + TUseOfObsoleteMacroAtomicVarInitQuery() or + TInvalidDefineOrUndefOfStdBoolMacroQuery() or + TCallToObsolescentFunctionGetsQuery() or + TUngetcCallOnStreamPositionZeroQuery() or + TSizeInReallocCallMayBeZeroQuery() or + TSizeInReallocCallIsZeroQuery() + +predicate isLanguage4QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `missingStaticSpecifierFuncRedeclarationObsolete` query + Language4Package::missingStaticSpecifierFuncRedeclarationObsoleteQuery() and + queryId = + // `@id` for the `missingStaticSpecifierFuncRedeclarationObsolete` query + "c/misra/missing-static-specifier-func-redeclaration-obsolete" and + ruleId = "RULE-1-5" and + category = "required" + or + query = + // `Query` instance for the `missingStaticSpecifierObjectRedeclarationObsolete` query + Language4Package::missingStaticSpecifierObjectRedeclarationObsoleteQuery() and + queryId = + // `@id` for the `missingStaticSpecifierObjectRedeclarationObsolete` query + "c/misra/missing-static-specifier-object-redeclaration-obsolete" and + ruleId = "RULE-1-5" and + category = "required" + or + query = + // `Query` instance for the `functionTypesNotInPrototypeFormObsolete` query + Language4Package::functionTypesNotInPrototypeFormObsoleteQuery() and + queryId = + // `@id` for the `functionTypesNotInPrototypeFormObsolete` query + "c/misra/function-types-not-in-prototype-form-obsolete" and + ruleId = "RULE-1-5" and + category = "required" + or + query = + // `Query` instance for the `useOfObsoleteMacroAtomicVarInit` query + Language4Package::useOfObsoleteMacroAtomicVarInitQuery() and + queryId = + // `@id` for the `useOfObsoleteMacroAtomicVarInit` query + "c/misra/use-of-obsolete-macro-atomic-var-init" and + ruleId = "RULE-1-5" and + category = "required" + or + query = + // `Query` instance for the `invalidDefineOrUndefOfStdBoolMacro` query + Language4Package::invalidDefineOrUndefOfStdBoolMacroQuery() and + queryId = + // `@id` for the `invalidDefineOrUndefOfStdBoolMacro` query + "c/misra/invalid-define-or-undef-of-std-bool-macro" and + ruleId = "RULE-1-5" and + category = "required" + or + query = + // `Query` instance for the `callToObsolescentFunctionGets` query + Language4Package::callToObsolescentFunctionGetsQuery() and + queryId = + // `@id` for the `callToObsolescentFunctionGets` query + "c/misra/call-to-obsolescent-function-gets" and + ruleId = "RULE-1-5" and + category = "required" + or + query = + // `Query` instance for the `ungetcCallOnStreamPositionZero` query + Language4Package::ungetcCallOnStreamPositionZeroQuery() and + queryId = + // `@id` for the `ungetcCallOnStreamPositionZero` query + "c/misra/ungetc-call-on-stream-position-zero" and + ruleId = "RULE-1-5" and + category = "required" + or + query = + // `Query` instance for the `sizeInReallocCallMayBeZero` query + Language4Package::sizeInReallocCallMayBeZeroQuery() and + queryId = + // `@id` for the `sizeInReallocCallMayBeZero` query + "c/misra/size-in-realloc-call-may-be-zero" and + ruleId = "RULE-1-5" and + category = "required" + or + query = + // `Query` instance for the `sizeInReallocCallIsZero` query + Language4Package::sizeInReallocCallIsZeroQuery() and + queryId = + // `@id` for the `sizeInReallocCallIsZero` query + "c/misra/size-in-realloc-call-is-zero" and + ruleId = "RULE-1-5" and + category = "required" +} + +module Language4Package { + Query missingStaticSpecifierFuncRedeclarationObsoleteQuery() { + //autogenerate `Query` type + result = + // `Query` type for `missingStaticSpecifierFuncRedeclarationObsolete` query + TQueryC(TLanguage4PackageQuery(TMissingStaticSpecifierFuncRedeclarationObsoleteQuery())) + } + + Query missingStaticSpecifierObjectRedeclarationObsoleteQuery() { + //autogenerate `Query` type + result = + // `Query` type for `missingStaticSpecifierObjectRedeclarationObsolete` query + TQueryC(TLanguage4PackageQuery(TMissingStaticSpecifierObjectRedeclarationObsoleteQuery())) + } + + Query functionTypesNotInPrototypeFormObsoleteQuery() { + //autogenerate `Query` type + result = + // `Query` type for `functionTypesNotInPrototypeFormObsolete` query + TQueryC(TLanguage4PackageQuery(TFunctionTypesNotInPrototypeFormObsoleteQuery())) + } + + Query useOfObsoleteMacroAtomicVarInitQuery() { + //autogenerate `Query` type + result = + // `Query` type for `useOfObsoleteMacroAtomicVarInit` query + TQueryC(TLanguage4PackageQuery(TUseOfObsoleteMacroAtomicVarInitQuery())) + } + + Query invalidDefineOrUndefOfStdBoolMacroQuery() { + //autogenerate `Query` type + result = + // `Query` type for `invalidDefineOrUndefOfStdBoolMacro` query + TQueryC(TLanguage4PackageQuery(TInvalidDefineOrUndefOfStdBoolMacroQuery())) + } + + Query callToObsolescentFunctionGetsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `callToObsolescentFunctionGets` query + TQueryC(TLanguage4PackageQuery(TCallToObsolescentFunctionGetsQuery())) + } + + Query ungetcCallOnStreamPositionZeroQuery() { + //autogenerate `Query` type + result = + // `Query` type for `ungetcCallOnStreamPositionZero` query + TQueryC(TLanguage4PackageQuery(TUngetcCallOnStreamPositionZeroQuery())) + } + + Query sizeInReallocCallMayBeZeroQuery() { + //autogenerate `Query` type + result = + // `Query` type for `sizeInReallocCallMayBeZero` query + TQueryC(TLanguage4PackageQuery(TSizeInReallocCallMayBeZeroQuery())) + } + + Query sizeInReallocCallIsZeroQuery() { + //autogenerate `Query` type + result = + // `Query` type for `sizeInReallocCallIsZero` query + TQueryC(TLanguage4PackageQuery(TSizeInReallocCallIsZeroQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/NoReturn.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/NoReturn.qll new file mode 100644 index 0000000000..07b9360213 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/NoReturn.qll @@ -0,0 +1,61 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype NoReturnQuery = + TNonVoidReturnTypeOfNoreturnFunctionQuery() or + TFunctionWithNoReturningBranchShouldBeNoreturnQuery() or + TReturnStatementInNoreturnFunctionQuery() + +predicate isNoReturnQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `nonVoidReturnTypeOfNoreturnFunction` query + NoReturnPackage::nonVoidReturnTypeOfNoreturnFunctionQuery() and + queryId = + // `@id` for the `nonVoidReturnTypeOfNoreturnFunction` query + "c/misra/non-void-return-type-of-noreturn-function" and + ruleId = "RULE-17-10" and + category = "required" + or + query = + // `Query` instance for the `functionWithNoReturningBranchShouldBeNoreturn` query + NoReturnPackage::functionWithNoReturningBranchShouldBeNoreturnQuery() and + queryId = + // `@id` for the `functionWithNoReturningBranchShouldBeNoreturn` query + "c/misra/function-with-no-returning-branch-should-be-noreturn" and + ruleId = "RULE-17-11" and + category = "advisory" + or + query = + // `Query` instance for the `returnStatementInNoreturnFunction` query + NoReturnPackage::returnStatementInNoreturnFunctionQuery() and + queryId = + // `@id` for the `returnStatementInNoreturnFunction` query + "c/misra/return-statement-in-noreturn-function" and + ruleId = "RULE-17-9" and + category = "mandatory" +} + +module NoReturnPackage { + Query nonVoidReturnTypeOfNoreturnFunctionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nonVoidReturnTypeOfNoreturnFunction` query + TQueryC(TNoReturnPackageQuery(TNonVoidReturnTypeOfNoreturnFunctionQuery())) + } + + Query functionWithNoReturningBranchShouldBeNoreturnQuery() { + //autogenerate `Query` type + result = + // `Query` type for `functionWithNoReturningBranchShouldBeNoreturn` query + TQueryC(TNoReturnPackageQuery(TFunctionWithNoReturningBranchShouldBeNoreturnQuery())) + } + + Query returnStatementInNoreturnFunctionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `returnStatementInNoreturnFunction` query + TQueryC(TNoReturnPackageQuery(TReturnStatementInNoreturnFunctionQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Pointers1.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Pointers1.qll index e35f0f3a88..725fe46904 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/Pointers1.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Pointers1.qll @@ -19,6 +19,7 @@ newtype Pointers1Query = TDoNotUseAdditionOrSubtractionOperatorsOnPointersQuery() or TNoMoreThanTwoLevelsOfPointerNestingInDeclarationsQuery() or TAutomaticStorageObjectAddressCopiedToOtherObjectQuery() or + TThreadLocalObjectAddressCopiedToGlobalObjectQuery() or TObjectWithNoPointerDereferenceShouldBeOpaqueQuery() or TPointerShouldPointToConstTypeWhenPossibleQuery() @@ -158,6 +159,15 @@ predicate isPointers1QueryMetadata(Query query, string queryId, string ruleId, s ruleId = "RULE-18-6" and category = "required" or + query = + // `Query` instance for the `threadLocalObjectAddressCopiedToGlobalObject` query + Pointers1Package::threadLocalObjectAddressCopiedToGlobalObjectQuery() and + queryId = + // `@id` for the `threadLocalObjectAddressCopiedToGlobalObject` query + "c/misra/thread-local-object-address-copied-to-global-object" and + ruleId = "RULE-18-6" and + category = "required" + or query = // `Query` instance for the `objectWithNoPointerDereferenceShouldBeOpaque` query Pointers1Package::objectWithNoPointerDereferenceShouldBeOpaqueQuery() and @@ -283,6 +293,13 @@ module Pointers1Package { TQueryC(TPointers1PackageQuery(TAutomaticStorageObjectAddressCopiedToOtherObjectQuery())) } + Query threadLocalObjectAddressCopiedToGlobalObjectQuery() { + //autogenerate `Query` type + result = + // `Query` type for `threadLocalObjectAddressCopiedToGlobalObject` query + TQueryC(TPointers1PackageQuery(TThreadLocalObjectAddressCopiedToGlobalObjectQuery())) + } + Query objectWithNoPointerDereferenceShouldBeOpaqueQuery() { //autogenerate `Query` type result = diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index c2771f4171..b574f7551c 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -2,13 +2,21 @@ import cpp import codingstandards.cpp.exclusions.RuleMetadata //** Import packages for this language **/ +import Alignment import Banned +import Banned2 import BitfieldTypes +import BitfieldTypes2 import Concurrency1 import Concurrency2 import Concurrency3 import Concurrency4 import Concurrency5 +import Concurrency6 +import Concurrency7 +import Concurrency8 +import Concurrency9 +import Contracts import Contracts1 import Contracts2 import Contracts3 @@ -17,6 +25,7 @@ import Contracts5 import Contracts6 import Contracts7 import DeadCode +import DeadCode2 import Declarations1 import Declarations2 import Declarations3 @@ -25,9 +34,15 @@ import Declarations5 import Declarations6 import Declarations7 import Declarations8 +import Declarations9 import EssentialTypes +import EssentialTypes2 import Expressions +import Expressions2 import FloatingTypes +import FloatingTypes2 +import FunctionTypes +import Generics import IO1 import IO2 import IO3 @@ -35,13 +50,16 @@ import IO4 import IntegerOverflow import InvalidMemory1 import InvalidMemory2 +import InvalidMemory3 import Language1 import Language2 import Language3 +import Language4 import Memory1 import Memory2 import Memory3 import Misc +import NoReturn import OutOfBounds import Pointers1 import Pointers2 @@ -70,16 +88,25 @@ import Strings2 import Strings3 import Syntax import Types1 +import Types2 /** The TQuery type representing this language * */ newtype TCQuery = + TAlignmentPackageQuery(AlignmentQuery q) or TBannedPackageQuery(BannedQuery q) or + TBanned2PackageQuery(Banned2Query q) or TBitfieldTypesPackageQuery(BitfieldTypesQuery q) or + TBitfieldTypes2PackageQuery(BitfieldTypes2Query q) or TConcurrency1PackageQuery(Concurrency1Query q) or TConcurrency2PackageQuery(Concurrency2Query q) or TConcurrency3PackageQuery(Concurrency3Query q) or TConcurrency4PackageQuery(Concurrency4Query q) or TConcurrency5PackageQuery(Concurrency5Query q) or + TConcurrency6PackageQuery(Concurrency6Query q) or + TConcurrency7PackageQuery(Concurrency7Query q) or + TConcurrency8PackageQuery(Concurrency8Query q) or + TConcurrency9PackageQuery(Concurrency9Query q) or + TContractsPackageQuery(ContractsQuery q) or TContracts1PackageQuery(Contracts1Query q) or TContracts2PackageQuery(Contracts2Query q) or TContracts3PackageQuery(Contracts3Query q) or @@ -88,6 +115,7 @@ newtype TCQuery = TContracts6PackageQuery(Contracts6Query q) or TContracts7PackageQuery(Contracts7Query q) or TDeadCodePackageQuery(DeadCodeQuery q) or + TDeadCode2PackageQuery(DeadCode2Query q) or TDeclarations1PackageQuery(Declarations1Query q) or TDeclarations2PackageQuery(Declarations2Query q) or TDeclarations3PackageQuery(Declarations3Query q) or @@ -96,9 +124,15 @@ newtype TCQuery = TDeclarations6PackageQuery(Declarations6Query q) or TDeclarations7PackageQuery(Declarations7Query q) or TDeclarations8PackageQuery(Declarations8Query q) or + TDeclarations9PackageQuery(Declarations9Query q) or TEssentialTypesPackageQuery(EssentialTypesQuery q) or + TEssentialTypes2PackageQuery(EssentialTypes2Query q) or TExpressionsPackageQuery(ExpressionsQuery q) or + TExpressions2PackageQuery(Expressions2Query q) or TFloatingTypesPackageQuery(FloatingTypesQuery q) or + TFloatingTypes2PackageQuery(FloatingTypes2Query q) or + TFunctionTypesPackageQuery(FunctionTypesQuery q) or + TGenericsPackageQuery(GenericsQuery q) or TIO1PackageQuery(IO1Query q) or TIO2PackageQuery(IO2Query q) or TIO3PackageQuery(IO3Query q) or @@ -106,13 +140,16 @@ newtype TCQuery = TIntegerOverflowPackageQuery(IntegerOverflowQuery q) or TInvalidMemory1PackageQuery(InvalidMemory1Query q) or TInvalidMemory2PackageQuery(InvalidMemory2Query q) or + TInvalidMemory3PackageQuery(InvalidMemory3Query q) or TLanguage1PackageQuery(Language1Query q) or TLanguage2PackageQuery(Language2Query q) or TLanguage3PackageQuery(Language3Query q) or + TLanguage4PackageQuery(Language4Query q) or TMemory1PackageQuery(Memory1Query q) or TMemory2PackageQuery(Memory2Query q) or TMemory3PackageQuery(Memory3Query q) or TMiscPackageQuery(MiscQuery q) or + TNoReturnPackageQuery(NoReturnQuery q) or TOutOfBoundsPackageQuery(OutOfBoundsQuery q) or TPointers1PackageQuery(Pointers1Query q) or TPointers2PackageQuery(Pointers2Query q) or @@ -140,17 +177,26 @@ newtype TCQuery = TStrings2PackageQuery(Strings2Query q) or TStrings3PackageQuery(Strings3Query q) or TSyntaxPackageQuery(SyntaxQuery q) or - TTypes1PackageQuery(Types1Query q) + TTypes1PackageQuery(Types1Query q) or + TTypes2PackageQuery(Types2Query q) /** The metadata predicate * */ predicate isQueryMetadata(Query query, string queryId, string ruleId, string category) { + isAlignmentQueryMetadata(query, queryId, ruleId, category) or isBannedQueryMetadata(query, queryId, ruleId, category) or + isBanned2QueryMetadata(query, queryId, ruleId, category) or isBitfieldTypesQueryMetadata(query, queryId, ruleId, category) or + isBitfieldTypes2QueryMetadata(query, queryId, ruleId, category) or isConcurrency1QueryMetadata(query, queryId, ruleId, category) or isConcurrency2QueryMetadata(query, queryId, ruleId, category) or isConcurrency3QueryMetadata(query, queryId, ruleId, category) or isConcurrency4QueryMetadata(query, queryId, ruleId, category) or isConcurrency5QueryMetadata(query, queryId, ruleId, category) or + isConcurrency6QueryMetadata(query, queryId, ruleId, category) or + isConcurrency7QueryMetadata(query, queryId, ruleId, category) or + isConcurrency8QueryMetadata(query, queryId, ruleId, category) or + isConcurrency9QueryMetadata(query, queryId, ruleId, category) or + isContractsQueryMetadata(query, queryId, ruleId, category) or isContracts1QueryMetadata(query, queryId, ruleId, category) or isContracts2QueryMetadata(query, queryId, ruleId, category) or isContracts3QueryMetadata(query, queryId, ruleId, category) or @@ -159,6 +205,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isContracts6QueryMetadata(query, queryId, ruleId, category) or isContracts7QueryMetadata(query, queryId, ruleId, category) or isDeadCodeQueryMetadata(query, queryId, ruleId, category) or + isDeadCode2QueryMetadata(query, queryId, ruleId, category) or isDeclarations1QueryMetadata(query, queryId, ruleId, category) or isDeclarations2QueryMetadata(query, queryId, ruleId, category) or isDeclarations3QueryMetadata(query, queryId, ruleId, category) or @@ -167,9 +214,15 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isDeclarations6QueryMetadata(query, queryId, ruleId, category) or isDeclarations7QueryMetadata(query, queryId, ruleId, category) or isDeclarations8QueryMetadata(query, queryId, ruleId, category) or + isDeclarations9QueryMetadata(query, queryId, ruleId, category) or isEssentialTypesQueryMetadata(query, queryId, ruleId, category) or + isEssentialTypes2QueryMetadata(query, queryId, ruleId, category) or isExpressionsQueryMetadata(query, queryId, ruleId, category) or + isExpressions2QueryMetadata(query, queryId, ruleId, category) or isFloatingTypesQueryMetadata(query, queryId, ruleId, category) or + isFloatingTypes2QueryMetadata(query, queryId, ruleId, category) or + isFunctionTypesQueryMetadata(query, queryId, ruleId, category) or + isGenericsQueryMetadata(query, queryId, ruleId, category) or isIO1QueryMetadata(query, queryId, ruleId, category) or isIO2QueryMetadata(query, queryId, ruleId, category) or isIO3QueryMetadata(query, queryId, ruleId, category) or @@ -177,13 +230,16 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isIntegerOverflowQueryMetadata(query, queryId, ruleId, category) or isInvalidMemory1QueryMetadata(query, queryId, ruleId, category) or isInvalidMemory2QueryMetadata(query, queryId, ruleId, category) or + isInvalidMemory3QueryMetadata(query, queryId, ruleId, category) or isLanguage1QueryMetadata(query, queryId, ruleId, category) or isLanguage2QueryMetadata(query, queryId, ruleId, category) or isLanguage3QueryMetadata(query, queryId, ruleId, category) or + isLanguage4QueryMetadata(query, queryId, ruleId, category) or isMemory1QueryMetadata(query, queryId, ruleId, category) or isMemory2QueryMetadata(query, queryId, ruleId, category) or isMemory3QueryMetadata(query, queryId, ruleId, category) or isMiscQueryMetadata(query, queryId, ruleId, category) or + isNoReturnQueryMetadata(query, queryId, ruleId, category) or isOutOfBoundsQueryMetadata(query, queryId, ruleId, category) or isPointers1QueryMetadata(query, queryId, ruleId, category) or isPointers2QueryMetadata(query, queryId, ruleId, category) or @@ -211,5 +267,6 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isStrings2QueryMetadata(query, queryId, ruleId, category) or isStrings3QueryMetadata(query, queryId, ruleId, category) or isSyntaxQueryMetadata(query, queryId, ruleId, category) or - isTypes1QueryMetadata(query, queryId, ruleId, category) + isTypes1QueryMetadata(query, queryId, ruleId, category) or + isTypes2QueryMetadata(query, queryId, ruleId, category) } diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects1.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects1.qll index 24175cdfb7..ec8ab3eae8 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects1.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects1.qll @@ -104,7 +104,7 @@ predicate isSideEffects1QueryMetadata(Query query, string queryId, string ruleId // `@id` for the `sizeofOperandWithSideEffect` query "c/misra/sizeof-operand-with-side-effect" and ruleId = "RULE-13-6" and - category = "mandatory" + category = "required" } module SideEffects1Package { diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects3.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects3.qll index eff4f2caf9..7b01c18099 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects3.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects3.qll @@ -3,7 +3,9 @@ import cpp import RuleMetadata import codingstandards.cpp.exclusions.RuleMetadata -newtype SideEffects3Query = TUnsequencedSideEffectsQuery() +newtype SideEffects3Query = + TUnsequencedSideEffectsQuery() or + TUnsequencedAtomicReadsQuery() predicate isSideEffects3QueryMetadata(Query query, string queryId, string ruleId, string category) { query = @@ -14,6 +16,15 @@ predicate isSideEffects3QueryMetadata(Query query, string queryId, string ruleId "c/misra/unsequenced-side-effects" and ruleId = "RULE-13-2" and category = "required" + or + query = + // `Query` instance for the `unsequencedAtomicReads` query + SideEffects3Package::unsequencedAtomicReadsQuery() and + queryId = + // `@id` for the `unsequencedAtomicReads` query + "c/misra/unsequenced-atomic-reads" and + ruleId = "RULE-13-2" and + category = "required" } module SideEffects3Package { @@ -23,4 +34,11 @@ module SideEffects3Package { // `Query` type for `unsequencedSideEffects` query TQueryC(TSideEffects3PackageQuery(TUnsequencedSideEffectsQuery())) } + + Query unsequencedAtomicReadsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unsequencedAtomicReads` query + TQueryC(TSideEffects3PackageQuery(TUnsequencedAtomicReadsQuery())) + } } diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Types2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Types2.qll new file mode 100644 index 0000000000..3b2d3a4342 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Types2.qll @@ -0,0 +1,95 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Types2Query = + TInvalidIntegerConstantMacroArgumentQuery() or + TInvalidLiteralForIntegerConstantMacroArgumentQuery() or + TIntegerConstantMacroArgumentUsesSuffixQuery() or + TIncorrectlySizedIntegerConstantMacroArgumentQuery() or + TUseOfBannedSmallIntegerConstantMacroQuery() + +predicate isTypes2QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `invalidIntegerConstantMacroArgument` query + Types2Package::invalidIntegerConstantMacroArgumentQuery() and + queryId = + // `@id` for the `invalidIntegerConstantMacroArgument` query + "c/misra/invalid-integer-constant-macro-argument" and + ruleId = "RULE-7-5" and + category = "required" + or + query = + // `Query` instance for the `invalidLiteralForIntegerConstantMacroArgument` query + Types2Package::invalidLiteralForIntegerConstantMacroArgumentQuery() and + queryId = + // `@id` for the `invalidLiteralForIntegerConstantMacroArgument` query + "c/misra/invalid-literal-for-integer-constant-macro-argument" and + ruleId = "RULE-7-5" and + category = "required" + or + query = + // `Query` instance for the `integerConstantMacroArgumentUsesSuffix` query + Types2Package::integerConstantMacroArgumentUsesSuffixQuery() and + queryId = + // `@id` for the `integerConstantMacroArgumentUsesSuffix` query + "c/misra/integer-constant-macro-argument-uses-suffix" and + ruleId = "RULE-7-5" and + category = "required" + or + query = + // `Query` instance for the `incorrectlySizedIntegerConstantMacroArgument` query + Types2Package::incorrectlySizedIntegerConstantMacroArgumentQuery() and + queryId = + // `@id` for the `incorrectlySizedIntegerConstantMacroArgument` query + "c/misra/incorrectly-sized-integer-constant-macro-argument" and + ruleId = "RULE-7-5" and + category = "required" + or + query = + // `Query` instance for the `useOfBannedSmallIntegerConstantMacro` query + Types2Package::useOfBannedSmallIntegerConstantMacroQuery() and + queryId = + // `@id` for the `useOfBannedSmallIntegerConstantMacro` query + "c/misra/use-of-banned-small-integer-constant-macro" and + ruleId = "RULE-7-6" and + category = "required" +} + +module Types2Package { + Query invalidIntegerConstantMacroArgumentQuery() { + //autogenerate `Query` type + result = + // `Query` type for `invalidIntegerConstantMacroArgument` query + TQueryC(TTypes2PackageQuery(TInvalidIntegerConstantMacroArgumentQuery())) + } + + Query invalidLiteralForIntegerConstantMacroArgumentQuery() { + //autogenerate `Query` type + result = + // `Query` type for `invalidLiteralForIntegerConstantMacroArgument` query + TQueryC(TTypes2PackageQuery(TInvalidLiteralForIntegerConstantMacroArgumentQuery())) + } + + Query integerConstantMacroArgumentUsesSuffixQuery() { + //autogenerate `Query` type + result = + // `Query` type for `integerConstantMacroArgumentUsesSuffix` query + TQueryC(TTypes2PackageQuery(TIntegerConstantMacroArgumentUsesSuffixQuery())) + } + + Query incorrectlySizedIntegerConstantMacroArgumentQuery() { + //autogenerate `Query` type + result = + // `Query` type for `incorrectlySizedIntegerConstantMacroArgument` query + TQueryC(TTypes2PackageQuery(TIncorrectlySizedIntegerConstantMacroArgumentQuery())) + } + + Query useOfBannedSmallIntegerConstantMacroQuery() { + //autogenerate `Query` type + result = + // `Query` type for `useOfBannedSmallIntegerConstantMacro` query + TQueryC(TTypes2PackageQuery(TUseOfBannedSmallIntegerConstantMacroQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll new file mode 100644 index 0000000000..ea4f78841b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll @@ -0,0 +1,180 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype BannedAPIsQuery = + TAvoidProgramTerminatingFunctionsQuery() or + TNoVariadicFunctionMacrosQuery() or + TNoCsetjmpHeaderQuery() or + TUnsafeStringHandlingFunctionsQuery() or + TBannedSystemFunctionQuery() or + TUseSmartPtrFactoryFunctionsQuery() or + TCharacterHandlingFunctionRestrictionsQuery() or + TNoMemoryFunctionsFromCStringQuery() or + TLocaleGlobalFunctionNotAllowedQuery() or + TAvoidStandardIntegerTypeNamesQuery() + +predicate isBannedAPIsQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `avoidProgramTerminatingFunctions` query + BannedAPIsPackage::avoidProgramTerminatingFunctionsQuery() and + queryId = + // `@id` for the `avoidProgramTerminatingFunctions` query + "cpp/misra/avoid-program-terminating-functions" and + ruleId = "RULE-18-5-2" and + category = "advisory" + or + query = + // `Query` instance for the `noVariadicFunctionMacros` query + BannedAPIsPackage::noVariadicFunctionMacrosQuery() and + queryId = + // `@id` for the `noVariadicFunctionMacros` query + "cpp/misra/no-variadic-function-macros" and + ruleId = "RULE-21-10-1" and + category = "required" + or + query = + // `Query` instance for the `noCsetjmpHeader` query + BannedAPIsPackage::noCsetjmpHeaderQuery() and + queryId = + // `@id` for the `noCsetjmpHeader` query + "cpp/misra/no-csetjmp-header" and + ruleId = "RULE-21-10-2" and + category = "required" + or + query = + // `Query` instance for the `unsafeStringHandlingFunctions` query + BannedAPIsPackage::unsafeStringHandlingFunctionsQuery() and + queryId = + // `@id` for the `unsafeStringHandlingFunctions` query + "cpp/misra/unsafe-string-handling-functions" and + ruleId = "RULE-21-2-2" and + category = "required" + or + query = + // `Query` instance for the `bannedSystemFunction` query + BannedAPIsPackage::bannedSystemFunctionQuery() and + queryId = + // `@id` for the `bannedSystemFunction` query + "cpp/misra/banned-system-function" and + ruleId = "RULE-21-2-3" and + category = "required" + or + query = + // `Query` instance for the `useSmartPtrFactoryFunctions` query + BannedAPIsPackage::useSmartPtrFactoryFunctionsQuery() and + queryId = + // `@id` for the `useSmartPtrFactoryFunctions` query + "cpp/misra/use-smart-ptr-factory-functions" and + ruleId = "RULE-23-11-1" and + category = "advisory" + or + query = + // `Query` instance for the `characterHandlingFunctionRestrictions` query + BannedAPIsPackage::characterHandlingFunctionRestrictionsQuery() and + queryId = + // `@id` for the `characterHandlingFunctionRestrictions` query + "cpp/misra/character-handling-function-restrictions" and + ruleId = "RULE-24-5-1" and + category = "required" + or + query = + // `Query` instance for the `noMemoryFunctionsFromCString` query + BannedAPIsPackage::noMemoryFunctionsFromCStringQuery() and + queryId = + // `@id` for the `noMemoryFunctionsFromCString` query + "cpp/misra/no-memory-functions-from-c-string" and + ruleId = "RULE-24-5-2" and + category = "required" + or + query = + // `Query` instance for the `localeGlobalFunctionNotAllowed` query + BannedAPIsPackage::localeGlobalFunctionNotAllowedQuery() and + queryId = + // `@id` for the `localeGlobalFunctionNotAllowed` query + "cpp/misra/locale-global-function-not-allowed" and + ruleId = "RULE-25-5-1" and + category = "required" + or + query = + // `Query` instance for the `avoidStandardIntegerTypeNames` query + BannedAPIsPackage::avoidStandardIntegerTypeNamesQuery() and + queryId = + // `@id` for the `avoidStandardIntegerTypeNames` query + "cpp/misra/avoid-standard-integer-type-names" and + ruleId = "RULE-6-9-2" and + category = "advisory" +} + +module BannedAPIsPackage { + Query avoidProgramTerminatingFunctionsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `avoidProgramTerminatingFunctions` query + TQueryCPP(TBannedAPIsPackageQuery(TAvoidProgramTerminatingFunctionsQuery())) + } + + Query noVariadicFunctionMacrosQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noVariadicFunctionMacros` query + TQueryCPP(TBannedAPIsPackageQuery(TNoVariadicFunctionMacrosQuery())) + } + + Query noCsetjmpHeaderQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noCsetjmpHeader` query + TQueryCPP(TBannedAPIsPackageQuery(TNoCsetjmpHeaderQuery())) + } + + Query unsafeStringHandlingFunctionsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unsafeStringHandlingFunctions` query + TQueryCPP(TBannedAPIsPackageQuery(TUnsafeStringHandlingFunctionsQuery())) + } + + Query bannedSystemFunctionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `bannedSystemFunction` query + TQueryCPP(TBannedAPIsPackageQuery(TBannedSystemFunctionQuery())) + } + + Query useSmartPtrFactoryFunctionsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `useSmartPtrFactoryFunctions` query + TQueryCPP(TBannedAPIsPackageQuery(TUseSmartPtrFactoryFunctionsQuery())) + } + + Query characterHandlingFunctionRestrictionsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `characterHandlingFunctionRestrictions` query + TQueryCPP(TBannedAPIsPackageQuery(TCharacterHandlingFunctionRestrictionsQuery())) + } + + Query noMemoryFunctionsFromCStringQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noMemoryFunctionsFromCString` query + TQueryCPP(TBannedAPIsPackageQuery(TNoMemoryFunctionsFromCStringQuery())) + } + + Query localeGlobalFunctionNotAllowedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `localeGlobalFunctionNotAllowed` query + TQueryCPP(TBannedAPIsPackageQuery(TLocaleGlobalFunctionNotAllowedQuery())) + } + + Query avoidStandardIntegerTypeNamesQuery() { + //autogenerate `Query` type + result = + // `Query` type for `avoidStandardIntegerTypeNames` query + TQueryCPP(TBannedAPIsPackageQuery(TAvoidStandardIntegerTypeNamesQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Classes.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Classes.qll index 92c7a4280e..3daf48c696 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Classes.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Classes.qll @@ -13,7 +13,6 @@ newtype ClassesQuery = TClassDataMembersInitializationConditionQuery() or TRedundantMemberFunctionsShouldBeDefaultedOrLeftUndefinedQuery() or TNonTemplateMemberDefinedInTemplateQuery() or - TTrivialOrTemplateFunctionDefinedOutsideClassDefinitionQuery() or TNonTrivialNonTemplateFunctionDefinedInsideClassDefinitionQuery() or TInParametersForNotCheapToCopyTypesNotPassedByReferenceQuery() or TInParametersForCheapToCopyTypesNotPassedByValueQuery() or @@ -105,15 +104,6 @@ predicate isClassesQueryMetadata(Query query, string queryId, string ruleId, str ruleId = "A14-5-2" and category = "advisory" or - query = - // `Query` instance for the `trivialOrTemplateFunctionDefinedOutsideClassDefinition` query - ClassesPackage::trivialOrTemplateFunctionDefinedOutsideClassDefinitionQuery() and - queryId = - // `@id` for the `trivialOrTemplateFunctionDefinedOutsideClassDefinition` query - "cpp/autosar/trivial-or-template-function-defined-outside-class-definition" and - ruleId = "A3-1-5" and - category = "required" - or query = // `Query` instance for the `nonTrivialNonTemplateFunctionDefinedInsideClassDefinition` query ClassesPackage::nonTrivialNonTemplateFunctionDefinedInsideClassDefinitionQuery() and @@ -251,13 +241,6 @@ module ClassesPackage { TQueryCPP(TClassesPackageQuery(TNonTemplateMemberDefinedInTemplateQuery())) } - Query trivialOrTemplateFunctionDefinedOutsideClassDefinitionQuery() { - //autogenerate `Query` type - result = - // `Query` type for `trivialOrTemplateFunctionDefinedOutsideClassDefinition` query - TQueryCPP(TClassesPackageQuery(TTrivialOrTemplateFunctionDefinedOutsideClassDefinitionQuery())) - } - Query nonTrivialNonTemplateFunctionDefinedInsideClassDefinitionQuery() { //autogenerate `Query` type result = diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Const.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Const.qll index 09f40388cc..f542ddf486 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Const.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Const.qll @@ -7,7 +7,6 @@ newtype ConstQuery = TRemoveConstOrVolatileQualificationAutosarQuery() or TDeclarationUnmodifiedObjectMissingConstSpecifierQuery() or TVariableMissingConstexprQuery() or - TFunctionMissingConstexprQuery() or TCvQualifiersNotPlacedOnTheRightHandSideQuery() or TOutputParametersUsedQuery() or TInOutParametersDeclaredAsTNotModifiedQuery() or @@ -45,15 +44,6 @@ predicate isConstQueryMetadata(Query query, string queryId, string ruleId, strin ruleId = "A7-1-2" and category = "required" or - query = - // `Query` instance for the `functionMissingConstexpr` query - ConstPackage::functionMissingConstexprQuery() and - queryId = - // `@id` for the `functionMissingConstexpr` query - "cpp/autosar/function-missing-constexpr" and - ruleId = "A7-1-2" and - category = "required" - or query = // `Query` instance for the `cvQualifiersNotPlacedOnTheRightHandSide` query ConstPackage::cvQualifiersNotPlacedOnTheRightHandSideQuery() and @@ -149,13 +139,6 @@ module ConstPackage { TQueryCPP(TConstPackageQuery(TVariableMissingConstexprQuery())) } - Query functionMissingConstexprQuery() { - //autogenerate `Query` type - result = - // `Query` type for `functionMissingConstexpr` query - TQueryCPP(TConstPackageQuery(TFunctionMissingConstexprQuery())) - } - Query cvQualifiersNotPlacedOnTheRightHandSideQuery() { //autogenerate `Query` type result = diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions.qll new file mode 100644 index 0000000000..393f0cbdf5 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions.qll @@ -0,0 +1,129 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype ConversionsQuery = + TNoConversionFromBoolQuery() or + TNoImplicitBoolConversionQuery() or + TNoCharacterNumericalValueQuery() or + TInappropriateBitwiseOrShiftOperandsQuery() or + TNoSignednessChangeFromPromotionQuery() or + TNumericAssignmentTypeMismatchQuery() or + TFunctionPointerConversionContextQuery() + +predicate isConversionsQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `noConversionFromBool` query + ConversionsPackage::noConversionFromBoolQuery() and + queryId = + // `@id` for the `noConversionFromBool` query + "cpp/misra/no-conversion-from-bool" and + ruleId = "RULE-7-0-1" and + category = "required" + or + query = + // `Query` instance for the `noImplicitBoolConversion` query + ConversionsPackage::noImplicitBoolConversionQuery() and + queryId = + // `@id` for the `noImplicitBoolConversion` query + "cpp/misra/no-implicit-bool-conversion" and + ruleId = "RULE-7-0-2" and + category = "required" + or + query = + // `Query` instance for the `noCharacterNumericalValue` query + ConversionsPackage::noCharacterNumericalValueQuery() and + queryId = + // `@id` for the `noCharacterNumericalValue` query + "cpp/misra/no-character-numerical-value" and + ruleId = "RULE-7-0-3" and + category = "required" + or + query = + // `Query` instance for the `inappropriateBitwiseOrShiftOperands` query + ConversionsPackage::inappropriateBitwiseOrShiftOperandsQuery() and + queryId = + // `@id` for the `inappropriateBitwiseOrShiftOperands` query + "cpp/misra/inappropriate-bitwise-or-shift-operands" and + ruleId = "RULE-7-0-4" and + category = "required" + or + query = + // `Query` instance for the `noSignednessChangeFromPromotion` query + ConversionsPackage::noSignednessChangeFromPromotionQuery() and + queryId = + // `@id` for the `noSignednessChangeFromPromotion` query + "cpp/misra/no-signedness-change-from-promotion" and + ruleId = "RULE-7-0-5" and + category = "required" + or + query = + // `Query` instance for the `numericAssignmentTypeMismatch` query + ConversionsPackage::numericAssignmentTypeMismatchQuery() and + queryId = + // `@id` for the `numericAssignmentTypeMismatch` query + "cpp/misra/numeric-assignment-type-mismatch" and + ruleId = "RULE-7-0-6" and + category = "required" + or + query = + // `Query` instance for the `functionPointerConversionContext` query + ConversionsPackage::functionPointerConversionContextQuery() and + queryId = + // `@id` for the `functionPointerConversionContext` query + "cpp/misra/function-pointer-conversion-context" and + ruleId = "RULE-7-11-3" and + category = "required" +} + +module ConversionsPackage { + Query noConversionFromBoolQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noConversionFromBool` query + TQueryCPP(TConversionsPackageQuery(TNoConversionFromBoolQuery())) + } + + Query noImplicitBoolConversionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noImplicitBoolConversion` query + TQueryCPP(TConversionsPackageQuery(TNoImplicitBoolConversionQuery())) + } + + Query noCharacterNumericalValueQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noCharacterNumericalValue` query + TQueryCPP(TConversionsPackageQuery(TNoCharacterNumericalValueQuery())) + } + + Query inappropriateBitwiseOrShiftOperandsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `inappropriateBitwiseOrShiftOperands` query + TQueryCPP(TConversionsPackageQuery(TInappropriateBitwiseOrShiftOperandsQuery())) + } + + Query noSignednessChangeFromPromotionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noSignednessChangeFromPromotion` query + TQueryCPP(TConversionsPackageQuery(TNoSignednessChangeFromPromotionQuery())) + } + + Query numericAssignmentTypeMismatchQuery() { + //autogenerate `Query` type + result = + // `Query` type for `numericAssignmentTypeMismatch` query + TQueryCPP(TConversionsPackageQuery(TNumericAssignmentTypeMismatchQuery())) + } + + Query functionPointerConversionContextQuery() { + //autogenerate `Query` type + result = + // `Query` type for `functionPointerConversionContext` query + TQueryCPP(TConversionsPackageQuery(TFunctionPointerConversionContextQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions2.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions2.qll new file mode 100644 index 0000000000..a250b4b5b1 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions2.qll @@ -0,0 +1,112 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Conversions2Query = + TVirtualBaseClassCastToDerivedQuery() or + TNoCStyleOrFunctionalCastsQuery() or + TIntToPointerCastProhibitedQuery() or + TNoPointerToIntegralCastQuery() or + TPointerToIntegralCastQuery() or + TNoStandaloneTypeCastExpressionQuery() + +predicate isConversions2QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `virtualBaseClassCastToDerived` query + Conversions2Package::virtualBaseClassCastToDerivedQuery() and + queryId = + // `@id` for the `virtualBaseClassCastToDerived` query + "cpp/misra/virtual-base-class-cast-to-derived" and + ruleId = "RULE-8-2-1" and + category = "required" + or + query = + // `Query` instance for the `noCStyleOrFunctionalCasts` query + Conversions2Package::noCStyleOrFunctionalCastsQuery() and + queryId = + // `@id` for the `noCStyleOrFunctionalCasts` query + "cpp/misra/no-c-style-or-functional-casts" and + ruleId = "RULE-8-2-2" and + category = "required" + or + query = + // `Query` instance for the `intToPointerCastProhibited` query + Conversions2Package::intToPointerCastProhibitedQuery() and + queryId = + // `@id` for the `intToPointerCastProhibited` query + "cpp/misra/int-to-pointer-cast-prohibited" and + ruleId = "RULE-8-2-6" and + category = "required" + or + query = + // `Query` instance for the `noPointerToIntegralCast` query + Conversions2Package::noPointerToIntegralCastQuery() and + queryId = + // `@id` for the `noPointerToIntegralCast` query + "cpp/misra/no-pointer-to-integral-cast" and + ruleId = "RULE-8-2-7" and + category = "advisory" + or + query = + // `Query` instance for the `pointerToIntegralCast` query + Conversions2Package::pointerToIntegralCastQuery() and + queryId = + // `@id` for the `pointerToIntegralCast` query + "cpp/misra/pointer-to-integral-cast" and + ruleId = "RULE-8-2-8" and + category = "required" + or + query = + // `Query` instance for the `noStandaloneTypeCastExpression` query + Conversions2Package::noStandaloneTypeCastExpressionQuery() and + queryId = + // `@id` for the `noStandaloneTypeCastExpression` query + "cpp/misra/no-standalone-type-cast-expression" and + ruleId = "RULE-9-2-1" and + category = "required" +} + +module Conversions2Package { + Query virtualBaseClassCastToDerivedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `virtualBaseClassCastToDerived` query + TQueryCPP(TConversions2PackageQuery(TVirtualBaseClassCastToDerivedQuery())) + } + + Query noCStyleOrFunctionalCastsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noCStyleOrFunctionalCasts` query + TQueryCPP(TConversions2PackageQuery(TNoCStyleOrFunctionalCastsQuery())) + } + + Query intToPointerCastProhibitedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `intToPointerCastProhibited` query + TQueryCPP(TConversions2PackageQuery(TIntToPointerCastProhibitedQuery())) + } + + Query noPointerToIntegralCastQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noPointerToIntegralCast` query + TQueryCPP(TConversions2PackageQuery(TNoPointerToIntegralCastQuery())) + } + + Query pointerToIntegralCastQuery() { + //autogenerate `Query` type + result = + // `Query` type for `pointerToIntegralCast` query + TQueryCPP(TConversions2PackageQuery(TPointerToIntegralCastQuery())) + } + + Query noStandaloneTypeCastExpressionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noStandaloneTypeCastExpression` query + TQueryCPP(TConversions2PackageQuery(TNoStandaloneTypeCastExpressionQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/DeadCode.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/DeadCode.qll index 40b8795e5e..f11741fde5 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/DeadCode.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/DeadCode.qll @@ -12,6 +12,7 @@ newtype DeadCodeQuery = TUnusedTypeDeclarationsQuery() or TUnreachableCodeQuery() or TUnusedFunctionQuery() or + TUnusedSplMemberFunctionQuery() or TInfeasiblePathQuery() or TUnusedLocalVariableQuery() or TUnusedGlobalOrNamespaceVariableQuery() or @@ -94,6 +95,15 @@ predicate isDeadCodeQueryMetadata(Query query, string queryId, string ruleId, st ruleId = "M0-1-10" and category = "advisory" or + query = + // `Query` instance for the `unusedSplMemberFunction` query + DeadCodePackage::unusedSplMemberFunctionQuery() and + queryId = + // `@id` for the `unusedSplMemberFunction` query + "cpp/autosar/unused-spl-member-function" and + ruleId = "M0-1-10" and + category = "advisory" + or query = // `Query` instance for the `infeasiblePath` query DeadCodePackage::infeasiblePathQuery() and @@ -224,6 +234,13 @@ module DeadCodePackage { TQueryCPP(TDeadCodePackageQuery(TUnusedFunctionQuery())) } + Query unusedSplMemberFunctionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unusedSplMemberFunction` query + TQueryCPP(TDeadCodePackageQuery(TUnusedSplMemberFunctionQuery())) + } + Query infeasiblePathQuery() { //autogenerate `Query` type result = diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/FloatingPoint.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/FloatingPoint.qll new file mode 100644 index 0000000000..0ff7a07214 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/FloatingPoint.qll @@ -0,0 +1,44 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype FloatingPointQuery = + TPossibleMisuseOfInfiniteFloatingPointValueQuery() or + TPossibleMisuseOfNaNFloatingPointValueQuery() + +predicate isFloatingPointQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `possibleMisuseOfInfiniteFloatingPointValue` query + FloatingPointPackage::possibleMisuseOfInfiniteFloatingPointValueQuery() and + queryId = + // `@id` for the `possibleMisuseOfInfiniteFloatingPointValue` query + "cpp/misra/possible-misuse-of-infinite-floating-point-value" and + ruleId = "DIR-0-3-1" and + category = "advisory" + or + query = + // `Query` instance for the `possibleMisuseOfNaNFloatingPointValue` query + FloatingPointPackage::possibleMisuseOfNaNFloatingPointValueQuery() and + queryId = + // `@id` for the `possibleMisuseOfNaNFloatingPointValue` query + "cpp/misra/possible-misuse-of-nan-floating-point-value" and + ruleId = "DIR-0-3-1" and + category = "advisory" +} + +module FloatingPointPackage { + Query possibleMisuseOfInfiniteFloatingPointValueQuery() { + //autogenerate `Query` type + result = + // `Query` type for `possibleMisuseOfInfiniteFloatingPointValue` query + TQueryCPP(TFloatingPointPackageQuery(TPossibleMisuseOfInfiniteFloatingPointValueQuery())) + } + + Query possibleMisuseOfNaNFloatingPointValueQuery() { + //autogenerate `Query` type + result = + // `Query` type for `possibleMisuseOfNaNFloatingPointValue` query + TQueryCPP(TFloatingPointPackageQuery(TPossibleMisuseOfNaNFloatingPointValueQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/ImportMisra23.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/ImportMisra23.qll new file mode 100644 index 0000000000..d31affb27c --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/ImportMisra23.qll @@ -0,0 +1,1438 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype ImportMisra23Query = + TSectionsOfCodeShouldNotBeCommentedOutQuery() or + TOneDefinitionRuleViolatedQuery() or + TVariableDeclaredInInnerScopeHidesOuterScopeQuery() or + TObjectAccessedBeforeLifetimeMisraQuery() or + TObjectAccessedAfterLifetimeMisraQuery() or + TCastRemovesConstOrVolatileFromPointerOrReferenceQuery() or + TIfElseIfEndConditionQuery() or + TGotoShallJumpToLabelDeclaredLaterInTheFunctionQuery() or + TFunctionDeclaredWithTheNoreturnAttributeReturnQuery() or + TNonVoidFunctionShallReturnAValueOnAllPathsQuery() or + TDeclarationOfAnObjectIndirectionsLevelQuery() or + THandlersReferToNonStaticMembersFromTheirClassQuery() or + TIncludeDirectivesPrecededByPreprocessorDirectivesQuery() or + TIdentifiersUsedInTheControllingExpressionOfQuery() or + TCharsThatShouldNotOccurInHeaderFileNameQuery() or + TAndPreprocessorOperatorsShouldNotBeUsedQuery() or + TTokensThatLookLikeDirectivesInAMacroArgumentQuery() or + TPointerToAnIncompleteClassTypeDeletedQuery() or + TPointersReturnedByLocaleFunctionsMustBeUsedAsConstQuery() or + TCallToSetlocaleInvalidatesOldPointersMisraQuery() or + TCallToSetlocaleInvalidatesOldPointersWarnMisraQuery() or + TObjectUsedWhileInPotentiallyMovedFromStateQuery() or + TReadsAndWritesOnStreamNotSeparatedByPositioningQuery() or + TCommaOperatorShouldNotBeUsedQuery() or + TCopyAndMoveAssignmentsShallHandleSelfAssignmentQuery() or + TUseSingleLocalDeclaratorsQuery() or + TUseSingleGlobalOrMemberDeclaratorsQuery() or + TEnumerationNotDefinedWithAnExplicitUnderlyingTypeQuery() or + TAsmDeclarationShallNotBeUsedQuery() or + TNonUniqueEnumerationConstantQuery() or + TBitFieldShallHaveAnAppropriateTypeQuery() or + TSignedIntegerNamedBitFieldHaveALengthOfOneBitQuery() or + TVirtualAndNonVirtualClassInTheHierarchyQuery() or + TOverridingShallSpecifyDifferentDefaultArgumentsQuery() or + TPotentiallyVirtualPointerOnlyComparesToNullptrQuery() or + TObjectsDynamicTypeUsedFromConstructorOrDestructorQuery() or + TInitializeAllVirtualBaseClassesQuery() or + TInitializerListConstructorIsTheOnlyConstructorQuery() or + TAddressOfOperatorOverloadedQuery() or + TFunctionTemplatesExplicitlySpecializedQuery() or + TExceptionObjectHavePointerTypeQuery() or + TEmptyThrowOnlyWithinACatchHandlerQuery() or + TNoexceptFunctionShouldNotPropagateToTheCallerQuery() or + TFunctionLikeMacrosDefinedQuery() or + TMacroParameterFollowingHashQuery() or + TAMixedUseMacroArgumentSubjectToExpansionQuery() or + TCsignalFacilitiesUsedQuery() or + TCsignalTypesShallNotBeUsedQuery() or + TAtofAtoiAtolAndAtollUsedQuery() or + TMacroOffsetofShallNotBeUsedQuery() or + TGlobalSizedOperatorDeleteShallBeDefinedQuery() or + TGlobalUnsizedOperatorDeleteShallBeDefinedQuery() or + TVectorShouldNotBeSpecializedWithBoolQuery() or + TForwardingReferencesAndForwardNotUsedTogetherQuery() or + TCstdioFunctionsShallNotBeUsedQuery() or + TCstdioMacrosShallNotBeUsedQuery() or + TCstdioTypesShallNotBeUsedQuery() or + TBackslashCharacterMisuseQuery() or + TNonTerminatedEscapeSequencesQuery() or + TOctalConstantsUsedQuery() or + TUnsignedIntegerLiteralsNotAppropriatelySuffixedQuery() or + TLowercaseLStartsInLiteralSuffixQuery() or + TCharacterSequenceUsedWithinACStyleCommentQuery() or + TLineSplicingUsedInCommentsQuery() or + TGlobalNamespaceDeclarationsQuery() or + TNonGlobalFunctionMainQuery() or + TInheritedNonOverridableMemberFunctionQuery() or + TInheritedOverridableMemberFunctionQuery() or + TDefinitionShallBeConsideredForUnqualifiedLookupQuery() or + TNameShallBeReferredUsingAQualifiedIdOrThisQuery() or + TNameShallBeReferredUsingAQualifiedIdOrThisAuditQuery() or + TReturnReferenceOrPointerToAutomaticLocalVariableQuery() or + TNullptrNotTheOnlyFormOfTheNullPointerConstantQuery() or + TArrayPassedAsFunctionArgumentDecayToAPointerQuery() or + TResultOfAnAssignmentOperatorShouldNotBeUsedQuery() or + TFunctionsCallThemselvesEitherDirectlyOrIndirectlyQuery() or + TCastsBetweenAPointerToFunctionAndAnyOtherTypeQuery() or + TReinterpretCastShallNotBeUsedQuery() or + TUnsignedOperationWithConstantOperandsWrapsQuery() or + TBuiltInUnaryOperatorAppliedToUnsignedExpressionQuery() or + TSwitchBodyCompoundConditionQuery() or + TLoopBodyCompoundConditionQuery() or + TGotoStatementShouldNotBeUsedQuery() or + TGotoReferenceALabelInSurroundingBlockQuery() + +predicate isImportMisra23QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `sectionsOfCodeShouldNotBeCommentedOut` query + ImportMisra23Package::sectionsOfCodeShouldNotBeCommentedOutQuery() and + queryId = + // `@id` for the `sectionsOfCodeShouldNotBeCommentedOut` query + "cpp/misra/sections-of-code-should-not-be-commented-out" and + ruleId = "DIR-5-7-2" and + category = "advisory" + or + query = + // `Query` instance for the `oneDefinitionRuleViolated` query + ImportMisra23Package::oneDefinitionRuleViolatedQuery() and + queryId = + // `@id` for the `oneDefinitionRuleViolated` query + "cpp/misra/one-definition-rule-violated" and + ruleId = "RULE-6-2-1" and + category = "required" + or + query = + // `Query` instance for the `variableDeclaredInInnerScopeHidesOuterScope` query + ImportMisra23Package::variableDeclaredInInnerScopeHidesOuterScopeQuery() and + queryId = + // `@id` for the `variableDeclaredInInnerScopeHidesOuterScope` query + "cpp/misra/variable-declared-in-inner-scope-hides-outer-scope" and + ruleId = "RULE-6-4-1" and + category = "required" + or + query = + // `Query` instance for the `objectAccessedBeforeLifetimeMisra` query + ImportMisra23Package::objectAccessedBeforeLifetimeMisraQuery() and + queryId = + // `@id` for the `objectAccessedBeforeLifetimeMisra` query + "cpp/misra/object-accessed-before-lifetime-misra" and + ruleId = "RULE-6-8-1" and + category = "required" + or + query = + // `Query` instance for the `objectAccessedAfterLifetimeMisra` query + ImportMisra23Package::objectAccessedAfterLifetimeMisraQuery() and + queryId = + // `@id` for the `objectAccessedAfterLifetimeMisra` query + "cpp/misra/object-accessed-after-lifetime-misra" and + ruleId = "RULE-6-8-1" and + category = "required" + or + query = + // `Query` instance for the `castRemovesConstOrVolatileFromPointerOrReference` query + ImportMisra23Package::castRemovesConstOrVolatileFromPointerOrReferenceQuery() and + queryId = + // `@id` for the `castRemovesConstOrVolatileFromPointerOrReference` query + "cpp/misra/cast-removes-const-or-volatile-from-pointer-or-reference" and + ruleId = "RULE-8-2-3" and + category = "required" + or + query = + // `Query` instance for the `ifElseIfEndCondition` query + ImportMisra23Package::ifElseIfEndConditionQuery() and + queryId = + // `@id` for the `ifElseIfEndCondition` query + "cpp/misra/if-else-if-end-condition" and + ruleId = "RULE-9-4-1" and + category = "required" + or + query = + // `Query` instance for the `gotoShallJumpToLabelDeclaredLaterInTheFunction` query + ImportMisra23Package::gotoShallJumpToLabelDeclaredLaterInTheFunctionQuery() and + queryId = + // `@id` for the `gotoShallJumpToLabelDeclaredLaterInTheFunction` query + "cpp/misra/goto-shall-jump-to-label-declared-later-in-the-function" and + ruleId = "RULE-9-6-3" and + category = "required" + or + query = + // `Query` instance for the `functionDeclaredWithTheNoreturnAttributeReturn` query + ImportMisra23Package::functionDeclaredWithTheNoreturnAttributeReturnQuery() and + queryId = + // `@id` for the `functionDeclaredWithTheNoreturnAttributeReturn` query + "cpp/misra/function-declared-with-the-noreturn-attribute-return" and + ruleId = "RULE-9-6-4" and + category = "required" + or + query = + // `Query` instance for the `nonVoidFunctionShallReturnAValueOnAllPaths` query + ImportMisra23Package::nonVoidFunctionShallReturnAValueOnAllPathsQuery() and + queryId = + // `@id` for the `nonVoidFunctionShallReturnAValueOnAllPaths` query + "cpp/misra/non-void-function-shall-return-a-value-on-all-paths" and + ruleId = "RULE-9-6-5" and + category = "required" + or + query = + // `Query` instance for the `declarationOfAnObjectIndirectionsLevel` query + ImportMisra23Package::declarationOfAnObjectIndirectionsLevelQuery() and + queryId = + // `@id` for the `declarationOfAnObjectIndirectionsLevel` query + "cpp/misra/declaration-of-an-object-indirections-level" and + ruleId = "RULE-11-3-2" and + category = "advisory" + or + query = + // `Query` instance for the `handlersReferToNonStaticMembersFromTheirClass` query + ImportMisra23Package::handlersReferToNonStaticMembersFromTheirClassQuery() and + queryId = + // `@id` for the `handlersReferToNonStaticMembersFromTheirClass` query + "cpp/misra/handlers-refer-to-non-static-members-from-their-class" and + ruleId = "RULE-18-3-3" and + category = "required" + or + query = + // `Query` instance for the `includeDirectivesPrecededByPreprocessorDirectives` query + ImportMisra23Package::includeDirectivesPrecededByPreprocessorDirectivesQuery() and + queryId = + // `@id` for the `includeDirectivesPrecededByPreprocessorDirectives` query + "cpp/misra/include-directives-preceded-by-preprocessor-directives" and + ruleId = "RULE-19-0-3" and + category = "advisory" + or + query = + // `Query` instance for the `identifiersUsedInTheControllingExpressionOf` query + ImportMisra23Package::identifiersUsedInTheControllingExpressionOfQuery() and + queryId = + // `@id` for the `identifiersUsedInTheControllingExpressionOf` query + "cpp/misra/identifiers-used-in-the-controlling-expression-of" and + ruleId = "RULE-19-1-3" and + category = "required" + or + query = + // `Query` instance for the `charsThatShouldNotOccurInHeaderFileName` query + ImportMisra23Package::charsThatShouldNotOccurInHeaderFileNameQuery() and + queryId = + // `@id` for the `charsThatShouldNotOccurInHeaderFileName` query + "cpp/misra/chars-that-should-not-occur-in-header-file-name" and + ruleId = "RULE-19-2-3" and + category = "required" + or + query = + // `Query` instance for the `andPreprocessorOperatorsShouldNotBeUsed` query + ImportMisra23Package::andPreprocessorOperatorsShouldNotBeUsedQuery() and + queryId = + // `@id` for the `andPreprocessorOperatorsShouldNotBeUsed` query + "cpp/misra/and-preprocessor-operators-should-not-be-used" and + ruleId = "RULE-19-3-1" and + category = "advisory" + or + query = + // `Query` instance for the `tokensThatLookLikeDirectivesInAMacroArgument` query + ImportMisra23Package::tokensThatLookLikeDirectivesInAMacroArgumentQuery() and + queryId = + // `@id` for the `tokensThatLookLikeDirectivesInAMacroArgument` query + "cpp/misra/tokens-that-look-like-directives-in-a-macro-argument" and + ruleId = "RULE-19-3-5" and + category = "required" + or + query = + // `Query` instance for the `pointerToAnIncompleteClassTypeDeleted` query + ImportMisra23Package::pointerToAnIncompleteClassTypeDeletedQuery() and + queryId = + // `@id` for the `pointerToAnIncompleteClassTypeDeleted` query + "cpp/misra/pointer-to-an-incomplete-class-type-deleted" and + ruleId = "RULE-21-6-5" and + category = "required" + or + query = + // `Query` instance for the `pointersReturnedByLocaleFunctionsMustBeUsedAsConst` query + ImportMisra23Package::pointersReturnedByLocaleFunctionsMustBeUsedAsConstQuery() and + queryId = + // `@id` for the `pointersReturnedByLocaleFunctionsMustBeUsedAsConst` query + "cpp/misra/pointers-returned-by-locale-functions-must-be-used-as-const" and + ruleId = "RULE-25-5-2" and + category = "mandatory" + or + query = + // `Query` instance for the `callToSetlocaleInvalidatesOldPointersMisra` query + ImportMisra23Package::callToSetlocaleInvalidatesOldPointersMisraQuery() and + queryId = + // `@id` for the `callToSetlocaleInvalidatesOldPointersMisra` query + "cpp/misra/call-to-setlocale-invalidates-old-pointers-misra" and + ruleId = "RULE-25-5-3" and + category = "mandatory" + or + query = + // `Query` instance for the `callToSetlocaleInvalidatesOldPointersWarnMisra` query + ImportMisra23Package::callToSetlocaleInvalidatesOldPointersWarnMisraQuery() and + queryId = + // `@id` for the `callToSetlocaleInvalidatesOldPointersWarnMisra` query + "cpp/misra/call-to-setlocale-invalidates-old-pointers-warn-misra" and + ruleId = "RULE-25-5-3" and + category = "mandatory" + or + query = + // `Query` instance for the `objectUsedWhileInPotentiallyMovedFromState` query + ImportMisra23Package::objectUsedWhileInPotentiallyMovedFromStateQuery() and + queryId = + // `@id` for the `objectUsedWhileInPotentiallyMovedFromState` query + "cpp/misra/object-used-while-in-potentially-moved-from-state" and + ruleId = "RULE-28-6-3" and + category = "required" + or + query = + // `Query` instance for the `readsAndWritesOnStreamNotSeparatedByPositioning` query + ImportMisra23Package::readsAndWritesOnStreamNotSeparatedByPositioningQuery() and + queryId = + // `@id` for the `readsAndWritesOnStreamNotSeparatedByPositioning` query + "cpp/misra/reads-and-writes-on-stream-not-separated-by-positioning" and + ruleId = "RULE-30-0-2" and + category = "required" + or + query = + // `Query` instance for the `commaOperatorShouldNotBeUsed` query + ImportMisra23Package::commaOperatorShouldNotBeUsedQuery() and + queryId = + // `@id` for the `commaOperatorShouldNotBeUsed` query + "cpp/misra/comma-operator-should-not-be-used" and + ruleId = "RULE-8-19-1" and + category = "advisory" + or + query = + // `Query` instance for the `copyAndMoveAssignmentsShallHandleSelfAssignment` query + ImportMisra23Package::copyAndMoveAssignmentsShallHandleSelfAssignmentQuery() and + queryId = + // `@id` for the `copyAndMoveAssignmentsShallHandleSelfAssignment` query + "cpp/misra/copy-and-move-assignments-shall-handle-self-assignment" and + ruleId = "DIR-15-8-1" and + category = "required" + or + query = + // `Query` instance for the `useSingleLocalDeclarators` query + ImportMisra23Package::useSingleLocalDeclaratorsQuery() and + queryId = + // `@id` for the `useSingleLocalDeclarators` query + "cpp/misra/use-single-local-declarators" and + ruleId = "RULE-10-0-1" and + category = "advisory" + or + query = + // `Query` instance for the `useSingleGlobalOrMemberDeclarators` query + ImportMisra23Package::useSingleGlobalOrMemberDeclaratorsQuery() and + queryId = + // `@id` for the `useSingleGlobalOrMemberDeclarators` query + "cpp/misra/use-single-global-or-member-declarators" and + ruleId = "RULE-10-0-1" and + category = "advisory" + or + query = + // `Query` instance for the `enumerationNotDefinedWithAnExplicitUnderlyingType` query + ImportMisra23Package::enumerationNotDefinedWithAnExplicitUnderlyingTypeQuery() and + queryId = + // `@id` for the `enumerationNotDefinedWithAnExplicitUnderlyingType` query + "cpp/misra/enumeration-not-defined-with-an-explicit-underlying-type" and + ruleId = "RULE-10-2-1" and + category = "required" + or + query = + // `Query` instance for the `asmDeclarationShallNotBeUsed` query + ImportMisra23Package::asmDeclarationShallNotBeUsedQuery() and + queryId = + // `@id` for the `asmDeclarationShallNotBeUsed` query + "cpp/misra/asm-declaration-shall-not-be-used" and + ruleId = "RULE-10-4-1" and + category = "required" + or + query = + // `Query` instance for the `nonUniqueEnumerationConstant` query + ImportMisra23Package::nonUniqueEnumerationConstantQuery() and + queryId = + // `@id` for the `nonUniqueEnumerationConstant` query + "cpp/misra/non-unique-enumeration-constant" and + ruleId = "RULE-11-6-3" and + category = "required" + or + query = + // `Query` instance for the `bitFieldShallHaveAnAppropriateType` query + ImportMisra23Package::bitFieldShallHaveAnAppropriateTypeQuery() and + queryId = + // `@id` for the `bitFieldShallHaveAnAppropriateType` query + "cpp/misra/bit-field-shall-have-an-appropriate-type" and + ruleId = "RULE-12-2-2" and + category = "required" + or + query = + // `Query` instance for the `signedIntegerNamedBitFieldHaveALengthOfOneBit` query + ImportMisra23Package::signedIntegerNamedBitFieldHaveALengthOfOneBitQuery() and + queryId = + // `@id` for the `signedIntegerNamedBitFieldHaveALengthOfOneBit` query + "cpp/misra/signed-integer-named-bit-field-have-a-length-of-one-bit" and + ruleId = "RULE-12-2-3" and + category = "required" + or + query = + // `Query` instance for the `virtualAndNonVirtualClassInTheHierarchy` query + ImportMisra23Package::virtualAndNonVirtualClassInTheHierarchyQuery() and + queryId = + // `@id` for the `virtualAndNonVirtualClassInTheHierarchy` query + "cpp/misra/virtual-and-non-virtual-class-in-the-hierarchy" and + ruleId = "RULE-13-1-2" and + category = "required" + or + query = + // `Query` instance for the `overridingShallSpecifyDifferentDefaultArguments` query + ImportMisra23Package::overridingShallSpecifyDifferentDefaultArgumentsQuery() and + queryId = + // `@id` for the `overridingShallSpecifyDifferentDefaultArguments` query + "cpp/misra/overriding-shall-specify-different-default-arguments" and + ruleId = "RULE-13-3-2" and + category = "required" + or + query = + // `Query` instance for the `potentiallyVirtualPointerOnlyComparesToNullptr` query + ImportMisra23Package::potentiallyVirtualPointerOnlyComparesToNullptrQuery() and + queryId = + // `@id` for the `potentiallyVirtualPointerOnlyComparesToNullptr` query + "cpp/misra/potentially-virtual-pointer-only-compares-to-nullptr" and + ruleId = "RULE-13-3-4" and + category = "required" + or + query = + // `Query` instance for the `objectsDynamicTypeUsedFromConstructorOrDestructor` query + ImportMisra23Package::objectsDynamicTypeUsedFromConstructorOrDestructorQuery() and + queryId = + // `@id` for the `objectsDynamicTypeUsedFromConstructorOrDestructor` query + "cpp/misra/objects-dynamic-type-used-from-constructor-or-destructor" and + ruleId = "RULE-15-1-1" and + category = "required" + or + query = + // `Query` instance for the `initializeAllVirtualBaseClasses` query + ImportMisra23Package::initializeAllVirtualBaseClassesQuery() and + queryId = + // `@id` for the `initializeAllVirtualBaseClasses` query + "cpp/misra/initialize-all-virtual-base-classes" and + ruleId = "RULE-15-1-2" and + category = "advisory" + or + query = + // `Query` instance for the `initializerListConstructorIsTheOnlyConstructor` query + ImportMisra23Package::initializerListConstructorIsTheOnlyConstructorQuery() and + queryId = + // `@id` for the `initializerListConstructorIsTheOnlyConstructor` query + "cpp/misra/initializer-list-constructor-is-the-only-constructor" and + ruleId = "RULE-15-1-5" and + category = "required" + or + query = + // `Query` instance for the `addressOfOperatorOverloaded` query + ImportMisra23Package::addressOfOperatorOverloadedQuery() and + queryId = + // `@id` for the `addressOfOperatorOverloaded` query + "cpp/misra/address-of-operator-overloaded" and + ruleId = "RULE-16-5-2" and + category = "required" + or + query = + // `Query` instance for the `functionTemplatesExplicitlySpecialized` query + ImportMisra23Package::functionTemplatesExplicitlySpecializedQuery() and + queryId = + // `@id` for the `functionTemplatesExplicitlySpecialized` query + "cpp/misra/function-templates-explicitly-specialized" and + ruleId = "RULE-17-8-1" and + category = "required" + or + query = + // `Query` instance for the `exceptionObjectHavePointerType` query + ImportMisra23Package::exceptionObjectHavePointerTypeQuery() and + queryId = + // `@id` for the `exceptionObjectHavePointerType` query + "cpp/misra/exception-object-have-pointer-type" and + ruleId = "RULE-18-1-1" and + category = "required" + or + query = + // `Query` instance for the `emptyThrowOnlyWithinACatchHandler` query + ImportMisra23Package::emptyThrowOnlyWithinACatchHandlerQuery() and + queryId = + // `@id` for the `emptyThrowOnlyWithinACatchHandler` query + "cpp/misra/empty-throw-only-within-a-catch-handler" and + ruleId = "RULE-18-1-2" and + category = "required" + or + query = + // `Query` instance for the `noexceptFunctionShouldNotPropagateToTheCaller` query + ImportMisra23Package::noexceptFunctionShouldNotPropagateToTheCallerQuery() and + queryId = + // `@id` for the `noexceptFunctionShouldNotPropagateToTheCaller` query + "cpp/misra/noexcept-function-should-not-propagate-to-the-caller" and + ruleId = "RULE-18-5-1" and + category = "advisory" + or + query = + // `Query` instance for the `functionLikeMacrosDefined` query + ImportMisra23Package::functionLikeMacrosDefinedQuery() and + queryId = + // `@id` for the `functionLikeMacrosDefined` query + "cpp/misra/function-like-macros-defined" and + ruleId = "RULE-19-0-2" and + category = "required" + or + query = + // `Query` instance for the `macroParameterFollowingHash` query + ImportMisra23Package::macroParameterFollowingHashQuery() and + queryId = + // `@id` for the `macroParameterFollowingHash` query + "cpp/misra/macro-parameter-following-hash" and + ruleId = "RULE-19-3-2" and + category = "required" + or + query = + // `Query` instance for the `aMixedUseMacroArgumentSubjectToExpansion` query + ImportMisra23Package::aMixedUseMacroArgumentSubjectToExpansionQuery() and + queryId = + // `@id` for the `aMixedUseMacroArgumentSubjectToExpansion` query + "cpp/misra/a-mixed-use-macro-argument-subject-to-expansion" and + ruleId = "RULE-19-3-3" and + category = "required" + or + query = + // `Query` instance for the `csignalFacilitiesUsed` query + ImportMisra23Package::csignalFacilitiesUsedQuery() and + queryId = + // `@id` for the `csignalFacilitiesUsed` query + "cpp/misra/csignal-facilities-used" and + ruleId = "RULE-21-10-3" and + category = "required" + or + query = + // `Query` instance for the `csignalTypesShallNotBeUsed` query + ImportMisra23Package::csignalTypesShallNotBeUsedQuery() and + queryId = + // `@id` for the `csignalTypesShallNotBeUsed` query + "cpp/misra/csignal-types-shall-not-be-used" and + ruleId = "RULE-21-10-3" and + category = "required" + or + query = + // `Query` instance for the `atofAtoiAtolAndAtollUsed` query + ImportMisra23Package::atofAtoiAtolAndAtollUsedQuery() and + queryId = + // `@id` for the `atofAtoiAtolAndAtollUsed` query + "cpp/misra/atof-atoi-atol-and-atoll-used" and + ruleId = "RULE-21-2-1" and + category = "required" + or + query = + // `Query` instance for the `macroOffsetofShallNotBeUsed` query + ImportMisra23Package::macroOffsetofShallNotBeUsedQuery() and + queryId = + // `@id` for the `macroOffsetofShallNotBeUsed` query + "cpp/misra/macro-offsetof-shall-not-be-used" and + ruleId = "RULE-21-2-4" and + category = "required" + or + query = + // `Query` instance for the `globalSizedOperatorDeleteShallBeDefined` query + ImportMisra23Package::globalSizedOperatorDeleteShallBeDefinedQuery() and + queryId = + // `@id` for the `globalSizedOperatorDeleteShallBeDefined` query + "cpp/misra/global-sized-operator-delete-shall-be-defined" and + ruleId = "RULE-21-6-4" and + category = "required" + or + query = + // `Query` instance for the `globalUnsizedOperatorDeleteShallBeDefined` query + ImportMisra23Package::globalUnsizedOperatorDeleteShallBeDefinedQuery() and + queryId = + // `@id` for the `globalUnsizedOperatorDeleteShallBeDefined` query + "cpp/misra/global-unsized-operator-delete-shall-be-defined" and + ruleId = "RULE-21-6-4" and + category = "required" + or + query = + // `Query` instance for the `vectorShouldNotBeSpecializedWithBool` query + ImportMisra23Package::vectorShouldNotBeSpecializedWithBoolQuery() and + queryId = + // `@id` for the `vectorShouldNotBeSpecializedWithBool` query + "cpp/misra/vector-should-not-be-specialized-with-bool" and + ruleId = "RULE-26-3-1" and + category = "advisory" + or + query = + // `Query` instance for the `forwardingReferencesAndForwardNotUsedTogether` query + ImportMisra23Package::forwardingReferencesAndForwardNotUsedTogetherQuery() and + queryId = + // `@id` for the `forwardingReferencesAndForwardNotUsedTogether` query + "cpp/misra/forwarding-references-and-forward-not-used-together" and + ruleId = "RULE-28-6-2" and + category = "required" + or + query = + // `Query` instance for the `cstdioFunctionsShallNotBeUsed` query + ImportMisra23Package::cstdioFunctionsShallNotBeUsedQuery() and + queryId = + // `@id` for the `cstdioFunctionsShallNotBeUsed` query + "cpp/misra/cstdio-functions-shall-not-be-used" and + ruleId = "RULE-30-0-1" and + category = "required" + or + query = + // `Query` instance for the `cstdioMacrosShallNotBeUsed` query + ImportMisra23Package::cstdioMacrosShallNotBeUsedQuery() and + queryId = + // `@id` for the `cstdioMacrosShallNotBeUsed` query + "cpp/misra/cstdio-macros-shall-not-be-used" and + ruleId = "RULE-30-0-1" and + category = "required" + or + query = + // `Query` instance for the `cstdioTypesShallNotBeUsed` query + ImportMisra23Package::cstdioTypesShallNotBeUsedQuery() and + queryId = + // `@id` for the `cstdioTypesShallNotBeUsed` query + "cpp/misra/cstdio-types-shall-not-be-used" and + ruleId = "RULE-30-0-1" and + category = "required" + or + query = + // `Query` instance for the `backslashCharacterMisuse` query + ImportMisra23Package::backslashCharacterMisuseQuery() and + queryId = + // `@id` for the `backslashCharacterMisuse` query + "cpp/misra/backslash-character-misuse" and + ruleId = "RULE-5-13-1" and + category = "required" + or + query = + // `Query` instance for the `nonTerminatedEscapeSequences` query + ImportMisra23Package::nonTerminatedEscapeSequencesQuery() and + queryId = + // `@id` for the `nonTerminatedEscapeSequences` query + "cpp/misra/non-terminated-escape-sequences" and + ruleId = "RULE-5-13-2" and + category = "required" + or + query = + // `Query` instance for the `octalConstantsUsed` query + ImportMisra23Package::octalConstantsUsedQuery() and + queryId = + // `@id` for the `octalConstantsUsed` query + "cpp/misra/octal-constants-used" and + ruleId = "RULE-5-13-3" and + category = "required" + or + query = + // `Query` instance for the `unsignedIntegerLiteralsNotAppropriatelySuffixed` query + ImportMisra23Package::unsignedIntegerLiteralsNotAppropriatelySuffixedQuery() and + queryId = + // `@id` for the `unsignedIntegerLiteralsNotAppropriatelySuffixed` query + "cpp/misra/unsigned-integer-literals-not-appropriately-suffixed" and + ruleId = "RULE-5-13-4" and + category = "required" + or + query = + // `Query` instance for the `lowercaseLStartsInLiteralSuffix` query + ImportMisra23Package::lowercaseLStartsInLiteralSuffixQuery() and + queryId = + // `@id` for the `lowercaseLStartsInLiteralSuffix` query + "cpp/misra/lowercase-l-starts-in-literal-suffix" and + ruleId = "RULE-5-13-5" and + category = "required" + or + query = + // `Query` instance for the `characterSequenceUsedWithinACStyleComment` query + ImportMisra23Package::characterSequenceUsedWithinACStyleCommentQuery() and + queryId = + // `@id` for the `characterSequenceUsedWithinACStyleComment` query + "cpp/misra/character-sequence-used-within-ac-style-comment" and + ruleId = "RULE-5-7-1" and + category = "required" + or + query = + // `Query` instance for the `lineSplicingUsedInComments` query + ImportMisra23Package::lineSplicingUsedInCommentsQuery() and + queryId = + // `@id` for the `lineSplicingUsedInComments` query + "cpp/misra/line-splicing-used-in-comments" and + ruleId = "RULE-5-7-3" and + category = "required" + or + query = + // `Query` instance for the `globalNamespaceDeclarations` query + ImportMisra23Package::globalNamespaceDeclarationsQuery() and + queryId = + // `@id` for the `globalNamespaceDeclarations` query + "cpp/misra/global-namespace-declarations" and + ruleId = "RULE-6-0-3" and + category = "advisory" + or + query = + // `Query` instance for the `nonGlobalFunctionMain` query + ImportMisra23Package::nonGlobalFunctionMainQuery() and + queryId = + // `@id` for the `nonGlobalFunctionMain` query + "cpp/misra/non-global-function-main" and + ruleId = "RULE-6-0-4" and + category = "required" + or + query = + // `Query` instance for the `inheritedNonOverridableMemberFunction` query + ImportMisra23Package::inheritedNonOverridableMemberFunctionQuery() and + queryId = + // `@id` for the `inheritedNonOverridableMemberFunction` query + "cpp/misra/inherited-non-overridable-member-function" and + ruleId = "RULE-6-4-2" and + category = "required" + or + query = + // `Query` instance for the `inheritedOverridableMemberFunction` query + ImportMisra23Package::inheritedOverridableMemberFunctionQuery() and + queryId = + // `@id` for the `inheritedOverridableMemberFunction` query + "cpp/misra/inherited-overridable-member-function" and + ruleId = "RULE-6-4-2" and + category = "required" + or + query = + // `Query` instance for the `definitionShallBeConsideredForUnqualifiedLookup` query + ImportMisra23Package::definitionShallBeConsideredForUnqualifiedLookupQuery() and + queryId = + // `@id` for the `definitionShallBeConsideredForUnqualifiedLookup` query + "cpp/misra/definition-shall-be-considered-for-unqualified-lookup" and + ruleId = "RULE-6-4-2" and + category = "required" + or + query = + // `Query` instance for the `nameShallBeReferredUsingAQualifiedIdOrThis` query + ImportMisra23Package::nameShallBeReferredUsingAQualifiedIdOrThisQuery() and + queryId = + // `@id` for the `nameShallBeReferredUsingAQualifiedIdOrThis` query + "cpp/misra/name-shall-be-referred-using-a-qualified-id-or-this" and + ruleId = "RULE-6-4-3" and + category = "required" + or + query = + // `Query` instance for the `nameShallBeReferredUsingAQualifiedIdOrThisAudit` query + ImportMisra23Package::nameShallBeReferredUsingAQualifiedIdOrThisAuditQuery() and + queryId = + // `@id` for the `nameShallBeReferredUsingAQualifiedIdOrThisAudit` query + "cpp/misra/name-shall-be-referred-using-a-qualified-id-or-this-audit" and + ruleId = "RULE-6-4-3" and + category = "required" + or + query = + // `Query` instance for the `returnReferenceOrPointerToAutomaticLocalVariable` query + ImportMisra23Package::returnReferenceOrPointerToAutomaticLocalVariableQuery() and + queryId = + // `@id` for the `returnReferenceOrPointerToAutomaticLocalVariable` query + "cpp/misra/return-reference-or-pointer-to-automatic-local-variable" and + ruleId = "RULE-6-8-2" and + category = "mandatory" + or + query = + // `Query` instance for the `nullptrNotTheOnlyFormOfTheNullPointerConstant` query + ImportMisra23Package::nullptrNotTheOnlyFormOfTheNullPointerConstantQuery() and + queryId = + // `@id` for the `nullptrNotTheOnlyFormOfTheNullPointerConstant` query + "cpp/misra/nullptr-not-the-only-form-of-the-null-pointer-constant" and + ruleId = "RULE-7-11-1" and + category = "required" + or + query = + // `Query` instance for the `arrayPassedAsFunctionArgumentDecayToAPointer` query + ImportMisra23Package::arrayPassedAsFunctionArgumentDecayToAPointerQuery() and + queryId = + // `@id` for the `arrayPassedAsFunctionArgumentDecayToAPointer` query + "cpp/misra/array-passed-as-function-argument-decay-to-a-pointer" and + ruleId = "RULE-7-11-2" and + category = "required" + or + query = + // `Query` instance for the `resultOfAnAssignmentOperatorShouldNotBeUsed` query + ImportMisra23Package::resultOfAnAssignmentOperatorShouldNotBeUsedQuery() and + queryId = + // `@id` for the `resultOfAnAssignmentOperatorShouldNotBeUsed` query + "cpp/misra/result-of-an-assignment-operator-should-not-be-used" and + ruleId = "RULE-8-18-2" and + category = "advisory" + or + query = + // `Query` instance for the `functionsCallThemselvesEitherDirectlyOrIndirectly` query + ImportMisra23Package::functionsCallThemselvesEitherDirectlyOrIndirectlyQuery() and + queryId = + // `@id` for the `functionsCallThemselvesEitherDirectlyOrIndirectly` query + "cpp/misra/functions-call-themselves-either-directly-or-indirectly" and + ruleId = "RULE-8-2-10" and + category = "required" + or + query = + // `Query` instance for the `castsBetweenAPointerToFunctionAndAnyOtherType` query + ImportMisra23Package::castsBetweenAPointerToFunctionAndAnyOtherTypeQuery() and + queryId = + // `@id` for the `castsBetweenAPointerToFunctionAndAnyOtherType` query + "cpp/misra/casts-between-a-pointer-to-function-and-any-other-type" and + ruleId = "RULE-8-2-4" and + category = "required" + or + query = + // `Query` instance for the `reinterpretCastShallNotBeUsed` query + ImportMisra23Package::reinterpretCastShallNotBeUsedQuery() and + queryId = + // `@id` for the `reinterpretCastShallNotBeUsed` query + "cpp/misra/reinterpret-cast-shall-not-be-used" and + ruleId = "RULE-8-2-5" and + category = "required" + or + query = + // `Query` instance for the `unsignedOperationWithConstantOperandsWraps` query + ImportMisra23Package::unsignedOperationWithConstantOperandsWrapsQuery() and + queryId = + // `@id` for the `unsignedOperationWithConstantOperandsWraps` query + "cpp/misra/unsigned-operation-with-constant-operands-wraps" and + ruleId = "RULE-8-20-1" and + category = "advisory" + or + query = + // `Query` instance for the `builtInUnaryOperatorAppliedToUnsignedExpression` query + ImportMisra23Package::builtInUnaryOperatorAppliedToUnsignedExpressionQuery() and + queryId = + // `@id` for the `builtInUnaryOperatorAppliedToUnsignedExpression` query + "cpp/misra/built-in-unary-operator-applied-to-unsigned-expression" and + ruleId = "RULE-8-3-1" and + category = "advisory" + or + query = + // `Query` instance for the `switchBodyCompoundCondition` query + ImportMisra23Package::switchBodyCompoundConditionQuery() and + queryId = + // `@id` for the `switchBodyCompoundCondition` query + "cpp/misra/switch-body-compound-condition" and + ruleId = "RULE-9-3-1" and + category = "required" + or + query = + // `Query` instance for the `loopBodyCompoundCondition` query + ImportMisra23Package::loopBodyCompoundConditionQuery() and + queryId = + // `@id` for the `loopBodyCompoundCondition` query + "cpp/misra/loop-body-compound-condition" and + ruleId = "RULE-9-3-1" and + category = "required" + or + query = + // `Query` instance for the `gotoStatementShouldNotBeUsed` query + ImportMisra23Package::gotoStatementShouldNotBeUsedQuery() and + queryId = + // `@id` for the `gotoStatementShouldNotBeUsed` query + "cpp/misra/goto-statement-should-not-be-used" and + ruleId = "RULE-9-6-1" and + category = "advisory" + or + query = + // `Query` instance for the `gotoReferenceALabelInSurroundingBlock` query + ImportMisra23Package::gotoReferenceALabelInSurroundingBlockQuery() and + queryId = + // `@id` for the `gotoReferenceALabelInSurroundingBlock` query + "cpp/misra/goto-reference-a-label-in-surrounding-block" and + ruleId = "RULE-9-6-2" and + category = "required" +} + +module ImportMisra23Package { + Query sectionsOfCodeShouldNotBeCommentedOutQuery() { + //autogenerate `Query` type + result = + // `Query` type for `sectionsOfCodeShouldNotBeCommentedOut` query + TQueryCPP(TImportMisra23PackageQuery(TSectionsOfCodeShouldNotBeCommentedOutQuery())) + } + + Query oneDefinitionRuleViolatedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `oneDefinitionRuleViolated` query + TQueryCPP(TImportMisra23PackageQuery(TOneDefinitionRuleViolatedQuery())) + } + + Query variableDeclaredInInnerScopeHidesOuterScopeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `variableDeclaredInInnerScopeHidesOuterScope` query + TQueryCPP(TImportMisra23PackageQuery(TVariableDeclaredInInnerScopeHidesOuterScopeQuery())) + } + + Query objectAccessedBeforeLifetimeMisraQuery() { + //autogenerate `Query` type + result = + // `Query` type for `objectAccessedBeforeLifetimeMisra` query + TQueryCPP(TImportMisra23PackageQuery(TObjectAccessedBeforeLifetimeMisraQuery())) + } + + Query objectAccessedAfterLifetimeMisraQuery() { + //autogenerate `Query` type + result = + // `Query` type for `objectAccessedAfterLifetimeMisra` query + TQueryCPP(TImportMisra23PackageQuery(TObjectAccessedAfterLifetimeMisraQuery())) + } + + Query castRemovesConstOrVolatileFromPointerOrReferenceQuery() { + //autogenerate `Query` type + result = + // `Query` type for `castRemovesConstOrVolatileFromPointerOrReference` query + TQueryCPP(TImportMisra23PackageQuery(TCastRemovesConstOrVolatileFromPointerOrReferenceQuery())) + } + + Query ifElseIfEndConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `ifElseIfEndCondition` query + TQueryCPP(TImportMisra23PackageQuery(TIfElseIfEndConditionQuery())) + } + + Query gotoShallJumpToLabelDeclaredLaterInTheFunctionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `gotoShallJumpToLabelDeclaredLaterInTheFunction` query + TQueryCPP(TImportMisra23PackageQuery(TGotoShallJumpToLabelDeclaredLaterInTheFunctionQuery())) + } + + Query functionDeclaredWithTheNoreturnAttributeReturnQuery() { + //autogenerate `Query` type + result = + // `Query` type for `functionDeclaredWithTheNoreturnAttributeReturn` query + TQueryCPP(TImportMisra23PackageQuery(TFunctionDeclaredWithTheNoreturnAttributeReturnQuery())) + } + + Query nonVoidFunctionShallReturnAValueOnAllPathsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nonVoidFunctionShallReturnAValueOnAllPaths` query + TQueryCPP(TImportMisra23PackageQuery(TNonVoidFunctionShallReturnAValueOnAllPathsQuery())) + } + + Query declarationOfAnObjectIndirectionsLevelQuery() { + //autogenerate `Query` type + result = + // `Query` type for `declarationOfAnObjectIndirectionsLevel` query + TQueryCPP(TImportMisra23PackageQuery(TDeclarationOfAnObjectIndirectionsLevelQuery())) + } + + Query handlersReferToNonStaticMembersFromTheirClassQuery() { + //autogenerate `Query` type + result = + // `Query` type for `handlersReferToNonStaticMembersFromTheirClass` query + TQueryCPP(TImportMisra23PackageQuery(THandlersReferToNonStaticMembersFromTheirClassQuery())) + } + + Query includeDirectivesPrecededByPreprocessorDirectivesQuery() { + //autogenerate `Query` type + result = + // `Query` type for `includeDirectivesPrecededByPreprocessorDirectives` query + TQueryCPP(TImportMisra23PackageQuery(TIncludeDirectivesPrecededByPreprocessorDirectivesQuery())) + } + + Query identifiersUsedInTheControllingExpressionOfQuery() { + //autogenerate `Query` type + result = + // `Query` type for `identifiersUsedInTheControllingExpressionOf` query + TQueryCPP(TImportMisra23PackageQuery(TIdentifiersUsedInTheControllingExpressionOfQuery())) + } + + Query charsThatShouldNotOccurInHeaderFileNameQuery() { + //autogenerate `Query` type + result = + // `Query` type for `charsThatShouldNotOccurInHeaderFileName` query + TQueryCPP(TImportMisra23PackageQuery(TCharsThatShouldNotOccurInHeaderFileNameQuery())) + } + + Query andPreprocessorOperatorsShouldNotBeUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `andPreprocessorOperatorsShouldNotBeUsed` query + TQueryCPP(TImportMisra23PackageQuery(TAndPreprocessorOperatorsShouldNotBeUsedQuery())) + } + + Query tokensThatLookLikeDirectivesInAMacroArgumentQuery() { + //autogenerate `Query` type + result = + // `Query` type for `tokensThatLookLikeDirectivesInAMacroArgument` query + TQueryCPP(TImportMisra23PackageQuery(TTokensThatLookLikeDirectivesInAMacroArgumentQuery())) + } + + Query pointerToAnIncompleteClassTypeDeletedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `pointerToAnIncompleteClassTypeDeleted` query + TQueryCPP(TImportMisra23PackageQuery(TPointerToAnIncompleteClassTypeDeletedQuery())) + } + + Query pointersReturnedByLocaleFunctionsMustBeUsedAsConstQuery() { + //autogenerate `Query` type + result = + // `Query` type for `pointersReturnedByLocaleFunctionsMustBeUsedAsConst` query + TQueryCPP(TImportMisra23PackageQuery(TPointersReturnedByLocaleFunctionsMustBeUsedAsConstQuery())) + } + + Query callToSetlocaleInvalidatesOldPointersMisraQuery() { + //autogenerate `Query` type + result = + // `Query` type for `callToSetlocaleInvalidatesOldPointersMisra` query + TQueryCPP(TImportMisra23PackageQuery(TCallToSetlocaleInvalidatesOldPointersMisraQuery())) + } + + Query callToSetlocaleInvalidatesOldPointersWarnMisraQuery() { + //autogenerate `Query` type + result = + // `Query` type for `callToSetlocaleInvalidatesOldPointersWarnMisra` query + TQueryCPP(TImportMisra23PackageQuery(TCallToSetlocaleInvalidatesOldPointersWarnMisraQuery())) + } + + Query objectUsedWhileInPotentiallyMovedFromStateQuery() { + //autogenerate `Query` type + result = + // `Query` type for `objectUsedWhileInPotentiallyMovedFromState` query + TQueryCPP(TImportMisra23PackageQuery(TObjectUsedWhileInPotentiallyMovedFromStateQuery())) + } + + Query readsAndWritesOnStreamNotSeparatedByPositioningQuery() { + //autogenerate `Query` type + result = + // `Query` type for `readsAndWritesOnStreamNotSeparatedByPositioning` query + TQueryCPP(TImportMisra23PackageQuery(TReadsAndWritesOnStreamNotSeparatedByPositioningQuery())) + } + + Query commaOperatorShouldNotBeUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `commaOperatorShouldNotBeUsed` query + TQueryCPP(TImportMisra23PackageQuery(TCommaOperatorShouldNotBeUsedQuery())) + } + + Query copyAndMoveAssignmentsShallHandleSelfAssignmentQuery() { + //autogenerate `Query` type + result = + // `Query` type for `copyAndMoveAssignmentsShallHandleSelfAssignment` query + TQueryCPP(TImportMisra23PackageQuery(TCopyAndMoveAssignmentsShallHandleSelfAssignmentQuery())) + } + + Query useSingleLocalDeclaratorsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `useSingleLocalDeclarators` query + TQueryCPP(TImportMisra23PackageQuery(TUseSingleLocalDeclaratorsQuery())) + } + + Query useSingleGlobalOrMemberDeclaratorsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `useSingleGlobalOrMemberDeclarators` query + TQueryCPP(TImportMisra23PackageQuery(TUseSingleGlobalOrMemberDeclaratorsQuery())) + } + + Query enumerationNotDefinedWithAnExplicitUnderlyingTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `enumerationNotDefinedWithAnExplicitUnderlyingType` query + TQueryCPP(TImportMisra23PackageQuery(TEnumerationNotDefinedWithAnExplicitUnderlyingTypeQuery())) + } + + Query asmDeclarationShallNotBeUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `asmDeclarationShallNotBeUsed` query + TQueryCPP(TImportMisra23PackageQuery(TAsmDeclarationShallNotBeUsedQuery())) + } + + Query nonUniqueEnumerationConstantQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nonUniqueEnumerationConstant` query + TQueryCPP(TImportMisra23PackageQuery(TNonUniqueEnumerationConstantQuery())) + } + + Query bitFieldShallHaveAnAppropriateTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `bitFieldShallHaveAnAppropriateType` query + TQueryCPP(TImportMisra23PackageQuery(TBitFieldShallHaveAnAppropriateTypeQuery())) + } + + Query signedIntegerNamedBitFieldHaveALengthOfOneBitQuery() { + //autogenerate `Query` type + result = + // `Query` type for `signedIntegerNamedBitFieldHaveALengthOfOneBit` query + TQueryCPP(TImportMisra23PackageQuery(TSignedIntegerNamedBitFieldHaveALengthOfOneBitQuery())) + } + + Query virtualAndNonVirtualClassInTheHierarchyQuery() { + //autogenerate `Query` type + result = + // `Query` type for `virtualAndNonVirtualClassInTheHierarchy` query + TQueryCPP(TImportMisra23PackageQuery(TVirtualAndNonVirtualClassInTheHierarchyQuery())) + } + + Query overridingShallSpecifyDifferentDefaultArgumentsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `overridingShallSpecifyDifferentDefaultArguments` query + TQueryCPP(TImportMisra23PackageQuery(TOverridingShallSpecifyDifferentDefaultArgumentsQuery())) + } + + Query potentiallyVirtualPointerOnlyComparesToNullptrQuery() { + //autogenerate `Query` type + result = + // `Query` type for `potentiallyVirtualPointerOnlyComparesToNullptr` query + TQueryCPP(TImportMisra23PackageQuery(TPotentiallyVirtualPointerOnlyComparesToNullptrQuery())) + } + + Query objectsDynamicTypeUsedFromConstructorOrDestructorQuery() { + //autogenerate `Query` type + result = + // `Query` type for `objectsDynamicTypeUsedFromConstructorOrDestructor` query + TQueryCPP(TImportMisra23PackageQuery(TObjectsDynamicTypeUsedFromConstructorOrDestructorQuery())) + } + + Query initializeAllVirtualBaseClassesQuery() { + //autogenerate `Query` type + result = + // `Query` type for `initializeAllVirtualBaseClasses` query + TQueryCPP(TImportMisra23PackageQuery(TInitializeAllVirtualBaseClassesQuery())) + } + + Query initializerListConstructorIsTheOnlyConstructorQuery() { + //autogenerate `Query` type + result = + // `Query` type for `initializerListConstructorIsTheOnlyConstructor` query + TQueryCPP(TImportMisra23PackageQuery(TInitializerListConstructorIsTheOnlyConstructorQuery())) + } + + Query addressOfOperatorOverloadedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `addressOfOperatorOverloaded` query + TQueryCPP(TImportMisra23PackageQuery(TAddressOfOperatorOverloadedQuery())) + } + + Query functionTemplatesExplicitlySpecializedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `functionTemplatesExplicitlySpecialized` query + TQueryCPP(TImportMisra23PackageQuery(TFunctionTemplatesExplicitlySpecializedQuery())) + } + + Query exceptionObjectHavePointerTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `exceptionObjectHavePointerType` query + TQueryCPP(TImportMisra23PackageQuery(TExceptionObjectHavePointerTypeQuery())) + } + + Query emptyThrowOnlyWithinACatchHandlerQuery() { + //autogenerate `Query` type + result = + // `Query` type for `emptyThrowOnlyWithinACatchHandler` query + TQueryCPP(TImportMisra23PackageQuery(TEmptyThrowOnlyWithinACatchHandlerQuery())) + } + + Query noexceptFunctionShouldNotPropagateToTheCallerQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noexceptFunctionShouldNotPropagateToTheCaller` query + TQueryCPP(TImportMisra23PackageQuery(TNoexceptFunctionShouldNotPropagateToTheCallerQuery())) + } + + Query functionLikeMacrosDefinedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `functionLikeMacrosDefined` query + TQueryCPP(TImportMisra23PackageQuery(TFunctionLikeMacrosDefinedQuery())) + } + + Query macroParameterFollowingHashQuery() { + //autogenerate `Query` type + result = + // `Query` type for `macroParameterFollowingHash` query + TQueryCPP(TImportMisra23PackageQuery(TMacroParameterFollowingHashQuery())) + } + + Query aMixedUseMacroArgumentSubjectToExpansionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `aMixedUseMacroArgumentSubjectToExpansion` query + TQueryCPP(TImportMisra23PackageQuery(TAMixedUseMacroArgumentSubjectToExpansionQuery())) + } + + Query csignalFacilitiesUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `csignalFacilitiesUsed` query + TQueryCPP(TImportMisra23PackageQuery(TCsignalFacilitiesUsedQuery())) + } + + Query csignalTypesShallNotBeUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `csignalTypesShallNotBeUsed` query + TQueryCPP(TImportMisra23PackageQuery(TCsignalTypesShallNotBeUsedQuery())) + } + + Query atofAtoiAtolAndAtollUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `atofAtoiAtolAndAtollUsed` query + TQueryCPP(TImportMisra23PackageQuery(TAtofAtoiAtolAndAtollUsedQuery())) + } + + Query macroOffsetofShallNotBeUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `macroOffsetofShallNotBeUsed` query + TQueryCPP(TImportMisra23PackageQuery(TMacroOffsetofShallNotBeUsedQuery())) + } + + Query globalSizedOperatorDeleteShallBeDefinedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `globalSizedOperatorDeleteShallBeDefined` query + TQueryCPP(TImportMisra23PackageQuery(TGlobalSizedOperatorDeleteShallBeDefinedQuery())) + } + + Query globalUnsizedOperatorDeleteShallBeDefinedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `globalUnsizedOperatorDeleteShallBeDefined` query + TQueryCPP(TImportMisra23PackageQuery(TGlobalUnsizedOperatorDeleteShallBeDefinedQuery())) + } + + Query vectorShouldNotBeSpecializedWithBoolQuery() { + //autogenerate `Query` type + result = + // `Query` type for `vectorShouldNotBeSpecializedWithBool` query + TQueryCPP(TImportMisra23PackageQuery(TVectorShouldNotBeSpecializedWithBoolQuery())) + } + + Query forwardingReferencesAndForwardNotUsedTogetherQuery() { + //autogenerate `Query` type + result = + // `Query` type for `forwardingReferencesAndForwardNotUsedTogether` query + TQueryCPP(TImportMisra23PackageQuery(TForwardingReferencesAndForwardNotUsedTogetherQuery())) + } + + Query cstdioFunctionsShallNotBeUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `cstdioFunctionsShallNotBeUsed` query + TQueryCPP(TImportMisra23PackageQuery(TCstdioFunctionsShallNotBeUsedQuery())) + } + + Query cstdioMacrosShallNotBeUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `cstdioMacrosShallNotBeUsed` query + TQueryCPP(TImportMisra23PackageQuery(TCstdioMacrosShallNotBeUsedQuery())) + } + + Query cstdioTypesShallNotBeUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `cstdioTypesShallNotBeUsed` query + TQueryCPP(TImportMisra23PackageQuery(TCstdioTypesShallNotBeUsedQuery())) + } + + Query backslashCharacterMisuseQuery() { + //autogenerate `Query` type + result = + // `Query` type for `backslashCharacterMisuse` query + TQueryCPP(TImportMisra23PackageQuery(TBackslashCharacterMisuseQuery())) + } + + Query nonTerminatedEscapeSequencesQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nonTerminatedEscapeSequences` query + TQueryCPP(TImportMisra23PackageQuery(TNonTerminatedEscapeSequencesQuery())) + } + + Query octalConstantsUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `octalConstantsUsed` query + TQueryCPP(TImportMisra23PackageQuery(TOctalConstantsUsedQuery())) + } + + Query unsignedIntegerLiteralsNotAppropriatelySuffixedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unsignedIntegerLiteralsNotAppropriatelySuffixed` query + TQueryCPP(TImportMisra23PackageQuery(TUnsignedIntegerLiteralsNotAppropriatelySuffixedQuery())) + } + + Query lowercaseLStartsInLiteralSuffixQuery() { + //autogenerate `Query` type + result = + // `Query` type for `lowercaseLStartsInLiteralSuffix` query + TQueryCPP(TImportMisra23PackageQuery(TLowercaseLStartsInLiteralSuffixQuery())) + } + + Query characterSequenceUsedWithinACStyleCommentQuery() { + //autogenerate `Query` type + result = + // `Query` type for `characterSequenceUsedWithinACStyleComment` query + TQueryCPP(TImportMisra23PackageQuery(TCharacterSequenceUsedWithinACStyleCommentQuery())) + } + + Query lineSplicingUsedInCommentsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `lineSplicingUsedInComments` query + TQueryCPP(TImportMisra23PackageQuery(TLineSplicingUsedInCommentsQuery())) + } + + Query globalNamespaceDeclarationsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `globalNamespaceDeclarations` query + TQueryCPP(TImportMisra23PackageQuery(TGlobalNamespaceDeclarationsQuery())) + } + + Query nonGlobalFunctionMainQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nonGlobalFunctionMain` query + TQueryCPP(TImportMisra23PackageQuery(TNonGlobalFunctionMainQuery())) + } + + Query inheritedNonOverridableMemberFunctionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `inheritedNonOverridableMemberFunction` query + TQueryCPP(TImportMisra23PackageQuery(TInheritedNonOverridableMemberFunctionQuery())) + } + + Query inheritedOverridableMemberFunctionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `inheritedOverridableMemberFunction` query + TQueryCPP(TImportMisra23PackageQuery(TInheritedOverridableMemberFunctionQuery())) + } + + Query definitionShallBeConsideredForUnqualifiedLookupQuery() { + //autogenerate `Query` type + result = + // `Query` type for `definitionShallBeConsideredForUnqualifiedLookup` query + TQueryCPP(TImportMisra23PackageQuery(TDefinitionShallBeConsideredForUnqualifiedLookupQuery())) + } + + Query nameShallBeReferredUsingAQualifiedIdOrThisQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nameShallBeReferredUsingAQualifiedIdOrThis` query + TQueryCPP(TImportMisra23PackageQuery(TNameShallBeReferredUsingAQualifiedIdOrThisQuery())) + } + + Query nameShallBeReferredUsingAQualifiedIdOrThisAuditQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nameShallBeReferredUsingAQualifiedIdOrThisAudit` query + TQueryCPP(TImportMisra23PackageQuery(TNameShallBeReferredUsingAQualifiedIdOrThisAuditQuery())) + } + + Query returnReferenceOrPointerToAutomaticLocalVariableQuery() { + //autogenerate `Query` type + result = + // `Query` type for `returnReferenceOrPointerToAutomaticLocalVariable` query + TQueryCPP(TImportMisra23PackageQuery(TReturnReferenceOrPointerToAutomaticLocalVariableQuery())) + } + + Query nullptrNotTheOnlyFormOfTheNullPointerConstantQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nullptrNotTheOnlyFormOfTheNullPointerConstant` query + TQueryCPP(TImportMisra23PackageQuery(TNullptrNotTheOnlyFormOfTheNullPointerConstantQuery())) + } + + Query arrayPassedAsFunctionArgumentDecayToAPointerQuery() { + //autogenerate `Query` type + result = + // `Query` type for `arrayPassedAsFunctionArgumentDecayToAPointer` query + TQueryCPP(TImportMisra23PackageQuery(TArrayPassedAsFunctionArgumentDecayToAPointerQuery())) + } + + Query resultOfAnAssignmentOperatorShouldNotBeUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `resultOfAnAssignmentOperatorShouldNotBeUsed` query + TQueryCPP(TImportMisra23PackageQuery(TResultOfAnAssignmentOperatorShouldNotBeUsedQuery())) + } + + Query functionsCallThemselvesEitherDirectlyOrIndirectlyQuery() { + //autogenerate `Query` type + result = + // `Query` type for `functionsCallThemselvesEitherDirectlyOrIndirectly` query + TQueryCPP(TImportMisra23PackageQuery(TFunctionsCallThemselvesEitherDirectlyOrIndirectlyQuery())) + } + + Query castsBetweenAPointerToFunctionAndAnyOtherTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `castsBetweenAPointerToFunctionAndAnyOtherType` query + TQueryCPP(TImportMisra23PackageQuery(TCastsBetweenAPointerToFunctionAndAnyOtherTypeQuery())) + } + + Query reinterpretCastShallNotBeUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `reinterpretCastShallNotBeUsed` query + TQueryCPP(TImportMisra23PackageQuery(TReinterpretCastShallNotBeUsedQuery())) + } + + Query unsignedOperationWithConstantOperandsWrapsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unsignedOperationWithConstantOperandsWraps` query + TQueryCPP(TImportMisra23PackageQuery(TUnsignedOperationWithConstantOperandsWrapsQuery())) + } + + Query builtInUnaryOperatorAppliedToUnsignedExpressionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `builtInUnaryOperatorAppliedToUnsignedExpression` query + TQueryCPP(TImportMisra23PackageQuery(TBuiltInUnaryOperatorAppliedToUnsignedExpressionQuery())) + } + + Query switchBodyCompoundConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `switchBodyCompoundCondition` query + TQueryCPP(TImportMisra23PackageQuery(TSwitchBodyCompoundConditionQuery())) + } + + Query loopBodyCompoundConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `loopBodyCompoundCondition` query + TQueryCPP(TImportMisra23PackageQuery(TLoopBodyCompoundConditionQuery())) + } + + Query gotoStatementShouldNotBeUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `gotoStatementShouldNotBeUsed` query + TQueryCPP(TImportMisra23PackageQuery(TGotoStatementShouldNotBeUsedQuery())) + } + + Query gotoReferenceALabelInSurroundingBlockQuery() { + //autogenerate `Query` type + result = + // `Query` type for `gotoReferenceALabelInSurroundingBlock` query + TQueryCPP(TImportMisra23PackageQuery(TGotoReferenceALabelInSurroundingBlockQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Representation.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Representation.qll index a423cfd4ff..2f92ea89ec 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Representation.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Representation.qll @@ -7,6 +7,7 @@ newtype RepresentationQuery = TBitFieldsShallBeUsedOnlyWhenInterfacingToHardwareOrConformingToCommunicationProtocolsQuery() or TAuditPossibleHardwareInterfaceDueToBitFieldUsageInDataTypeDefinitionQuery() or TObjectAssignedToAnOverlappingObjectQuery() or + TDoNotPassAliasedPointerToParamQuery() or TUnderlyingBitRepresentationsOfFloatingPointValuesUsedQuery() or TNamedBitFieldsWithSignedIntegerTypeShallHaveALengthOfMoreThanOneBitQuery() or TMemsetUsedToAccessObjectRepresentationQuery() or @@ -41,6 +42,15 @@ predicate isRepresentationQueryMetadata(Query query, string queryId, string rule ruleId = "M0-2-1" and category = "required" or + query = + // `Query` instance for the `doNotPassAliasedPointerToParam` query + RepresentationPackage::doNotPassAliasedPointerToParamQuery() and + queryId = + // `@id` for the `doNotPassAliasedPointerToParam` query + "cpp/autosar/do-not-pass-aliased-pointer-to-param" and + ruleId = "M0-2-1" and + category = "required" + or query = // `Query` instance for the `underlyingBitRepresentationsOfFloatingPointValuesUsed` query RepresentationPackage::underlyingBitRepresentationsOfFloatingPointValuesUsedQuery() and @@ -109,6 +119,13 @@ module RepresentationPackage { TQueryCPP(TRepresentationPackageQuery(TObjectAssignedToAnOverlappingObjectQuery())) } + Query doNotPassAliasedPointerToParamQuery() { + //autogenerate `Query` type + result = + // `Query` type for `doNotPassAliasedPointerToParam` query + TQueryCPP(TRepresentationPackageQuery(TDoNotPassAliasedPointerToParamQuery())) + } + Query underlyingBitRepresentationsOfFloatingPointValuesUsedQuery() { //autogenerate `Query` type result = diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll index 8dfbf9feaa..2e2403165f 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll @@ -3,6 +3,7 @@ import cpp import codingstandards.cpp.exclusions.RuleMetadata //** Import packages for this language **/ import Allocations +import BannedAPIs import BannedFunctions import BannedLibraries import BannedSyntax @@ -12,15 +13,19 @@ import Comments import Concurrency import Conditionals import Const +import Conversions +import Conversions2 import DeadCode import Declarations import ExceptionSafety import Exceptions1 import Exceptions2 import Expressions +import FloatingPoint import Freed import Functions import IO +import ImportMisra23 import Includes import Inheritance import Initialization @@ -45,6 +50,7 @@ import SideEffects1 import SideEffects2 import SmartPointers1 import SmartPointers2 +import Statements import Strings import Templates import Toolchain @@ -56,6 +62,7 @@ import VirtualFunctions /** The TQuery type representing this language * */ newtype TCPPQuery = TAllocationsPackageQuery(AllocationsQuery q) or + TBannedAPIsPackageQuery(BannedAPIsQuery q) or TBannedFunctionsPackageQuery(BannedFunctionsQuery q) or TBannedLibrariesPackageQuery(BannedLibrariesQuery q) or TBannedSyntaxPackageQuery(BannedSyntaxQuery q) or @@ -65,15 +72,19 @@ newtype TCPPQuery = TConcurrencyPackageQuery(ConcurrencyQuery q) or TConditionalsPackageQuery(ConditionalsQuery q) or TConstPackageQuery(ConstQuery q) or + TConversionsPackageQuery(ConversionsQuery q) or + TConversions2PackageQuery(Conversions2Query q) or TDeadCodePackageQuery(DeadCodeQuery q) or TDeclarationsPackageQuery(DeclarationsQuery q) or TExceptionSafetyPackageQuery(ExceptionSafetyQuery q) or TExceptions1PackageQuery(Exceptions1Query q) or TExceptions2PackageQuery(Exceptions2Query q) or TExpressionsPackageQuery(ExpressionsQuery q) or + TFloatingPointPackageQuery(FloatingPointQuery q) or TFreedPackageQuery(FreedQuery q) or TFunctionsPackageQuery(FunctionsQuery q) or TIOPackageQuery(IOQuery q) or + TImportMisra23PackageQuery(ImportMisra23Query q) or TIncludesPackageQuery(IncludesQuery q) or TInheritancePackageQuery(InheritanceQuery q) or TInitializationPackageQuery(InitializationQuery q) or @@ -98,6 +109,7 @@ newtype TCPPQuery = TSideEffects2PackageQuery(SideEffects2Query q) or TSmartPointers1PackageQuery(SmartPointers1Query q) or TSmartPointers2PackageQuery(SmartPointers2Query q) or + TStatementsPackageQuery(StatementsQuery q) or TStringsPackageQuery(StringsQuery q) or TTemplatesPackageQuery(TemplatesQuery q) or TToolchainPackageQuery(ToolchainQuery q) or @@ -109,6 +121,7 @@ newtype TCPPQuery = /** The metadata predicate * */ predicate isQueryMetadata(Query query, string queryId, string ruleId, string category) { isAllocationsQueryMetadata(query, queryId, ruleId, category) or + isBannedAPIsQueryMetadata(query, queryId, ruleId, category) or isBannedFunctionsQueryMetadata(query, queryId, ruleId, category) or isBannedLibrariesQueryMetadata(query, queryId, ruleId, category) or isBannedSyntaxQueryMetadata(query, queryId, ruleId, category) or @@ -118,15 +131,19 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isConcurrencyQueryMetadata(query, queryId, ruleId, category) or isConditionalsQueryMetadata(query, queryId, ruleId, category) or isConstQueryMetadata(query, queryId, ruleId, category) or + isConversionsQueryMetadata(query, queryId, ruleId, category) or + isConversions2QueryMetadata(query, queryId, ruleId, category) or isDeadCodeQueryMetadata(query, queryId, ruleId, category) or isDeclarationsQueryMetadata(query, queryId, ruleId, category) or isExceptionSafetyQueryMetadata(query, queryId, ruleId, category) or isExceptions1QueryMetadata(query, queryId, ruleId, category) or isExceptions2QueryMetadata(query, queryId, ruleId, category) or isExpressionsQueryMetadata(query, queryId, ruleId, category) or + isFloatingPointQueryMetadata(query, queryId, ruleId, category) or isFreedQueryMetadata(query, queryId, ruleId, category) or isFunctionsQueryMetadata(query, queryId, ruleId, category) or isIOQueryMetadata(query, queryId, ruleId, category) or + isImportMisra23QueryMetadata(query, queryId, ruleId, category) or isIncludesQueryMetadata(query, queryId, ruleId, category) or isInheritanceQueryMetadata(query, queryId, ruleId, category) or isInitializationQueryMetadata(query, queryId, ruleId, category) or @@ -151,6 +168,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isSideEffects2QueryMetadata(query, queryId, ruleId, category) or isSmartPointers1QueryMetadata(query, queryId, ruleId, category) or isSmartPointers2QueryMetadata(query, queryId, ruleId, category) or + isStatementsQueryMetadata(query, queryId, ruleId, category) or isStringsQueryMetadata(query, queryId, ruleId, category) or isTemplatesQueryMetadata(query, queryId, ruleId, category) or isToolchainQueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Statements.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Statements.qll new file mode 100644 index 0000000000..fe202ce31f --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Statements.qll @@ -0,0 +1,61 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype StatementsQuery = + TAppropriateStructureOfSwitchStatementQuery() or + TLegacyForStatementsShouldBeSimpleQuery() or + TForRangeInitializerAtMostOneFunctionCallQuery() + +predicate isStatementsQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `appropriateStructureOfSwitchStatement` query + StatementsPackage::appropriateStructureOfSwitchStatementQuery() and + queryId = + // `@id` for the `appropriateStructureOfSwitchStatement` query + "cpp/misra/appropriate-structure-of-switch-statement" and + ruleId = "RULE-9-4-2" and + category = "required" + or + query = + // `Query` instance for the `legacyForStatementsShouldBeSimple` query + StatementsPackage::legacyForStatementsShouldBeSimpleQuery() and + queryId = + // `@id` for the `legacyForStatementsShouldBeSimple` query + "cpp/misra/legacy-for-statements-should-be-simple" and + ruleId = "RULE-9-5-1" and + category = "advisory" + or + query = + // `Query` instance for the `forRangeInitializerAtMostOneFunctionCall` query + StatementsPackage::forRangeInitializerAtMostOneFunctionCallQuery() and + queryId = + // `@id` for the `forRangeInitializerAtMostOneFunctionCall` query + "cpp/misra/for-range-initializer-at-most-one-function-call" and + ruleId = "RULE-9-5-2" and + category = "required" +} + +module StatementsPackage { + Query appropriateStructureOfSwitchStatementQuery() { + //autogenerate `Query` type + result = + // `Query` type for `appropriateStructureOfSwitchStatement` query + TQueryCPP(TStatementsPackageQuery(TAppropriateStructureOfSwitchStatementQuery())) + } + + Query legacyForStatementsShouldBeSimpleQuery() { + //autogenerate `Query` type + result = + // `Query` type for `legacyForStatementsShouldBeSimple` query + TQueryCPP(TStatementsPackageQuery(TLegacyForStatementsShouldBeSimpleQuery())) + } + + Query forRangeInitializerAtMostOneFunctionCallQuery() { + //autogenerate `Query` type + result = + // `Query` type for `forRangeInitializerAtMostOneFunctionCall` query + TQueryCPP(TStatementsPackageQuery(TForRangeInitializerAtMostOneFunctionCallQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exprs/FunctionExprs.qll b/cpp/common/src/codingstandards/cpp/exprs/FunctionExprs.qll new file mode 100644 index 0000000000..5c46fce075 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exprs/FunctionExprs.qll @@ -0,0 +1,59 @@ +import cpp +import codingstandards.cpp.types.FunctionType + +/** + * A class representing an expression that has a function pointer type. This can be a function + * access, a variable access, or any expression that has a function pointer type. + */ +abstract class FunctionExpr extends Expr { + /** Any element that could represent the function, for example, a variable or an expression. */ + abstract Element getFunction(); + + /** A name or string that describes the function. */ + abstract string describe(); + + /** Get calls of this function */ + abstract Call getACall(); +} + +/** + * A function access is an an expression of function type where we know the function. + */ +class SimpleFunctionAccess extends FunctionExpr, FunctionAccess { + override Element getFunction() { result = this.getTarget() } + + override string describe() { result = "Address of function " + this.getTarget().getName() } + + override FunctionCall getACall() { result.getTarget() = this.getTarget() } +} + +/** + * An access of a variable that has a function pointer type is also a function expression, for which + * we can track certain properties of the function. + */ +class FunctionVariableAccess extends FunctionExpr, VariableAccess { + FunctionVariableAccess() { this.getUnderlyingType() instanceof FunctionType } + + override Element getFunction() { result = this.getTarget() } + + override string describe() { result = "Function pointer variable " + this.getTarget().getName() } + + override ExprCall getACall() { result.getExpr().(VariableAccess).getTarget() = this.getTarget() } +} + +/** + * A function typed expression that is not a function access or a variable access. + */ +class FunctionTypedExpr extends FunctionExpr { + FunctionTypedExpr() { + this.getUnderlyingType() instanceof FunctionType and + not this instanceof FunctionAccess and + not this instanceof VariableAccess + } + + override Element getFunction() { result = this } + + override string describe() { result = "Expression with function pointer type" } + + override ExprCall getACall() { result.getExpr() = this } +} diff --git a/cpp/common/src/codingstandards/cpp/exprs/Guards.qll b/cpp/common/src/codingstandards/cpp/exprs/Guards.qll new file mode 100644 index 0000000000..73a35ccc6b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exprs/Guards.qll @@ -0,0 +1,34 @@ +import cpp +import codeql.util.Boolean +import semmle.code.cpp.controlflow.Guards +import codingstandards.cpp.exprs.FunctionExprs + +/** + * A guard of the form: `if (funcPtr) funcPtr();`, e.g., a null check on a function before calling + * that function. + * + * Note this does not consider the above to be a null function call guard if `funcPtr` is a + * function name, as that could only be null via unusual linkage steps, and is not expected to be + * an intentional null check. + */ +class NullFunctionCallGuard extends GuardCondition { + FunctionExpr expr; + + NullFunctionCallGuard() { + exists(BasicBlock block, Call guardedCall | + ( + // Handles 'if (funcPtr != NULL)`: + this.ensuresEq(expr, 0, block, false) + or + // Handles `if (funcPtr)` in C where no implicit conversion to bool exists: + expr = this and + expr.getFunction() instanceof Variable and + this.controls(block, true) + ) and + guardedCall = expr.getACall() and + block.contains(guardedCall) + ) + } + + FunctionExpr getFunctionExpr() { result = expr } +} diff --git a/cpp/common/src/codingstandards/cpp/lifetimes/lifetimeprofile/LifetimeProfile.qll b/cpp/common/src/codingstandards/cpp/lifetimes/lifetimeprofile/LifetimeProfile.qll index 7990f50216..b02f51380e 100644 --- a/cpp/common/src/codingstandards/cpp/lifetimes/lifetimeprofile/LifetimeProfile.qll +++ b/cpp/common/src/codingstandards/cpp/lifetimes/lifetimeprofile/LifetimeProfile.qll @@ -1,5 +1,4 @@ import cpp -private import codingstandards.cpp.dataflow.DataFlow private import semmle.code.cpp.controlflow.Nullness private import codingstandards.cpp.Dereferenced private import codingstandards.cpp.Expr diff --git a/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll b/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll new file mode 100644 index 0000000000..3dd61e934d --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll @@ -0,0 +1,91 @@ +import cpp +import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.valuenumbering.HashCons +import semmle.code.cpp.controlflow.Dominance +import codeql.util.Boolean + +/** + * A library for detecting leaked resources. + * + * To use this library, implement `ResourceLeakConfigSig`: + * + * ``` + * class UnjoinedThreadConfig implements ResourceLeakConfigSig { + * predicate isResource(DataFlow::Node node) { + * node.asExpr().isThreadCreate() + * } + * + * predicate isFree(ControlFlowNode node, DataFlow::Node resource) { + * node.asExpr().isThreadJoin(resource.asExpr()) + * } + * } + * ``` + * + * You can now check if a resource is leaked through the module predicate + * `ResourceLeak::isLeaked(resource)`. + * + * The leak analysis finds the exit point of the function in which the resource is is declared, and + * then reverses execution from there using `getAPredecessor()`. When this backwards walk discovers + * a control flow node that frees the resource, that exploration stops. If any exploration reaches + * a resource, that resource may be leaked via that path. + * + * Uses `DataFlow::Node` in order to track aliases of the resource to better detect when the + * resource is freed. + * + * This library by default assumes that resources are expression nodes. To use it with other kinds + * of nodes requires overriding `resourceInitPoint`. + */ +signature module ResourceLeakConfigSig { + predicate isAllocate(ControlFlowNode node, DataFlow::Node resource); + + predicate isFree(ControlFlowNode node, DataFlow::Node resource); + + bindingset[node] + default DataFlow::Node getAnAlias(DataFlow::Node node) { + DataFlow::localFlow(node, result) + or + exists(Expr current, Expr after | + current in [node.asExpr(), node.asDefiningArgument()] and + after in [result.asExpr(), result.asDefiningArgument()] and + hashCons(current) = hashCons(after) and + strictlyDominates(current, after) + ) + } + + /* A point at which a resource is considered to have leaked if it has not been freed. */ + default ControlFlowNode outOfScope(ControlFlowNode allocPoint) { + result = allocPoint.(Expr).getEnclosingFunction().getBlock().getLastStmt() + } +} + +module ResourceLeak { + private newtype TResource = + TJustResource(DataFlow::Node resource, ControlFlowNode cfgNode) { + Config::isAllocate(cfgNode, resource) + } + + private predicate isLeakedAtControlPoint(TResource resource, ControlFlowNode cfgNode) { + // Holds if this control point is where the resource was allocated (and therefore not freed). + resource = TJustResource(_, cfgNode) + or + // Holds if this control point does not free the resource, and is reachable from a point that + // does not free the resource. + isLeakedAtControlPoint(resource, cfgNode.getAPredecessor()) and + not exists(DataFlow::Node freed, DataFlow::Node resourceNode | + Config::isFree(cfgNode, freed) and + freed = Config::getAnAlias(resourceNode) and + resource = TJustResource(resourceNode, _) + ) + } + + /** + * Holds if `resource` is leaked. Use this module predicate to find leaked resources. + */ + ControlFlowNode getALeak(ControlFlowNode allocPoint) { + exists(TResource resourceWrapper, DataFlow::Node resource | + resourceWrapper = TJustResource(resource, allocPoint) and + result = Config::outOfScope(allocPoint) and + isLeakedAtControlPoint(resourceWrapper, result) + ) + } +} diff --git a/cpp/common/src/codingstandards/cpp/resources/ResourceManagement.qll b/cpp/common/src/codingstandards/cpp/resources/ResourceManagement.qll index 0798575495..17c30196a0 100644 --- a/cpp/common/src/codingstandards/cpp/resources/ResourceManagement.qll +++ b/cpp/common/src/codingstandards/cpp/resources/ResourceManagement.qll @@ -1,58 +1,45 @@ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow +import codingstandards.cpp.resources.ResourceLeakAnalysis -/** - * The `ResourceAcquisitionExpr` abstract class models resource - * acquisition and release expressions - */ -abstract class ResourceAcquisitionExpr extends Expr { - abstract Expr getReleaseExpr(); -} - -// allocation - deallocation -class AllocExpr extends ResourceAcquisitionExpr { - AllocExpr() { this.(AllocationExpr).requiresDealloc() } - - override Expr getReleaseExpr() { - exists(DeallocationExpr d | result = d.getFreedExpr()) and - DataFlow::localFlow(DataFlow::exprNode(this), DataFlow::exprNode(result)) - } -} - -// file open-close -class FstreamAcquisitionExpr extends ResourceAcquisitionExpr { - FstreamAcquisitionExpr() { +module ResourceLeakConfig implements ResourceLeakConfigSig { + predicate isAllocate(ControlFlowNode allocPoint, DataFlow::Node node) { + exists(AllocationExpr alloc | + allocPoint = alloc and + alloc.requiresDealloc() and + node.asExpr() = alloc + ) + or exists(FunctionCall f | - f.getTarget().hasQualifiedName("std", "basic_fstream", "open") and this = f.getQualifier() + f.getTarget().hasQualifiedName("std", "basic_fstream", "open") and + allocPoint = f and + node.asDefiningArgument() = f.getQualifier() ) - } - - override Expr getReleaseExpr() { + or exists(FunctionCall f | - f.getTarget().hasQualifiedName("std", "basic_fstream", "close") and result = f.getQualifier() - ) and - exists(DataFlow::Node def | - def.asDefiningArgument() = this and - DataFlow::localFlow(def, DataFlow::exprNode(result)) + f.getTarget().hasQualifiedName("std", "mutex", "lock") and + allocPoint = f and + node.asDefiningArgument() = f.getQualifier() ) } -} -// mutex lock unlock -class MutexAcquisitionExpr extends ResourceAcquisitionExpr { - MutexAcquisitionExpr() { + predicate isFree(ControlFlowNode node, DataFlow::Node resource) { + exists(DeallocationExpr d, Expr freedExpr | + freedExpr = d.getFreedExpr() and + node = d and + resource.asExpr() = freedExpr + ) + or exists(FunctionCall f | - f.getTarget().hasQualifiedName("std", "mutex", "lock") and this = f.getQualifier() + f.getTarget().hasQualifiedName("std", "basic_fstream", "close") and + node = f and + resource.asExpr() = f.getQualifier() ) - } - - override Expr getReleaseExpr() { + or exists(FunctionCall f | - f.getTarget().hasQualifiedName("std", "mutex", "unlock") and result = f.getQualifier() - ) and - exists(DataFlow::Node def | - def.asDefiningArgument() = this and - DataFlow::localFlow(def, DataFlow::exprNode(result)) + f.getTarget().hasQualifiedName("std", "mutex", "unlock") and + node = f and + resource.asExpr() = f.getQualifier() ) } } diff --git a/cpp/common/src/codingstandards/cpp/rules/accessofnonexistingmemberthroughpointertomember/AccessOfNonExistingMemberThroughPointerToMember.qll b/cpp/common/src/codingstandards/cpp/rules/accessofnonexistingmemberthroughpointertomember/AccessOfNonExistingMemberThroughPointerToMember.qll index 138c0a89b5..ac135386f3 100644 --- a/cpp/common/src/codingstandards/cpp/rules/accessofnonexistingmemberthroughpointertomember/AccessOfNonExistingMemberThroughPointerToMember.qll +++ b/cpp/common/src/codingstandards/cpp/rules/accessofnonexistingmemberthroughpointertomember/AccessOfNonExistingMemberThroughPointerToMember.qll @@ -7,7 +7,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.Expr -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow abstract class AccessOfNonExistingMemberThroughPointerToMemberSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.qll b/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.qll index ab8659efd8..b213087c5c 100644 --- a/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.qll +++ b/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.qll @@ -7,7 +7,6 @@ import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.Nullness import codingstandards.cpp.Expr -import codingstandards.cpp.dataflow.DataFlow import NullPointerToPointerMemberExpressionFlow::PathGraph abstract class AccessOfUndefinedMemberThroughNullPointerSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughuninitializedstaticpointer/AccessOfUndefinedMemberThroughUninitializedStaticPointer.qll b/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughuninitializedstaticpointer/AccessOfUndefinedMemberThroughUninitializedStaticPointer.qll index ca1e2a4282..0271d7c6e7 100644 --- a/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughuninitializedstaticpointer/AccessOfUndefinedMemberThroughUninitializedStaticPointer.qll +++ b/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughuninitializedstaticpointer/AccessOfUndefinedMemberThroughUninitializedStaticPointer.qll @@ -12,7 +12,7 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.EncapsulatingFunctions diff --git a/cpp/common/src/codingstandards/cpp/rules/addressofoperatoroverloaded/AddressOfOperatorOverloaded.qll b/cpp/common/src/codingstandards/cpp/rules/addressofoperatoroverloaded/AddressOfOperatorOverloaded.qll new file mode 100644 index 0000000000..603a75bd01 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/addressofoperatoroverloaded/AddressOfOperatorOverloaded.qll @@ -0,0 +1,17 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The address-of operator shall not be overloaded. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Operator + +abstract class AddressOfOperatorOverloadedSharedQuery extends Query { } + +Query getQuery() { result instanceof AddressOfOperatorOverloadedSharedQuery } + +query predicate problems(UnaryAddressOfOperator e, string message) { + not isExcluded(e, getQuery()) and message = "The unary & operator overloaded." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/amixedusemacroargumentsubjecttoexpansion/AMixedUseMacroArgumentSubjectToExpansion.qll b/cpp/common/src/codingstandards/cpp/rules/amixedusemacroargumentsubjecttoexpansion/AMixedUseMacroArgumentSubjectToExpansion.qll new file mode 100644 index 0000000000..da17706f54 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/amixedusemacroargumentsubjecttoexpansion/AMixedUseMacroArgumentSubjectToExpansion.qll @@ -0,0 +1,34 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The argument to a mixed-use macro parameter shall not be subject to further + * expansion. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Macro + +abstract class AMixedUseMacroArgumentSubjectToExpansionSharedQuery extends Query { } + +Query getQuery() { result instanceof AMixedUseMacroArgumentSubjectToExpansionSharedQuery } + +query predicate problems(FunctionLikeMacro m, string message) { + exists(MacroInvocation mi, int i, string expanded, string param | + not isExcluded(m, getQuery()) and + mi = m.getAnInvocation() and + param = m.getParameter(i) and + ( + exists(TokenPastingOperator op | op.getMacro() = m and op.getOperand() = param) + or + exists(StringizingOperator op | op.getMacro() = m and op.getOperand() = param) + ) and + // An expansion that is equal to "" means the expansion is not used and is optimized away by EDG. This happens when the expanded argument is an operand to `#` or `##`. + // This check ensure there is an expansion that is used. + expanded = mi.getExpandedArgument(i) and + not expanded = "" and + not mi.getUnexpandedArgument(i) = mi.getExpandedArgument(i) and + message = + "Macro " + m.getName() + " contains use of parameter " + param + " used in multiple contexts." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/arraypassedasfunctionargumentdecaytoapointer/ArrayPassedAsFunctionArgumentDecayToAPointer.qll b/cpp/common/src/codingstandards/cpp/rules/arraypassedasfunctionargumentdecaytoapointer/ArrayPassedAsFunctionArgumentDecayToAPointer.qll new file mode 100644 index 0000000000..b7ec4917bd --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/arraypassedasfunctionargumentdecaytoapointer/ArrayPassedAsFunctionArgumentDecayToAPointer.qll @@ -0,0 +1,46 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * An array passed as a function argument shall not decay to a pointer. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class ArrayPassedAsFunctionArgumentDecayToAPointerSharedQuery extends Query { } + +Query getQuery() { result instanceof ArrayPassedAsFunctionArgumentDecayToAPointerSharedQuery } + +predicate arrayToPointerDecay(Access ae, Parameter p) { + ( + p.getType() instanceof PointerType and + // exclude parameters of void* because then it assumed the caller can pass in dimensions through other means. + // examples are uses in `memset` or `memcpy` + not p.getType() instanceof VoidPointerType + or + p.getType() instanceof ArrayType + ) and + ae.getType() instanceof ArrayType and + // exclude char[] arrays because we assume that we can determine its dimension by looking for a NULL byte. + not ae.getType().(ArrayType).getBaseType() instanceof CharType +} + +query predicate problems( + Element e, string message, Variable array, string array_string, Parameter decayedArray, + string decayedArray_string, Function f, string f_string +) { + exists(FunctionCall fc, VariableAccess arrayAccess, int i | + not isExcluded(e, getQuery()) and + arrayAccess = array.getAnAccess() and + f = fc.getTarget() and + arrayAccess = fc.getArgument(i) and + decayedArray = f.getParameter(i) and + arrayToPointerDecay(arrayAccess, decayedArray) and + not arrayAccess.isAffectedByMacro() and + e = fc.getArgument(i) and + array_string = array.getName() and + decayedArray_string = decayedArray.getName() and + f_string = f.getName() and + message = "The array $@ decays to the pointer $@ when passed as an argument to the function $@." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/asmdeclarationused/AsmDeclarationUsed.qll b/cpp/common/src/codingstandards/cpp/rules/asmdeclarationused/AsmDeclarationUsed.qll new file mode 100644 index 0000000000..c6748683da --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/asmdeclarationused/AsmDeclarationUsed.qll @@ -0,0 +1,16 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The asm declaration shall not be used. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class AsmDeclarationUsedSharedQuery extends Query { } + +Query getQuery() { result instanceof AsmDeclarationUsedSharedQuery } + +query predicate problems(AsmStmt e, string message) { + not isExcluded(e, getQuery()) and message = "Use of asm declaration" +} diff --git a/cpp/common/src/codingstandards/cpp/rules/atofatoiatolandatollused/AtofAtoiAtolAndAtollUsed.qll b/cpp/common/src/codingstandards/cpp/rules/atofatoiatolandatollused/AtofAtoiAtolAndAtollUsed.qll new file mode 100644 index 0000000000..295e346913 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/atofatoiatolandatollused/AtofAtoiAtolAndAtollUsed.qll @@ -0,0 +1,24 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The library functions atof, atoi, atol and atoll from shall not be used. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +private string atoi() { result = ["atof", "atoi", "atol", "atoll"] } + +abstract class AtofAtoiAtolAndAtollUsedSharedQuery extends Query { } + +Query getQuery() { result instanceof AtofAtoiAtolAndAtollUsedSharedQuery } + +query predicate problems(FunctionCall fc, string message) { + exists(Function f | + not isExcluded(fc, getQuery()) and + f = fc.getTarget() and + f.getName() = atoi() and + f.getFile().getBaseName() = "stdlib.h" and + message = "Call to banned function " + f.getName() + "." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/backslashcharactermisuse/BackslashCharacterMisuse.qll b/cpp/common/src/codingstandards/cpp/rules/backslashcharactermisuse/BackslashCharacterMisuse.qll new file mode 100644 index 0000000000..34cb93fb39 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/backslashcharactermisuse/BackslashCharacterMisuse.qll @@ -0,0 +1,23 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * In character literals and non-raw string literals, \ shall only be used to form a + * defined escape sequence or universal character name. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class BackslashCharacterMisuseSharedQuery extends Query { } + +Query getQuery() { result instanceof BackslashCharacterMisuseSharedQuery } + +query predicate problems(StringLiteral l, string message) { + exists(string es | + not isExcluded(l, getQuery()) and + es = l.getANonStandardEscapeSequence(_, _) and + // Exclude universal-character-names, which begin with \u or \U + not es.toLowerCase().matches("\\u") and + message = "This literal contains the non-standard escape sequence " + es + "." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/basicstringmaynotbenullterminated/BasicStringMayNotBeNullTerminated.qll b/cpp/common/src/codingstandards/cpp/rules/basicstringmaynotbenullterminated/BasicStringMayNotBeNullTerminated.qll index cea798ae11..e27f09fd98 100644 --- a/cpp/common/src/codingstandards/cpp/rules/basicstringmaynotbenullterminated/BasicStringMayNotBeNullTerminated.qll +++ b/cpp/common/src/codingstandards/cpp/rules/basicstringmaynotbenullterminated/BasicStringMayNotBeNullTerminated.qll @@ -8,8 +8,8 @@ import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import semmle.code.cpp.security.BufferWrite import semmle.code.cpp.commons.Buffer -import codingstandards.cpp.dataflow.DataFlow -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.TaintTracking import codingstandards.cpp.PossiblyUnsafeStringOperation abstract class BasicStringMayNotBeNullTerminatedSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/bitfieldshallhaveanappropriatetype/BitFieldShallHaveAnAppropriateType.qll b/cpp/common/src/codingstandards/cpp/rules/bitfieldshallhaveanappropriatetype/BitFieldShallHaveAnAppropriateType.qll new file mode 100644 index 0000000000..27048b2d25 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/bitfieldshallhaveanappropriatetype/BitFieldShallHaveAnAppropriateType.qll @@ -0,0 +1,41 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * A bit-field shall have an appropriate type. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Compiler + +abstract class BitFieldShallHaveAnAppropriateTypeSharedQuery extends Query { } + +Query getQuery() { result instanceof BitFieldShallHaveAnAppropriateTypeSharedQuery } + +Type getSupportedBitFieldType(Compiler compiler) { + compiler instanceof UnsupportedCompiler and + ( + result instanceof IntType and + ( + result.(IntegralType).isExplicitlySigned() or + result.(IntegralType).isExplicitlyUnsigned() + ) + or + result instanceof BoolType + ) + or + (compiler instanceof Gcc or compiler instanceof Clang) and + ( + result instanceof IntegralOrEnumType + or + result instanceof BoolType + ) +} + +query predicate problems(BitField bitField, string message) { + not isExcluded(bitField, getQuery()) and + /* A violation would neither be an appropriate primitive type nor an appropriate typedef. */ + not getSupportedBitFieldType(getCompiler(bitField.getFile())) = + bitField.getType().resolveTypedefs() and + message = "Bit-field '" + bitField + "' is declared on type '" + bitField.getType() + "'." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/builtinunaryoperatorappliedtounsignedexpression/BuiltInUnaryOperatorAppliedToUnsignedExpression.qll b/cpp/common/src/codingstandards/cpp/rules/builtinunaryoperatorappliedtounsignedexpression/BuiltInUnaryOperatorAppliedToUnsignedExpression.qll new file mode 100644 index 0000000000..0e516a43ec --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/builtinunaryoperatorappliedtounsignedexpression/BuiltInUnaryOperatorAppliedToUnsignedExpression.qll @@ -0,0 +1,25 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The built-in unary - operator should not be applied to an expression of unsigned + * type. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class BuiltInUnaryOperatorAppliedToUnsignedExpressionSharedQuery extends Query { } + +Query getQuery() { result instanceof BuiltInUnaryOperatorAppliedToUnsignedExpressionSharedQuery } + +query predicate problems(Element e, string message) { + exists(UnaryMinusExpr ex, IntegralType t | + t = ex.getOperand().getExplicitlyConverted().getType().getUnderlyingType() and + t.isUnsigned() and + not ex.isAffectedByMacro() and + e = ex.getOperand() and + not isExcluded(e, getQuery()) and + message = + "The unary minus operator shall not be applied to an expression whose underlying type is unsigned." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.qll b/cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.qll new file mode 100644 index 0000000000..66f1006d17 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.qll @@ -0,0 +1,26 @@ +/** + * Provides a library which includes a `problems` predicate for reporting.... + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class CastCharBeforeConvertingToLargerSizesSharedQuery extends Query { } + +Query getQuery() { result instanceof CastCharBeforeConvertingToLargerSizesSharedQuery } + +query predicate problems(Cast c, string message) { + not isExcluded(c, getQuery()) and + // find cases where there is a conversion happening wherein the + // base type is a char + c.getExpr().getType() instanceof CharType and + not c.getExpr().getType() instanceof UnsignedCharType and + // it's a bigger type + c.getType().getSize() > c.getExpr().getType().getSize() and + // and it's some kind of integer type + c.getType().getUnderlyingType() instanceof IntegralType and + not c.isFromTemplateInstantiation(_) and + message = + "Expression not converted to `unsigned char` before converting to a larger integer type." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/castsbetweenapointertofunctionandanyothertype/CastsBetweenAPointerToFunctionAndAnyOtherType.qll b/cpp/common/src/codingstandards/cpp/rules/castsbetweenapointertofunctionandanyothertype/CastsBetweenAPointerToFunctionAndAnyOtherType.qll new file mode 100644 index 0000000000..48fa1f0c86 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/castsbetweenapointertofunctionandanyothertype/CastsBetweenAPointerToFunctionAndAnyOtherType.qll @@ -0,0 +1,20 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Casts shall not be performed between a pointer to function and any other type. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class CastsBetweenAPointerToFunctionAndAnyOtherTypeSharedQuery extends Query { } + +Query getQuery() { result instanceof CastsBetweenAPointerToFunctionAndAnyOtherTypeSharedQuery } + +query predicate problems(Cast c, string message) { + not isExcluded(c, getQuery()) and + not c.isImplicit() and + not c.isAffectedByMacro() and + c.getExpr().getType() instanceof FunctionPointerType and + message = "Cast converting a pointer to function." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/catchexceptionsbylvaluereference/CatchExceptionsByLvalueReference.qll b/cpp/common/src/codingstandards/cpp/rules/catchexceptionsbylvaluereference/CatchExceptionsByLvalueReference.qll index 75c86e50dc..81fd306d86 100644 --- a/cpp/common/src/codingstandards/cpp/rules/catchexceptionsbylvaluereference/CatchExceptionsByLvalueReference.qll +++ b/cpp/common/src/codingstandards/cpp/rules/catchexceptionsbylvaluereference/CatchExceptionsByLvalueReference.qll @@ -6,7 +6,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType import codingstandards.cpp.exceptions.ExceptionFlow abstract class CatchExceptionsByLvalueReferenceSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/charactersequenceusedwithinacstylecomment/CharacterSequenceUsedWithinACStyleComment.qll b/cpp/common/src/codingstandards/cpp/rules/charactersequenceusedwithinacstylecomment/CharacterSequenceUsedWithinACStyleComment.qll new file mode 100644 index 0000000000..676b2d3030 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/charactersequenceusedwithinacstylecomment/CharacterSequenceUsedWithinACStyleComment.qll @@ -0,0 +1,18 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The presence of a nested /* comment can indicate accidentally commented out code. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class CharacterSequenceUsedWithinACStyleCommentSharedQuery extends Query { } + +Query getQuery() { result instanceof CharacterSequenceUsedWithinACStyleCommentSharedQuery } + +query predicate problems(CStyleComment c, string message) { + not isExcluded(c, getQuery()) and + exists(c.getContents().regexpFind("./\\*", _, _)) and + message = "C-style /* comment includes nested /*." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/commaoperatorused/CommaOperatorUsed.qll b/cpp/common/src/codingstandards/cpp/rules/commaoperatorused/CommaOperatorUsed.qll index a6a80969b8..6985f7fc1e 100644 --- a/cpp/common/src/codingstandards/cpp/rules/commaoperatorused/CommaOperatorUsed.qll +++ b/cpp/common/src/codingstandards/cpp/rules/commaoperatorused/CommaOperatorUsed.qll @@ -1,5 +1,6 @@ /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library with a `problems` predicate for the following issue: + * The comma operator shall not be used. */ import cpp diff --git a/cpp/common/src/codingstandards/cpp/rules/constlikereturnvalue/ConstLikeReturnValue.qll b/cpp/common/src/codingstandards/cpp/rules/constlikereturnvalue/ConstLikeReturnValue.qll index f4636b6b13..a366991714 100644 --- a/cpp/common/src/codingstandards/cpp/rules/constlikereturnvalue/ConstLikeReturnValue.qll +++ b/cpp/common/src/codingstandards/cpp/rules/constlikereturnvalue/ConstLikeReturnValue.qll @@ -1,11 +1,14 @@ /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library with a `problems` predicate for the following issue: + * The pointers returned by the Standard Library functions localeconv, getenv, + * setlocale or, strerror shall only be used as if they have pointer to + * const-qualified type. */ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import DFFlow::PathGraph abstract class ConstLikeReturnValueSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/containeraccesswithoutrangecheck/ContainerAccessWithoutRangeCheck.qll b/cpp/common/src/codingstandards/cpp/rules/containeraccesswithoutrangecheck/ContainerAccessWithoutRangeCheck.qll index 71e18a5c05..fcf20afbc0 100644 --- a/cpp/common/src/codingstandards/cpp/rules/containeraccesswithoutrangecheck/ContainerAccessWithoutRangeCheck.qll +++ b/cpp/common/src/codingstandards/cpp/rules/containeraccesswithoutrangecheck/ContainerAccessWithoutRangeCheck.qll @@ -12,7 +12,7 @@ import codingstandards.cpp.Operator import semmle.code.cpp.controlflow.Guards private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.valuenumbering.GlobalValueNumbering abstract class ContainerAccessWithoutRangeCheckSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/copyandmoveassignmentsshallhandleselfassignment/CopyAndMoveAssignmentsShallHandleSelfAssignment.qll b/cpp/common/src/codingstandards/cpp/rules/copyandmoveassignmentsshallhandleselfassignment/CopyAndMoveAssignmentsShallHandleSelfAssignment.qll new file mode 100644 index 0000000000..ae87176517 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/copyandmoveassignmentsshallhandleselfassignment/CopyAndMoveAssignmentsShallHandleSelfAssignment.qll @@ -0,0 +1,53 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * User-provided copy assignment operators and move assignment operators shall handle + * self-assignment. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Operator + +abstract class CopyAndMoveAssignmentsShallHandleSelfAssignmentSharedQuery extends Query { } + +Query getQuery() { result instanceof CopyAndMoveAssignmentsShallHandleSelfAssignmentSharedQuery } + +predicate isUserCopyOrUserMove(Operator o) { + o instanceof UserCopyOperator or + o instanceof UserMoveOperator +} + +predicate callsStdSwap(Function f) { + exists(FunctionCall fc | + fc.getTarget().hasGlobalOrStdName("swap") and + fc.getEnclosingFunction() = f + ) +} + +predicate callsNoExceptSwap(Operator o) { + exists(Function f, FunctionCall fc | + callsStdSwap(f) and + fc.getEnclosingFunction() = o and + fc.getTarget() = f + ) +} + +predicate checksForSelfAssignment(Operator o) { + exists(IfStmt i, ComparisonOperation c | + i.getEnclosingFunction() = o and + i.getCondition() = c and + ( + c.getLeftOperand().toString() = "this" or + c.getRightOperand().toString() = "this" + ) + ) +} + +query predicate problems(Operator o, string message) { + not isExcluded(o, getQuery()) and + isUserCopyOrUserMove(o) and + not callsNoExceptSwap(o) and + not checksForSelfAssignment(o) and + message = "User defined copy or user defined move does not handle self-assignment correctly." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/csignalfunctionsused/CsignalFunctionsUsed.qll b/cpp/common/src/codingstandards/cpp/rules/csignalfunctionsused/CsignalFunctionsUsed.qll new file mode 100644 index 0000000000..15c71018f9 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/csignalfunctionsused/CsignalFunctionsUsed.qll @@ -0,0 +1,21 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Signal handling contains implementation-defined and undefined behaviour. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class CsignalFunctionsUsedSharedQuery extends Query { } + +Query getQuery() { result instanceof CsignalFunctionsUsedSharedQuery } + +query predicate problems(FunctionCall fc, string message) { + exists(Function f | + not isExcluded(fc, getQuery()) and + f = fc.getTarget() and + f.hasGlobalOrStdName(["signal", "raise"]) and + message = "Use of function '" + f.getQualifiedName() + "'." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/csignaltypesused/CsignalTypesUsed.qll b/cpp/common/src/codingstandards/cpp/rules/csignaltypesused/CsignalTypesUsed.qll new file mode 100644 index 0000000000..21de1066f6 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/csignaltypesused/CsignalTypesUsed.qll @@ -0,0 +1,21 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Signal handling contains implementation-defined and undefined behaviour. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class CsignalTypesUsedSharedQuery extends Query { } + +Query getQuery() { result instanceof CsignalTypesUsedSharedQuery } + +query predicate problems(TypeMention tm, string message) { + exists(UserType ut | + not isExcluded(tm, getQuery()) and + ut = tm.getMentionedType() and + ut.hasGlobalOrStdName("sig_atomic_t") and + message = "Use of type '" + ut.getQualifiedName() + "'." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/cstdiofunctionsused/CstdioFunctionsUsed.qll b/cpp/common/src/codingstandards/cpp/rules/cstdiofunctionsused/CstdioFunctionsUsed.qll new file mode 100644 index 0000000000..284997dc19 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/cstdiofunctionsused/CstdioFunctionsUsed.qll @@ -0,0 +1,38 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Streams and file I/O have a large number of unspecified, undefined, and + * implementation-defined behaviours associated with them. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class CstdioFunctionsUsedSharedQuery extends Query { } + +Query getQuery() { result instanceof CstdioFunctionsUsedSharedQuery } + +query predicate problems(FunctionCall fc, string message) { + exists(Function f | + not isExcluded(fc, getQuery()) and + f = fc.getTarget() and + f.hasGlobalOrStdName([ + "remove", "rename", "tmpfile", "tmpnam", + // File access + "fclose", "fflush", "fopen", "freopen", "setbuf", "setvbuf", + // Formatted input/output + "fprintf", "fscanf", "printf", "scanf", "snprintf", "sprintf", "sscanf", "vfprintf", + "vfscanf", "vprintf", "vscanf", "vsnprintf", "vsprintf", "vsscanf", + // Character input/output + "fgetc", "fgets", "fputc", "fputs", "getc", "getchar", "gets", "putc", "putchar", "puts", + "ungetc", + // Direct input/output + "fread", "fwrite", + // File positioning + "fgetpos", "fseek", "fsetpos", "ftell", "rewind", + // Error handling + "clearerr", "feof", "ferror", "perror" + ]) and + message = "Use of function '" + f.getQualifiedName() + "'." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/cstdiomacrosused/CstdioMacrosUsed.qll b/cpp/common/src/codingstandards/cpp/rules/cstdiomacrosused/CstdioMacrosUsed.qll new file mode 100644 index 0000000000..d610b6a166 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/cstdiomacrosused/CstdioMacrosUsed.qll @@ -0,0 +1,22 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Streams and file I/O have a large number of unspecified, undefined, and + * implementation-defined behaviours associated with them. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class CstdioMacrosUsedSharedQuery extends Query { } + +Query getQuery() { result instanceof CstdioMacrosUsedSharedQuery } + +query predicate problems(MacroInvocation mi, string message) { + not isExcluded(mi, getQuery()) and + mi.getMacroName() in [ + "BUFSIZ", "EOF", "FILENAME_MAX", "FOPEN_MAX", "L_tmpnam", "TMP_MAX", "_IOFBF", "IOLBF", + "_IONBF", "SEEK_CUR", "SEEK_END", "SEEK_SET" + ] and + message = "Use of macro '" + mi.getMacroName() + "'." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/cstdiotypesused/CstdioTypesUsed.qll b/cpp/common/src/codingstandards/cpp/rules/cstdiotypesused/CstdioTypesUsed.qll new file mode 100644 index 0000000000..d517d78c8b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/cstdiotypesused/CstdioTypesUsed.qll @@ -0,0 +1,27 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Streams and file I/O have a large number of unspecified, undefined, and + * implementation-defined behaviours associated with them. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class CstdioTypesUsedSharedQuery extends Query { } + +Query getQuery() { result instanceof CstdioTypesUsedSharedQuery } + +query predicate problems(TypeMention tm, string message) { + exists(UserType ut | + not isExcluded(tm, getQuery()) and + ut = tm.getMentionedType() and + ut.hasGlobalOrStdName(["FILE", "fpos_t"]) and + // Not in the standard library + exists(tm.getFile().getRelativePath()) and + // Not in our tests copy of the standard library + not tm.getFile().getRelativePath() = + ["includes/standard-library/stddef.h", "includes/standard-library/stdio.h"] and + message = "Use of type '" + ut.getQualifiedName() + "'." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/danglingcapturewhenmovinglambdaobject/DanglingCaptureWhenMovingLambdaObject.qll b/cpp/common/src/codingstandards/cpp/rules/danglingcapturewhenmovinglambdaobject/DanglingCaptureWhenMovingLambdaObject.qll index ab2b067279..902d0ecf1f 100644 --- a/cpp/common/src/codingstandards/cpp/rules/danglingcapturewhenmovinglambdaobject/DanglingCaptureWhenMovingLambdaObject.qll +++ b/cpp/common/src/codingstandards/cpp/rules/danglingcapturewhenmovinglambdaobject/DanglingCaptureWhenMovingLambdaObject.qll @@ -5,7 +5,7 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.Expr diff --git a/cpp/common/src/codingstandards/cpp/rules/danglingcapturewhenreturninglambdaobject/DanglingCaptureWhenReturningLambdaObject.qll b/cpp/common/src/codingstandards/cpp/rules/danglingcapturewhenreturninglambdaobject/DanglingCaptureWhenReturningLambdaObject.qll index c35b723ff3..4ab01520f6 100644 --- a/cpp/common/src/codingstandards/cpp/rules/danglingcapturewhenreturninglambdaobject/DanglingCaptureWhenReturningLambdaObject.qll +++ b/cpp/common/src/codingstandards/cpp/rules/danglingcapturewhenreturninglambdaobject/DanglingCaptureWhenReturningLambdaObject.qll @@ -5,7 +5,7 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions diff --git a/cpp/common/src/codingstandards/cpp/rules/deadcode/DeadCode.qll b/cpp/common/src/codingstandards/cpp/rules/deadcode/DeadCode.qll index 4a008dc15a..fb0bd772a2 100644 --- a/cpp/common/src/codingstandards/cpp/rules/deadcode/DeadCode.qll +++ b/cpp/common/src/codingstandards/cpp/rules/deadcode/DeadCode.qll @@ -12,10 +12,12 @@ */ import cpp +import codingstandards.cpp.alertreporting.HoldsForAllCopies import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.deadcode.UselessAssignments import codingstandards.cpp.deadcode.UnreachableCode +import codingstandards.cpp.deadcode.UnusedVariables abstract class DeadCodeSharedQuery extends Query { } @@ -30,15 +32,12 @@ predicate isDeadOrUnreachableStmt(Stmt s) { s.getBasicBlock() = any(UnreachableBasicBlock ubb).getABasicBlock() } -/** - * Holds if the `Stmt` `s` is dead, i.e. could be executed, but its removal would not meaningfully - * affect the program. - */ predicate isDeadStmt(Stmt s) { // A `DeclStmt` is dead code if: // - All the declarations are variable declarations // - None of those variables are ever accessed in non-dead code // - The initializers for each of the variables are pure + // - It isn't constexpr and used to declare an array size exists(DeclStmt ds | ds = s and // Use forex so that we don't flag "fake" generated `DeclStmt`s (e.g. those generated by the @@ -50,7 +49,8 @@ predicate isDeadStmt(Stmt s) { not exists(VariableAccess va | va.getTarget() = v and not isDeadOrUnreachableStmt(va.getEnclosingStmt()) - ) + ) and + not countUsesInLocalArraySize(v) > 0 ) ) ) @@ -105,17 +105,33 @@ predicate isDeadStmt(Stmt s) { exists(TryStmt ts | s = ts and isDeadStmt(ts.getStmt())) } -query predicate problems(Stmt s, string message) { - not isExcluded(s, getQuery()) and +/** + * Holds if the `Stmt` `s` is dead, i.e. could be executed, but its removal would not meaningfully + * affect the program. + */ +class DeadStmtInstance extends Stmt { + DeadStmtInstance() { + isDeadStmt(this) and + // Exclude compiler generated statements + not this.isCompilerGenerated() and + // Exclude code fully generated by macros, because the code may be "live" in other expansions + isNotWithinMacroExpansion(this) and + // MISRA defines dead code as an "_executed_ statement whose removal would not affect the program + // output". We therefore exclude unreachable statements as they are, by definition, not executed. + not this.getBasicBlock() = any(UnreachableBasicBlock ubb).getABasicBlock() + } +} + +class DeadStmt = HoldsForAllCopies::LogicalResultElement; + +query predicate problems(DeadStmt s, string message) { + not isExcluded(s.getAnElementInstance(), getQuery()) and message = "This statement is dead code." and - isDeadStmt(s) and // Report only the highest level dead statement, to avoid over reporting - not isDeadStmt(s.getParentStmt()) and - // MISRA defines dead code as an "_executed_ statement whose removal would not affect the program - // output". We therefore exclude unreachable statements as they are, by definition, not executed. - not s.getBasicBlock() = any(UnreachableBasicBlock ubb).getABasicBlock() and - // Exclude code fully generated by macros, because the code may be "live" in other expansions - not s.isInMacroExpansion() and - // Exclude compiler generated statements - not s.isCompilerGenerated() + not exists(DeadStmt parent | + // All instances must share a dead statement parent for us to report the parent instead + forall(Stmt instance | instance = s.getAnElementInstance() | + parent.getAnElementInstance() = instance.getParentStmt() + ) + ) } diff --git a/cpp/common/src/codingstandards/cpp/rules/definitionnotconsideredforunqualifiedlookup/DefinitionNotConsideredForUnqualifiedLookup.qll b/cpp/common/src/codingstandards/cpp/rules/definitionnotconsideredforunqualifiedlookup/DefinitionNotConsideredForUnqualifiedLookup.qll new file mode 100644 index 0000000000..c2b857d600 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/definitionnotconsideredforunqualifiedlookup/DefinitionNotConsideredForUnqualifiedLookup.qll @@ -0,0 +1,70 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * A using declaration that makes a symbol available for unqualified lookup does not + * included definitions defined after the using declaration which can result in + * unexpected behavior. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class DefinitionNotConsideredForUnqualifiedLookupSharedQuery extends Query { } + +Query getQuery() { result instanceof DefinitionNotConsideredForUnqualifiedLookupSharedQuery } + +/** + * Holds if `functionDecl` is a possible intended target of the `usingDecl`. + */ +pragma[noinline] +predicate isPossibleIntendedTarget( + FunctionDeclarationEntry functionDecl, UsingDeclarationEntry usingDecl +) { + // Extracted to improve the join order. With this approach, we first compute a set of using + // declarations and a set of possible intended targets + functionDecl.getDeclaration().isTopLevel() and + functionDecl.getDeclaration().getQualifiedName() = usingDecl.getDeclaration().getQualifiedName() and + functionDecl.getDeclaration().getNamespace().getParentNamespace*() = usingDecl.getParentScope() +} + +/** + * Holds if `functionDecl` is a possible intended target of the `usingDecl`, and they exist at the + * given locations. + */ +pragma[noinline] +predicate isPossibleIntendedTargetLocation( + FunctionDeclarationEntry functionDecl, UsingDeclarationEntry usingDecl, File usingsFile, + File unavailableFile, int usingsStartLine, int unavailableStartLine +) { + // Extracted to improve the join order. With this approach, we take the set of possible intended + // targets computed in isPossibleIntendedTargets, and compute the files and start lines. + // This helps avoid the join order preferred by the optimiser if this is all written directly in + // the from-where-select, where it will eagerly join: + // + // usingDeclarationEntries -> enclosing files -> all other elements in those files + // + // which is expensive when there are a lot of files with using declarations + isPossibleIntendedTarget(functionDecl, usingDecl) and + usingsFile = usingDecl.getFile() and + unavailableFile = functionDecl.getFile() and + usingsStartLine = usingDecl.getLocation().getStartLine() and + unavailableStartLine = functionDecl.getLocation().getStartLine() +} + +query predicate problems( + FunctionDeclarationEntry unavailableDecl, string message, UsingDeclarationEntry usingDecl, + string usingDecl_string +) { + not isExcluded(unavailableDecl, getQuery()) and + exists(File usingsFile, File unavailableFile, int usingsStartLine, int unavailableStartLine | + isPossibleIntendedTargetLocation(unavailableDecl, usingDecl, usingsFile, unavailableFile, + usingsStartLine, unavailableStartLine) and + // An approximation of order where we want the using to preceed the new declaration. + usingsFile = unavailableFile and + usingsStartLine < unavailableStartLine + ) and + message = + "Definition for '" + unavailableDecl.getName() + + "' is not available for unqualified lookup because it is declared after $@" and + usingDecl_string = "using-declaration" +} diff --git a/cpp/common/src/codingstandards/cpp/rules/dereferenceofnullpointer/DereferenceOfNullPointer.qll b/cpp/common/src/codingstandards/cpp/rules/dereferenceofnullpointer/DereferenceOfNullPointer.qll index 5e3328cb63..950b14df3d 100644 --- a/cpp/common/src/codingstandards/cpp/rules/dereferenceofnullpointer/DereferenceOfNullPointer.qll +++ b/cpp/common/src/codingstandards/cpp/rules/dereferenceofnullpointer/DereferenceOfNullPointer.qll @@ -1,5 +1,6 @@ /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library with a `problems` predicate for the following issue: + * Dereferencing a NULL pointer leads to undefined behavior. */ import cpp diff --git a/cpp/common/src/codingstandards/cpp/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.qll b/cpp/common/src/codingstandards/cpp/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.qll index 87a4580ab3..5c7475883e 100644 --- a/cpp/common/src/codingstandards/cpp/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.qll +++ b/cpp/common/src/codingstandards/cpp/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.qll @@ -46,16 +46,32 @@ string step1(string s) { string step2(string s) { s = "m_" and result = "rn" } -predicate violation(UserVariable v1, UserVariable v2) { - v2 = getPotentialScopeOfVariable(v1) and +class VariableName extends string { + VariableName() { exists(UserVariable uv | uv.getName() = this) } + + string getCanon() { + result = + this.toLowerCase() + .replaceAll("_", "") + .regexpReplaceAll("[il]", "1") + .replaceAll("s", "5") + .replaceAll("z", "2") + .replaceAll("b", "8") + .replaceAll("h", "n") + .replaceAll("m", "rn") + .replaceAll("o", "0") + } +} + +predicate isConflictingName(VariableName name1, VariableName name2) { exists(string s1, string s2 | // over-approximate a match, because it is cheaper to compute - getCanon(v1) = getCanon(v2) and - v1 != v2 and - not v1.getName() = v2.getName() and + name1.getCanon() = name2.getCanon() and + // Exclude identical names + not name1 = name2 and // expand 'm' to 'm_' to match either 'm_' or 'rn' - s1 = v1.getName().replaceAll("_", "").replaceAll("m", "m_") and - s2 = v2.getName().replaceAll("_", "").replaceAll("m", "m_") and + s1 = name1.replaceAll("_", "").replaceAll("m", "m_") and + s2 = name2.replaceAll("_", "").replaceAll("m", "m_") and // at this point the strings must have equal length, the substitutions do not expand nor contract the string s1.length() = s2.length() and forall(int i | i in [0 .. s1.length() - 1] | @@ -87,6 +103,23 @@ predicate violation(UserVariable v1, UserVariable v2) { ) } +predicate violation(UserVariable v1, UserVariable v2) { + exists(string name1, string name2 | + isConflictingName(name1, name2) and + exists(Scope parentScope, Scope childScope | + parentScope.getVariable(name1) = v1 and + childScope.getVariable(name2) = v2 + | + childScope.getStrictParent+() = parentScope + or + // Disambiguate names in the same scope by name order + childScope = parentScope and + name1 < name2 + ) and + inSameTranslationUnitLate(v1.getFile(), v2.getFile()) + ) +} + query predicate problems( UserVariable v, string message, UserVariable v1, string v1Description, UserVariable v2, string v2Description diff --git a/cpp/common/src/codingstandards/cpp/rules/donotaccessaclosedfile/DoNotAccessAClosedFile.qll b/cpp/common/src/codingstandards/cpp/rules/donotaccessaclosedfile/DoNotAccessAClosedFile.qll index 3d84366d9a..83266ed524 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotaccessaclosedfile/DoNotAccessAClosedFile.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotaccessaclosedfile/DoNotAccessAClosedFile.qll @@ -6,7 +6,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.standardlibrary.FileAccess import semmle.code.cpp.controlflow.SubBasicBlocks diff --git a/cpp/common/src/codingstandards/cpp/rules/donotallowamutextogooutofscopewhilelocked/DoNotAllowAMutexToGoOutOfScopeWhileLocked.qll b/cpp/common/src/codingstandards/cpp/rules/donotallowamutextogooutofscopewhilelocked/DoNotAllowAMutexToGoOutOfScopeWhileLocked.qll index 8a8155f971..759d235eb4 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotallowamutextogooutofscopewhilelocked/DoNotAllowAMutexToGoOutOfScopeWhileLocked.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotallowamutextogooutofscopewhilelocked/DoNotAllowAMutexToGoOutOfScopeWhileLocked.qll @@ -17,7 +17,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.Concurrency -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking abstract class DoNotAllowAMutexToGoOutOfScopeWhileLockedSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/donotdestroyamutexwhileitislocked/DoNotDestroyAMutexWhileItIsLocked.qll b/cpp/common/src/codingstandards/cpp/rules/donotdestroyamutexwhileitislocked/DoNotDestroyAMutexWhileItIsLocked.qll index 46335c3d94..d77ae8cf39 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotdestroyamutexwhileitislocked/DoNotDestroyAMutexWhileItIsLocked.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotdestroyamutexwhileitislocked/DoNotDestroyAMutexWhileItIsLocked.qll @@ -15,7 +15,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.Concurrency -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking abstract class DoNotDestroyAMutexWhileItIsLockedSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.qll b/cpp/common/src/codingstandards/cpp/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.qll new file mode 100644 index 0000000000..79eda7714d --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.qll @@ -0,0 +1,193 @@ +/** + * Provides a library which includes a `problems` predicate for reporting.... + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.types.Pointers +import codingstandards.cpp.Variable +import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.pointsto.PointsTo +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis + +/** + * A function that has a parameter with a restrict-qualified pointer type. + */ +class FunctionWithRestrictParameters extends Function { + Parameter restrictPtrParam; + + FunctionWithRestrictParameters() { + restrictPtrParam.getUnspecifiedType() instanceof PointerOrArrayType and + ( + restrictPtrParam.getType().hasSpecifier(["restrict"]) and + restrictPtrParam = this.getAParameter() + or + this.hasGlobalName(["strcpy", "strncpy", "strcat", "strncat", "memcpy"]) and + restrictPtrParam = this.getParameter([0, 1]) + or + this.hasGlobalName(["strcpy_s", "strncpy_s", "strcat_s", "strncat_s", "memcpy_s"]) and + restrictPtrParam = this.getParameter([0, 2]) + or + this.hasGlobalName(["strtok_s"]) and + restrictPtrParam = this.getAParameter() + or + this.hasGlobalName(["printf", "printf_s", "scanf", "scanf_s"]) and + restrictPtrParam = this.getParameter(0) + or + this.hasGlobalName(["sprintf", "sprintf_s", "snprintf", "snprintf_s"]) and + restrictPtrParam = this.getParameter(3) + ) + } + + Parameter getARestrictPtrParam() { result = restrictPtrParam } +} + +/** + * A call to a function that has a parameter with a restrict-qualified pointer type. + */ +class CallToFunctionWithRestrictParameters extends FunctionCall { + CallToFunctionWithRestrictParameters() { + this.getTarget() instanceof FunctionWithRestrictParameters + } + + Expr getARestrictPtrArg() { + result = + this.getArgument(this.getTarget() + .(FunctionWithRestrictParameters) + .getARestrictPtrParam() + .getIndex()) + } + + Expr getAPtrArg(int index) { + result = this.getArgument(index) and + pointerValue(result) + } + + Expr getAPossibleSizeArg() { + exists(Parameter param | + param = this.getTarget().(FunctionWithRestrictParameters).getAParameter() and + param.getUnderlyingType() instanceof IntegralType and + // exclude __builtin_object_size + not result.(FunctionCall).getTarget() instanceof BuiltInFunction and + result = this.getArgument(param.getIndex()) + ) + } +} + +/** + * A `PointsToExpr` that is an argument of a pointer-type in a `CallToFunctionWithRestrictParameters` + */ +class CallToFunctionWithRestrictParametersArgExpr extends Expr { + int paramIndex; + + CallToFunctionWithRestrictParametersArgExpr() { + this = any(CallToFunctionWithRestrictParameters call).getAPtrArg(paramIndex) + } + + int getParamIndex() { result = paramIndex } +} + +int getStatedValue(Expr e) { + // `upperBound(e)` defaults to `exprMaxVal(e)` when `e` isn't analyzable. So to get a meaningful + // result in this case we pick the minimum value obtainable from dataflow and range analysis. + result = + upperBound(e) + .minimum(min(Expr source | DataFlow::localExprFlow(source, e) | source.getValue().toInt())) +} + +int getPointerArithmeticOperandStatedValue(CallToFunctionWithRestrictParametersArgExpr expr) { + result = getStatedValue(expr.(PointerArithmeticExpr).getOperand()) + or + // edge-case: &(array[index]) expressions + result = getStatedValue(expr.(AddressOfExpr).getOperand().(PointerArithmeticExpr).getOperand()) + or + // fall-back if `expr` is not a pointer arithmetic expression + not expr instanceof PointerArithmeticExpr and + not expr.(AddressOfExpr).getOperand() instanceof PointerArithmeticExpr and + result = 0 +} + +module PointerValueToRestrictArgConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { pointerValue(source.asExpr()) } + + predicate isSink(DataFlow::Node sink) { + exists(CallToFunctionWithRestrictParameters call | + sink.asExpr() = call.getAPtrArg(_).getAChild*() + ) + } + + predicate isBarrierIn(DataFlow::Node node) { + exists(AddressOfExpr a | node.asExpr() = a.getOperand().getAChild*()) + } +} + +module PointerValueToRestrictArgFlow = DataFlow::Global; + +abstract class DoNotPassAliasedPointerToRestrictQualifiedParamSharedSharedQuery extends Query { } + +Query getQuery() { + result instanceof DoNotPassAliasedPointerToRestrictQualifiedParamSharedSharedQuery +} + +query predicate problems( + CallToFunctionWithRestrictParameters call, string message, + CallToFunctionWithRestrictParametersArgExpr arg2, string arg2message, + CallToFunctionWithRestrictParametersArgExpr arg1, string arg1message, Expr source1, + string sourceMessage2, Expr source2, string lastMessage2 +) { + not isExcluded(call, getQuery()) and + exists(int argOffset1, int argOffset2, string sourceMessage1 | + arg1 = call.getARestrictPtrArg() and + arg2 = call.getAPtrArg(_) and + // enforce ordering to remove permutations if multiple restrict-qualified args exist + (not arg2 = call.getARestrictPtrArg() or arg2.getParamIndex() > arg1.getParamIndex()) and + ( + // check if two pointers address the same object + PointerValueToRestrictArgFlow::flow(DataFlow::exprNode(source1), + DataFlow::exprNode(arg1.getAChild*())) and + ( + // one pointer value flows to both args + PointerValueToRestrictArgFlow::flow(DataFlow::exprNode(source1), + DataFlow::exprNode(arg2.getAChild*())) and + sourceMessage1 = "$@" and + sourceMessage2 = "source" and + source1 = source2 + or + // there are two separate values that flow from an AddressOfExpr of the same target + getAddressOfExprTargetBase(source1) = getAddressOfExprTargetBase(source2) and + PointerValueToRestrictArgFlow::flow(DataFlow::exprNode(source2), + DataFlow::exprNode(arg2.getAChild*())) and + sourceMessage1 = "a pair of address-of expressions ($@, $@)" and + sourceMessage2 = "addressof1" and + not source1 = source2 + ) + ) and + // get the offset of the pointer arithmetic operand (or '0' if there is none) + argOffset1 = getPointerArithmeticOperandStatedValue(arg1) and + argOffset2 = getPointerArithmeticOperandStatedValue(arg2) and + ( + // case 1: the pointer args are the same. + // (definite aliasing) + argOffset1 = argOffset2 + or + // case 2: the pointer args are different, a size arg exists, + // and the size arg is greater than the difference between the offsets. + // (potential aliasing) + exists(Expr sizeArg | + sizeArg = call.getAPossibleSizeArg() and + getStatedValue(sizeArg) > (argOffset1 - argOffset2).abs() + ) + or + // case 3: the pointer args are different, and a size arg does not exist + // (potential aliasing) + not exists(call.getAPossibleSizeArg()) + ) and + lastMessage2 = "addressof2" and + arg2message = "aliased pointer" and + arg1message = "restrict-qualified parameter" and + message = + "Call to '" + call.getTarget().getName() + + "' passes an $@ to a $@ (pointer value derived from " + sourceMessage1 + "." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.qll b/cpp/common/src/codingstandards/cpp/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.qll index 0aa8d64feb..adb9785814 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.qll @@ -6,7 +6,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import ArrayToPointerDiffOperandFlow::PathGraph module ArrayToPointerDiffOperandConfig implements DataFlow::ConfigSig { diff --git a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll index dd10b840c5..5d3a7e1cda 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll @@ -7,20 +7,133 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.new.DataFlow import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis +import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils +import codeql.util.Boolean abstract class DoNotUsePointerArithmeticToAddressDifferentArraysSharedQuery extends Query { } Query getQuery() { result instanceof DoNotUsePointerArithmeticToAddressDifferentArraysSharedQuery } +/** + * A `VariableAccess` of a variable that is an array, or a pointer type casted to a byte pointer. + */ +abstract class ArrayLikeAccess extends Expr { + abstract Element getElement(); + + abstract string getName(); + + abstract int getSize(); + + abstract DataFlow::Node getNode(); +} + +/** + * A `VariableAccess` of a variable that is an array. + */ +class ArrayVariableAccess extends ArrayLikeAccess, VariableAccess { + int size; + + ArrayVariableAccess() { size = getType().(ArrayType).getArraySize() } + + override Variable getElement() { result = getTarget() } + + override string getName() { result = getElement().getName() } + + override int getSize() { result = size } + + override DataFlow::Node getNode() { result.asExpr() = this } +} + +/** + * Get the size of the object pointed to by a type (pointer or array). + * + * Depth of type unwrapping depends on the type. Pointer will be dereferenced only once: the element + * size of `T*` is `sizeof(T)` while the element size of `T**` is `sizeof(T*)`. However, array types + * will be deeply unwrapped, as the pointed to size of `T[][]` is `sizeof(T)`. These processes + * interact, so the element size of a pointer to an array of `T` has an element size of `sizeof(T)` + * and not `sizeof(T[length])`. + */ +int elementSize(Type type, Boolean deref) { + if type instanceof ArrayType + then result = elementSize(type.(ArrayType).getBaseType(), false) + else + if deref = true and type instanceof PointerType + then result = elementSize(type.(PointerType).getBaseType(), false) + else result = type.getSize() +} + +/** + * A pointer type casted to a byte pointer, which is effectively a pointer to a byte array whose + * length depends on `elementSize()` of the original pointed-to type. + */ +class CastedToBytePointer extends ArrayLikeAccess, Conversion { + /** The sizeof() the pointed-to type */ + int size; + + CastedToBytePointer() { + getType().(PointerType).getBaseType().getSize() = 1 and + size = elementSize(getExpr().getType(), true) and + size > 1 + } + + override Element getElement() { result = this } + + override string getName() { result = "cast to byte pointer" } + + override int getSize() { result = size } + + override DataFlow::Node getNode() { + // Carefully avoid use-use flow, which would mean any later usage of the original pointer value + // after the cast would be considered a usage of the byte pointer value. + // + // To fix this, we currently assume the value is assigned to a variable, and find that variable + // with `.asDefinition()` like so: + exists(DataFlow::Node conversion | + conversion.asConvertedExpr() = this and + result.asDefinition() = conversion.asExpr() + ) + } +} + +predicate pointerRecastBarrier(DataFlow::Node barrier) { + // Casting to a differently sized pointer + exists(CStyleCast cast, Expr casted | + cast.getExpr() = casted and casted = barrier.asConvertedExpr() + | + not casted.getType().(PointerType).getBaseType().getSize() = + cast.getType().(PointerType).getBaseType().getSize() + ) +} + +/** + * A data-flow configuration that tracks access to an array to type to an array index expression. + * This is used to determine possible pointer to array creations. + */ +module ByteArrayToArrayExprConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { exists(CastedToBytePointer a | a.getNode() = source) } + + predicate isBarrier(DataFlow::Node barrier) { + // Casting to a differently sized pointer invalidates this analysis. + pointerRecastBarrier(barrier) + } + + predicate isSink(DataFlow::Node sink) { exists(ArrayExpr c | c.getArrayBase() = sink.asExpr()) } +} + +module BytePointerToArrayExprFlow = DataFlow::Global; + /** * A data-flow configuration that tracks access to an array to type to an array index expression. * This is used to determine possible pointer to array creations. */ module ArrayToArrayExprConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { - source.asExpr().(VariableAccess).getType() instanceof ArrayType + predicate isSource(DataFlow::Node source) { exists(ArrayVariableAccess a | a.getNode() = source) } + + predicate isBarrier(DataFlow::Node barrier) { + // Casting to a differently sized pointer invalidates this analysis. + pointerRecastBarrier(barrier) } predicate isSink(DataFlow::Node sink) { exists(ArrayExpr c | c.getArrayBase() = sink.asExpr()) } @@ -28,32 +141,39 @@ module ArrayToArrayExprConfig implements DataFlow::ConfigSig { module ArrayToArrayExprFlow = DataFlow::Global; -/** Holds if the address taken expression `addressOf` takes the address of an array element at `index` of `array` with size `arraySize`. */ -predicate pointerOperandCreation(AddressOfExpr addressOf, Variable array, int arraySize, int index) { - arraySize = array.getType().(ArrayType).getArraySize() and - exists(ArrayExpr ae | - ArrayToArrayExprFlow::flow(DataFlow::exprNode(array.getAnAccess()), - DataFlow::exprNode(ae.getArrayBase())) and - index = lowerBound(ae.getArrayOffset().getFullyConverted()) and +/** Holds if the address taken expression `addressOf` takes the address of an array element at `index` of `array`. */ +predicate pointerOperandCreation(AddressOfExpr addressOf, ArrayLikeAccess array, int index) { + exists(ArrayExpr ae, Expr arrayOffset | + ( + ArrayToArrayExprFlow::flow(array.getNode(), DataFlow::exprNode(ae.getArrayBase())) and + array instanceof ArrayVariableAccess + or + // Since casts can occur in the middle of flow, barriers are not perfect for modeling the + // desired behavior. Handle casts to byte pointers as sources in a separate flow analysis. + BytePointerToArrayExprFlow::flow(array.getNode(), DataFlow::exprNode(ae.getArrayBase())) and + // flow() may hold for `ArrayVariableAccess` in the above, even though they aren't sources + array instanceof CastedToBytePointer + ) and + arrayOffset = ae.getArrayOffset().getFullyConverted() and + index = lowerBound(arrayOffset) and + // This case typically indicates range analysis has gone wrong: + not index = exprMaxVal(arrayOffset) and addressOf.getOperand() = ae ) } /** A variable that points to an element of an array. */ class PointerOperand extends Variable { - Variable array; - int arraySize; + ArrayLikeAccess array; int index; AddressOfExpr source; PointerOperand() { - pointerOperandCreation(source, array, arraySize, index) and + pointerOperandCreation(source, array, index) and this.getAnAssignedValue() = source } - Variable getArray() { result = array } - - int getArraySize() { result = arraySize } + ArrayLikeAccess getArray() { result = array } int getIndex() { result = index } @@ -111,9 +231,7 @@ class DerivedArrayPointer extends Variable { DerivedArrayPointer() { derivedPointer(this, source, operand, index) } - Variable getArray() { result = operand.getArray() } - - int getArraySize() { result = operand.getArraySize() } + ArrayLikeAccess getArray() { result = operand.getArray() } int getIndex() { result = index } @@ -131,15 +249,10 @@ class DerivedArrayPointerOrPointerOperand extends Variable { this instanceof PointerOperand } - Variable getArray() { + ArrayLikeAccess getArray() { result = this.(DerivedArrayPointer).getArray() or result = this.(PointerOperand).getArray() } - int getArraySize() { - result = this.(DerivedArrayPointer).getArraySize() or - result = this.(PointerOperand).getArraySize() - } - int getIndex() { result = this.(DerivedArrayPointer).getIndex() or result = this.(PointerOperand).getIndex() } @@ -149,14 +262,16 @@ class DerivedArrayPointerOrPointerOperand extends Variable { } } -query predicate problems(Expr arrayPointerCreation, string message, Variable array, string arrayName) { +query predicate problems(Expr arrayPointerCreation, string message, Element array, string arrayName) { not isExcluded(arrayPointerCreation, getQuery()) and exists( DerivedArrayPointerOrPointerOperand derivedArrayPointerOrPointerOperand, int index, - int arraySize, int difference, string denomination + ArrayLikeAccess arrayAccess, int arraySize, int difference, string denomination | - array = derivedArrayPointerOrPointerOperand.getArray() and - arraySize = derivedArrayPointerOrPointerOperand.getArraySize() and + arrayAccess = derivedArrayPointerOrPointerOperand.getArray() and + array = arrayAccess.getElement() and + arrayName = arrayAccess.getName() and + arraySize = arrayAccess.getSize() and index = derivedArrayPointerOrPointerOperand.getIndex() and arrayPointerCreation = derivedArrayPointerOrPointerOperand.getSource() and difference = index - arraySize and @@ -173,7 +288,6 @@ query predicate problems(Expr arrayPointerCreation, string message, Variable arr ) and message = "Array pointer " + derivedArrayPointerOrPointerOperand.getName() + " points " + - (index - arraySize).toString() + " " + denomination + " passed the end of $@." - ) and - arrayName = array.getName() + difference.toString() + " " + denomination + " past the end of $@." + ) } diff --git a/cpp/common/src/codingstandards/cpp/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.qll b/cpp/common/src/codingstandards/cpp/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.qll index 155ed1a7f4..aa8fa29bfd 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.qll @@ -7,7 +7,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import ArrayToRelationalOperationOperandFlow::PathGraph abstract class DoNotUseRelationalOperatorsWithDifferingArraysSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/donotusesetjmporlongjmpshared/DoNotUseSetjmpOrLongjmpShared.qll b/cpp/common/src/codingstandards/cpp/rules/donotusesetjmporlongjmpshared/DoNotUseSetjmpOrLongjmpShared.qll index 6c39b62fec..1441b6ec97 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotusesetjmporlongjmpshared/DoNotUseSetjmpOrLongjmpShared.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotusesetjmporlongjmpshared/DoNotUseSetjmpOrLongjmpShared.qll @@ -1,5 +1,6 @@ /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library with a `problems` predicate for the following issue: + * The macro setjmp and function longjmp shall not be used. */ import cpp diff --git a/cpp/common/src/codingstandards/cpp/rules/emptythrowonlywithinacatchhandler/EmptyThrowOnlyWithinACatchHandler.qll b/cpp/common/src/codingstandards/cpp/rules/emptythrowonlywithinacatchhandler/EmptyThrowOnlyWithinACatchHandler.qll new file mode 100644 index 0000000000..3dba1a3aa3 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/emptythrowonlywithinacatchhandler/EmptyThrowOnlyWithinACatchHandler.qll @@ -0,0 +1,19 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Empty throws with no currently handled exception can cause abrupt program + * termination. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class EmptyThrowOnlyWithinACatchHandlerSharedQuery extends Query { } + +Query getQuery() { result instanceof EmptyThrowOnlyWithinACatchHandlerSharedQuery } + +query predicate problems(ReThrowExpr re, string message) { + not isExcluded(re, getQuery()) and + not re.getEnclosingElement+() instanceof CatchBlock and + message = "Rethrow outside catch block" +} diff --git a/cpp/common/src/codingstandards/cpp/rules/enumerationnotdefinedwithanexplicitunderlyingtype/EnumerationNotDefinedWithAnExplicitUnderlyingType.qll b/cpp/common/src/codingstandards/cpp/rules/enumerationnotdefinedwithanexplicitunderlyingtype/EnumerationNotDefinedWithAnExplicitUnderlyingType.qll new file mode 100644 index 0000000000..d014e7be86 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/enumerationnotdefinedwithanexplicitunderlyingtype/EnumerationNotDefinedWithAnExplicitUnderlyingType.qll @@ -0,0 +1,18 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Although scoped enum will implicitly define an underlying type of int, the underlying base type of enumeration should always be explicitly defined with a type that will be large enough to store all enumerators. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class EnumerationNotDefinedWithAnExplicitUnderlyingTypeSharedQuery extends Query { } + +Query getQuery() { result instanceof EnumerationNotDefinedWithAnExplicitUnderlyingTypeSharedQuery } + +query predicate problems(Enum e, string message) { + not isExcluded(e, getQuery()) and + not e.hasExplicitUnderlyingType() and + message = "Base type of enumeration is not explicitly specified." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/exceptionobjecthavepointertype/ExceptionObjectHavePointerType.qll b/cpp/common/src/codingstandards/cpp/rules/exceptionobjecthavepointertype/ExceptionObjectHavePointerType.qll new file mode 100644 index 0000000000..1989afbc8b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/exceptionobjecthavepointertype/ExceptionObjectHavePointerType.qll @@ -0,0 +1,20 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Throwing an exception of pointer type can lead to use-after-free or memory leak + * issues. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class ExceptionObjectHavePointerTypeSharedQuery extends Query { } + +Query getQuery() { result instanceof ExceptionObjectHavePointerTypeSharedQuery } + +query predicate problems(Expr thrownExpr, string message) { + not isExcluded(thrownExpr, getQuery()) and + thrownExpr = any(ThrowExpr te).getExpr() and + thrownExpr.getType().getUnspecifiedType() instanceof PointerType and + message = "Exception object with pointer type " + thrownExpr.getType() + " is thrown here." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.qll b/cpp/common/src/codingstandards/cpp/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.qll index 16f86f78be..5a712dd522 100644 --- a/cpp/common/src/codingstandards/cpp/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.qll +++ b/cpp/common/src/codingstandards/cpp/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.qll @@ -4,43 +4,17 @@ */ import cpp -import semmle.code.cpp.controlflow.SubBasicBlocks import codingstandards.cpp.Exclusions import codingstandards.cpp.Customizations import codingstandards.cpp.exceptions.ExceptionFlow import codingstandards.cpp.ExceptionSafety import codingstandards.cpp.resources.ResourceManagement +import codingstandards.cpp.resources.ResourceLeakAnalysis abstract class ExceptionSafetyValidStateSharedQuery extends Query { } Query getQuery() { result instanceof ExceptionSafetyValidStateSharedQuery } -/** - * Ensures that `UncaughtThrowExpr` and `Expr` appear at the start of a `SubBasicBlock`. - */ -class SafetyValidStateSubBasicBlock extends SubBasicBlockCutNode { - SafetyValidStateSubBasicBlock() { - this instanceof ResourceAcquisitionExpr or - this = any(ResourceAcquisitionExpr rae).getReleaseExpr() or - this instanceof UncaughtThrowExpr - } -} - -/** - * Execution continues from an allocation expression - * without releasing the resource - */ -SubBasicBlock followsInitialized(ResourceAcquisitionExpr src) { - result = src - or - exists(SubBasicBlock mid | - mid = followsInitialized(src) and - result = mid.getASuccessor() and - //stop recursion on resource release - not result = src.getReleaseExpr() - ) -} - /** * `UncaughtThrowExpr` models a `throw` expression that is not handled */ @@ -48,14 +22,25 @@ class UncaughtThrowExpr extends ThrowExpr { UncaughtThrowExpr() { getASuccessor() = getEnclosingFunction() } } -query predicate problems( - UncaughtThrowExpr te, string message, ResourceAcquisitionExpr e, string eDescription -) { +module ThrowLeakConfig implements ResourceLeakConfigSig { + predicate isAllocate(ControlFlowNode node, DataFlow::Node resource) { + ResourceLeakConfig::isAllocate(node, resource) + } + + predicate isFree(ControlFlowNode node, DataFlow::Node resource) { + ResourceLeakConfig::isFree(node, resource) + } + + ControlFlowNode outOfScope(ControlFlowNode allocPoint) { + result.(UncaughtThrowExpr).getEnclosingFunction() = allocPoint.(Expr).getEnclosingFunction() + } + + DataFlow::Node getAnAlias(DataFlow::Node node) { DataFlow::localFlow(node, result) } +} + +query predicate problems(UncaughtThrowExpr te, string message, Element e, string eDescription) { not isExcluded(te, getQuery()) and - exists(SubBasicBlock sbb | - sbb.getANode() = e and - te = followsInitialized(sbb) - ) and + te = ResourceLeak::getALeak(e) and message = "The $@ is not released explicitly before throwing an exception." and eDescription = "allocated resource" } diff --git a/cpp/common/src/codingstandards/cpp/rules/forwardingreferencesandforwardnotusedtogether/ForwardingReferencesAndForwardNotUsedTogether.qll b/cpp/common/src/codingstandards/cpp/rules/forwardingreferencesandforwardnotusedtogether/ForwardingReferencesAndForwardNotUsedTogether.qll new file mode 100644 index 0000000000..960b4ba2b6 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/forwardingreferencesandforwardnotusedtogether/ForwardingReferencesAndForwardNotUsedTogether.qll @@ -0,0 +1,28 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Forwarding references and std::forward shall be used together. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.standardlibrary.Utility + +abstract class ForwardingReferencesAndForwardNotUsedTogetherSharedQuery extends Query { } + +Query getQuery() { result instanceof ForwardingReferencesAndForwardNotUsedTogetherSharedQuery } + +query predicate problems(FunctionCall c, string message, Parameter a, string a_string) { + not isExcluded(c, getQuery()) and + a_string = a.getName() and + a.getAnAccess() = c.getAnArgument() and + ( + c instanceof StdMoveCall and + a instanceof ForwardParameter and + message = "Function `std::forward` should be used for forwarding the forward reference $@." + or + c instanceof StdForwardCall and + a instanceof ConsumeParameter and + message = "Function `std::move` should be used for forwarding rvalue reference $@." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.qll b/cpp/common/src/codingstandards/cpp/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.qll new file mode 100644 index 0000000000..93177e4f46 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.qll @@ -0,0 +1,62 @@ +/** + * Provides a library which includes a `problems` predicate for reporting unchecked error values. + */ + +import cpp +import codingstandards.cpp.Customizations +import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.controlflow.Guards +import codingstandards.cpp.Exclusions + +abstract class FunctionErroneousReturnValueNotTestedSharedQuery extends Query { } + +Query getQuery() { result instanceof FunctionErroneousReturnValueNotTestedSharedQuery } + +query predicate problems(FunctionCall fc, string message) { + not isExcluded(fc, getQuery()) and + fc.getTarget() + .hasGlobalOrStdName([ + // fcntl.h + "open", "openat", "fcntl", "creat", + // locale.h + "setlocale", + // stdlib.h + "system", "getenv", "getenv_s", + // signal.h + "signal", "raise", + // setjmp.h + "setjmp", + // stdio.h + "fopen", "fopen_s", "freopen", "freopen_s", "fclose", "fcloseall", "fflush", "setvbuf", + "fgetc", "getc", "fgets", "fputc", "getchar", "gets", "gets_s", "putchar", "puts", + "ungetc", "scanf", "fscanf", "sscanf", "scanf_s", "fscanf_s", "sscanf_s", "vscanf", + "vfscanf", "vsscanf", "vscanf_s", "vfscanf_s", "vsscanf_s", "printf", "fprintf", + "sprintf", "snprintf", "printf_s", "fprintf_s", "sprintf_s", "snprintf_s", "vprintf", + "vfprintf", "vsprintf", "vsnprintf", "vprintf_s", "vfprintf_s", "vsprintf_s", + "vsnprintf_s", "ftell", "fgetpos", "fseek", "fsetpos", "remove", "rename", "tmpfile", + "tmpfile_s", "tmpnam", "tmpnam_s", + // string.h + "strcpy_s", "strncpy_s", "strcat_s", "strncat_s", "memset_s", "memcpy_s", "memmove_s", + "strerror_s", + // threads.h + "thrd_create", "thrd_sleep", "thrd_detach", "thrd_join", "mtx_init", "mtx_lock", + "mtx_timedlock", "mtx_trylock", "mtx_unlock", "cnd_init", "cnd_signal", "cnd_broadcast", + "cnd_wait", "cnd_timedwait", "tss_create", "tss_get", "tss_set", + // time.h + "time", "clock", "timespec_get", "asctime_s", "ctime_s", "gmtime", "gmtime_s", + "localtime", "localtime_s", + // unistd.h + "write", "read", "close", "unlink", + // wchar.h + "fgetwc", "getwc", "fgetws", "fputwc", "putwc", "fputws", "getwchar", "putwchar", + "ungetwc", "wscanf", "fwscanf", "swscanf", "wscanf_s", "fwscanf_s", "swscanf_s", + "vwscanf", "vfwscanf", "vswscanf", "vwscanf_s", "vfwscanf_s", "vswscanf_s", "wprintf", + "fwprintf", "swprintf", "wprintf_s", "fwprintf_s", "swprintf_s", "snwprintf_s", + "vwprintf", "vfwprintf", "vswprintf", "vwprintf_s", "vfwprintf_s", "vswprintf_s", + "vsnwprintf_s" + ]) and + not exists(GuardCondition gc | + DataFlow::localFlow(DataFlow::exprNode(fc), DataFlow::exprNode(gc.getAChild*())) + ) and + message = "Return value from " + fc.getTarget().getName() + " is not tested for errors." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/functionlikemacrosdefined/FunctionLikeMacrosDefined.qll b/cpp/common/src/codingstandards/cpp/rules/functionlikemacrosdefined/FunctionLikeMacrosDefined.qll new file mode 100644 index 0000000000..73e4181640 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/functionlikemacrosdefined/FunctionLikeMacrosDefined.qll @@ -0,0 +1,31 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Function-like macros shall not be defined. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.IrreplaceableFunctionLikeMacro + +abstract class FunctionLikeMacrosDefinedSharedQuery extends Query { } + +Query getQuery() { result instanceof FunctionLikeMacrosDefinedSharedQuery } + +predicate partOfConstantExpr(MacroInvocation i) { + exists(Expr e | + e.isConstant() and + not i.getExpr() = e and + i.getExpr().getParent+() = e + ) +} + +query predicate problems(FunctionLikeMacro m, string message) { + not isExcluded(m, getQuery()) and + not m instanceof IrreplaceableFunctionLikeMacro and + //macros can have empty body + not m.getBody().length() = 0 and + //function call not allowed in a constant expression (where constant expr is parent) + forall(MacroInvocation i | i = m.getAnInvocation() | not partOfConstantExpr(i)) and + message = "Macro used instead of a function." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.qll b/cpp/common/src/codingstandards/cpp/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.qll index 2b910612cb..bb54a31df6 100644 --- a/cpp/common/src/codingstandards/cpp/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.qll +++ b/cpp/common/src/codingstandards/cpp/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.qll @@ -5,20 +5,30 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions +import codingstandards.cpp.Noreturn abstract class FunctionNoReturnAttributeConditionSharedQuery extends Query { } Query getQuery() { result instanceof FunctionNoReturnAttributeConditionSharedQuery } +/** + * `noreturn` functions are declared differently in c/c++. Attempt to match + * the description to the file; low risk if it chooses incorrectly. + */ +string describeNoreturn(Function f) { + if f.getFile().getExtension() = ["c", "C", "h", "H"] + then result = "_Noreturn" + else result = "[[noreturn]]" +} + /** * This checks that the return statement is reachable from the function entry point */ -query predicate problems(Function f, string message) { +query predicate problems(NoreturnFunction f, string message) { not isExcluded(f, getQuery()) and - f.getAnAttribute().getName() = "noreturn" and - exists(ReturnStmt s | - f = s.getEnclosingFunction() and - s.getBasicBlock().isReachable() - ) and - message = "The function " + f.getName() + " declared with attribute [[noreturn]] returns a value." + mayReturn(f) and + not f.isCompilerGenerated() and + message = + "The function " + f.getName() + " declared with attribute " + describeNoreturn(f) + + " returns a value." } diff --git a/cpp/common/src/codingstandards/cpp/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.qll b/cpp/common/src/codingstandards/cpp/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.qll new file mode 100644 index 0000000000..e54e4378e9 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.qll @@ -0,0 +1,35 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Using recursive functions can lead to stack overflows and limit scalability and + * portability of the program. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class FunctionsCallThemselvesEitherDirectlyOrIndirectlySharedQuery extends Query { } + +Query getQuery() { result instanceof FunctionsCallThemselvesEitherDirectlyOrIndirectlySharedQuery } + +class RecursiveCall extends FunctionCall { + RecursiveCall() { + this.getTarget().calls*(this.getEnclosingFunction()) and + not this.getTarget().hasSpecifier("is_constexpr") + } +} + +class RecursiveFunction extends Function { + RecursiveFunction() { exists(RecursiveCall fc | fc.getEnclosingFunction() = this) } +} + +query predicate problems(FunctionCall fc, string message, RecursiveFunction f, string functionName) { + not isExcluded(fc, getQuery()) and + f = fc.getTarget() and + functionName = f.getName() and + if f = fc.getEnclosingFunction() + then message = "This call directly invokes its containing function $@." + else + message = + "The function " + fc.getEnclosingFunction() + " is indirectly recursive via this call to $@." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/functiontemplatesexplicitlyspecialized/FunctionTemplatesExplicitlySpecialized.qll b/cpp/common/src/codingstandards/cpp/rules/functiontemplatesexplicitlyspecialized/FunctionTemplatesExplicitlySpecialized.qll new file mode 100644 index 0000000000..d0f98d233e --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/functiontemplatesexplicitlyspecialized/FunctionTemplatesExplicitlySpecialized.qll @@ -0,0 +1,21 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Function templates shall not be explicitly specialized. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class FunctionTemplatesExplicitlySpecializedSharedQuery extends Query { } + +Query getQuery() { result instanceof FunctionTemplatesExplicitlySpecializedSharedQuery } + +query predicate problems( + FunctionTemplateSpecialization f, string message, TemplateFunction tf, string tf_string +) { + not isExcluded(f, getQuery()) and + tf = f.getPrimaryTemplate() and + tf_string = f.getPrimaryTemplate().getFile().getBaseName() and + message = "Specialization of function template from primary template located in $@." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.qll b/cpp/common/src/codingstandards/cpp/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.qll new file mode 100644 index 0000000000..3f6ce2786a --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.qll @@ -0,0 +1,53 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The use of non-prototype format parameter type declarators is an obsolescent + * language feature. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Identifiers + +abstract class FunctionTypesNotInPrototypeFormSharedSharedQuery extends Query { } + +/** + * `Parameter`s without names + */ +class UnnamedParameter extends Parameter { + UnnamedParameter() { not this.isNamed() } +} + +/* + * This is a copy of the private `hasZeroParamDecl` predicate from the standard set of + * queries as of the `codeql-cli/2.11.2` tag in `github/codeql`. + */ + +predicate hasZeroParamDecl(Function f) { + exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + not fde.isImplicit() and + not fde.hasVoidParamList() and + fde.getNumberOfParameters() = 0 and + not fde.isDefinition() + ) +} + +Query getQuery() { result instanceof FunctionTypesNotInPrototypeFormSharedSharedQuery } + +query predicate problems(Function f, string msg) { + not isExcluded(f, getQuery()) and + f instanceof InterestingIdentifiers and + ( + f.getAParameter() instanceof UnnamedParameter and + msg = "Function " + f + " declares parameter that is unnamed." + or + hasZeroParamDecl(f) and + msg = "Function " + f + " does not specify void for no parameters present." + or + //parameters declared in declaration list (not in function signature) + //have no prototype + not f.isPrototyped() and + not hasZeroParamDecl(f) and + msg = "Function " + f + " declares parameter in unsupported declaration list." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/globalnamespacedeclarations/GlobalNamespaceDeclarations.qll b/cpp/common/src/codingstandards/cpp/rules/globalnamespacedeclarations/GlobalNamespaceDeclarations.qll new file mode 100644 index 0000000000..285ccd909a --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/globalnamespacedeclarations/GlobalNamespaceDeclarations.qll @@ -0,0 +1,23 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The only declarations in the global namespace should be main, namespace declarations + * and extern "C" declarations. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class GlobalNamespaceDeclarationsSharedQuery extends Query { } + +Query getQuery() { result instanceof GlobalNamespaceDeclarationsSharedQuery } + +query predicate problems(DeclarationEntry e, string message) { + not isExcluded(e, getQuery()) and + e.getDeclaration().getNamespace() instanceof GlobalNamespace and + e.getDeclaration().isTopLevel() and + not exists(Function f | f = e.getDeclaration() | f.hasGlobalName("main") or f.hasCLinkage()) and + message = + "Declaration " + e.getName() + + " is in the global namespace and is not a main, a namespace, or an extern \"C\" declaration." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/globalsizedoperatordeletenotdefined/GlobalSizedOperatorDeleteNotDefined.qll b/cpp/common/src/codingstandards/cpp/rules/globalsizedoperatordeletenotdefined/GlobalSizedOperatorDeleteNotDefined.qll new file mode 100644 index 0000000000..c445c06253 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/globalsizedoperatordeletenotdefined/GlobalSizedOperatorDeleteNotDefined.qll @@ -0,0 +1,24 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * If a project has the unsized version of operator 'delete' globally defined, then the + * sized version shall be defined. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.OperatorDelete + +abstract class GlobalSizedOperatorDeleteNotDefinedSharedQuery extends Query { } + +Query getQuery() { result instanceof GlobalSizedOperatorDeleteNotDefinedSharedQuery } + +query predicate problems(OperatorDelete unsized_delete, string message) { + not isExcluded(unsized_delete, getQuery()) and + not unsized_delete.isSizeDelete() and + not exists(OperatorDelete od | unsized_delete.isNoThrowDelete() = od.isNoThrowDelete() | + od.isSizeDelete() + ) and + message = + "Unsized function '" + unsized_delete.getName() + "' defined globally without sized version." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/globalunsizedoperatordeletenotdefined/GlobalUnsizedOperatorDeleteNotDefined.qll b/cpp/common/src/codingstandards/cpp/rules/globalunsizedoperatordeletenotdefined/GlobalUnsizedOperatorDeleteNotDefined.qll new file mode 100644 index 0000000000..b99887ee03 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/globalunsizedoperatordeletenotdefined/GlobalUnsizedOperatorDeleteNotDefined.qll @@ -0,0 +1,24 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * If a project has the sized version of operator 'delete' globally defined, then the + * unsized version shall be defined. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.OperatorDelete + +abstract class GlobalUnsizedOperatorDeleteNotDefinedSharedQuery extends Query { } + +Query getQuery() { result instanceof GlobalUnsizedOperatorDeleteNotDefinedSharedQuery } + +query predicate problems(OperatorDelete sized_delete, string message) { + not isExcluded(sized_delete, getQuery()) and + sized_delete.isSizeDelete() and + not exists(OperatorDelete od | sized_delete.isNoThrowDelete() = od.isNoThrowDelete() | + not od.isSizeDelete() + ) and + message = + "Sized function '" + sized_delete.getName() + "' defined globally without unsized version." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/gotoreferencealabelinsurroundingblock/GotoReferenceALabelInSurroundingBlock.qll b/cpp/common/src/codingstandards/cpp/rules/gotoreferencealabelinsurroundingblock/GotoReferenceALabelInSurroundingBlock.qll new file mode 100644 index 0000000000..f329fff12d --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/gotoreferencealabelinsurroundingblock/GotoReferenceALabelInSurroundingBlock.qll @@ -0,0 +1,60 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * A goto statement shall reference a label in a surrounding block. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class GotoReferenceALabelInSurroundingBlockSharedQuery extends Query { } + +Query getQuery() { result instanceof GotoReferenceALabelInSurroundingBlockSharedQuery } + +predicate isPartOfSwitch(Stmt goto) { + exists(SwitchStmt switch | switch.getStmt() = goto.getParent()) +} + +SwitchCase getSwitchCase(Stmt stmt) { + exists(int index, SwitchStmt switch | + getStmtInSwitch(switch, stmt, index) and getStmtInSwitch(switch, result, index - 1) + ) + or + exists(int index, SwitchStmt switch, Stmt other | + getStmtInSwitch(switch, stmt, index) and + getStmtInSwitch(switch, other, index - 1) and + not other instanceof SwitchCase and + result = getSwitchCase(other) + ) +} + +predicate getStmtInSwitch(SwitchStmt switch, Stmt s, int index) { + switch.getStmt().(BlockStmt).getStmt(index) = s +} + +int statementDepth(Stmt statement) { + statement.getParent() = statement.getEnclosingFunction().getBlock() and result = 1 + or + statementDepth(statement.getParent()) + 1 = result +} + +query predicate problems(GotoStmt goto, string message, Stmt target, string target_string) { + not isExcluded(goto, getQuery()) and + exists(int gotoDepth, int targetDepth | + goto.getTarget() = target and + gotoDepth = statementDepth(goto) and + targetDepth = statementDepth(target) and + targetDepth >= gotoDepth and + ( + targetDepth = gotoDepth + implies + ( + not isPartOfSwitch(goto) and not goto.getParent() = target.getParent() + or + isPartOfSwitch(goto) and not getSwitchCase(goto) = getSwitchCase(target) + ) + ) and + target_string = "label" and + message = "The goto statement and its $@ are not declared or enclosed in the same block." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/gotostatementshouldnotbeused/GotoStatementShouldNotBeUsed.qll b/cpp/common/src/codingstandards/cpp/rules/gotostatementshouldnotbeused/GotoStatementShouldNotBeUsed.qll new file mode 100644 index 0000000000..6a13ea083c --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/gotostatementshouldnotbeused/GotoStatementShouldNotBeUsed.qll @@ -0,0 +1,18 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The goto statement shall not be used. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class GotoStatementShouldNotBeUsedSharedQuery extends Query { } + +Query getQuery() { result instanceof GotoStatementShouldNotBeUsedSharedQuery } + +query predicate problems(Stmt s, string message) { + not isExcluded(s, getQuery()) and + (s instanceof GotoStmt or s instanceof ComputedGotoStmt) and + message = "Use of goto." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/handleallexceptionsduringstartup/HandleAllExceptionsDuringStartup.qll b/cpp/common/src/codingstandards/cpp/rules/handleallexceptionsduringstartup/HandleAllExceptionsDuringStartup.qll index ccc0a23460..8d859f726d 100644 --- a/cpp/common/src/codingstandards/cpp/rules/handleallexceptionsduringstartup/HandleAllExceptionsDuringStartup.qll +++ b/cpp/common/src/codingstandards/cpp/rules/handleallexceptionsduringstartup/HandleAllExceptionsDuringStartup.qll @@ -1,5 +1,6 @@ /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library with a `problems` predicate for the following issue: + * Exceptions thrown before main begins executing cannot be caught. */ import cpp diff --git a/cpp/common/src/codingstandards/cpp/rules/hiddeninheritednonoverridablememberfunction/HiddenInheritedNonOverridableMemberFunction.qll b/cpp/common/src/codingstandards/cpp/rules/hiddeninheritednonoverridablememberfunction/HiddenInheritedNonOverridableMemberFunction.qll new file mode 100644 index 0000000000..1c371da20c --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/hiddeninheritednonoverridablememberfunction/HiddenInheritedNonOverridableMemberFunction.qll @@ -0,0 +1,58 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * A non-overriding member function definition that hides an inherited member function + * can result in unexpected behavior. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Class + +abstract class HiddenInheritedNonOverridableMemberFunctionSharedQuery extends Query { } + +Query getQuery() { result instanceof HiddenInheritedNonOverridableMemberFunctionSharedQuery } + +/** + * Holds if the class has a non-virtual member function with the given name. + */ +pragma[noinline, nomagic] +predicate hasNonVirtualMemberFunction(Class clazz, MemberFunction mf, string name) { + mf.getDeclaringType() = clazz and + mf.getName() = name and + not mf.isVirtual() and + // Exclude private member functions, which cannot be inherited. + not mf.isPrivate() +} + +/** + * Holds if the member function is in a class with the given base class, and has the given name. + */ +pragma[noinline, nomagic] +predicate hasDeclarationBaseClass(MemberFunction mf, Class baseClass, string functionName) { + baseClass = mf.getDeclaringType().getABaseClass() and + functionName = mf.getName() +} + +query predicate problems( + MemberFunction overridingDecl, string message, MemberFunction hiddenDecl, string hiddenDecl_string +) { + exists(Class baseClass, string name | + not isExcluded(overridingDecl, getQuery()) and // Check if we are overriding a non-virtual inherited member function + hasNonVirtualMemberFunction(baseClass, hiddenDecl, name) and + hasDeclarationBaseClass(overridingDecl, baseClass, name) and + // Where the hidden member function isn't explicitly brought in scope through a using declaration. + not exists(UsingDeclarationEntry ude | + ude.getDeclaration() = hiddenDecl and + ude.getEnclosingElement() = overridingDecl.getDeclaringType() + ) and + // Exclude compiler generated member functions which include things like copy constructor that hide base class + // copy constructors. + not overridingDecl.isCompilerGenerated() and + // Exclude special member functions, which cannot be inherited. + not overridingDecl instanceof SpecialMemberFunction and + message = + "Declaration for member '" + name + "' hides non-overridable inherited member function $@" and + hiddenDecl_string = hiddenDecl.getName() + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/hiddeninheritedoverridablememberfunction/HiddenInheritedOverridableMemberFunction.qll b/cpp/common/src/codingstandards/cpp/rules/hiddeninheritedoverridablememberfunction/HiddenInheritedOverridableMemberFunction.qll new file mode 100644 index 0000000000..ef99e01973 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/hiddeninheritedoverridablememberfunction/HiddenInheritedOverridableMemberFunction.qll @@ -0,0 +1,56 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * An overriding member function definition thats hides an overload of the overridden + * inherited member function can result in unexpected behavior. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class HiddenInheritedOverridableMemberFunctionSharedQuery extends Query { } + +Query getQuery() { result instanceof HiddenInheritedOverridableMemberFunctionSharedQuery } + +query predicate problems( + FunctionDeclarationEntry overridingDecl, string message, FunctionDeclarationEntry hiddenDecl, + string hiddenDecl_string +) { + not isExcluded(overridingDecl, getQuery()) and + // Check if we are overriding a virtual inherited member function + hiddenDecl.getDeclaration().isVirtual() and + // Exclude private member functions, which cannot be inherited. + not hiddenDecl.getDeclaration().(MemberFunction).isPrivate() and + // The overriding declaration hides the hidden declaration if: + ( + // 1. the overriding declaration overrides a function in a base class that is an overload of the hidden declaration + // and the hidden declaration isn't overriden in the same class. + exists(FunctionDeclarationEntry overridenDecl | + overridingDecl.getDeclaration().(MemberFunction).overrides(overridenDecl.getDeclaration()) and + overridenDecl.getDeclaration().getAnOverload() = hiddenDecl.getDeclaration() and + not exists(MemberFunction overridingFunc | + hiddenDecl.getDeclaration().(MemberFunction).getAnOverridingFunction() = overridingFunc and + overridingFunc.getDeclaringType() = overridingDecl.getDeclaration().getDeclaringType() + ) + ) and + // and the hidden declaration isn't explicitly brought in scope through a using declaration. + not exists(UsingDeclarationEntry ude | + ude.getDeclaration() = hiddenDecl.getDeclaration() and + ude.getEnclosingElement() = overridingDecl.getDeclaration().getDeclaringType() + ) + or + // 2. if the overriding declaration doesn't override a base member function but has the same name + // as the hidden declaration + not overridingDecl.getDeclaration().(MemberFunction).overrides(_) and + overridingDecl.getName() = hiddenDecl.getName() and + overridingDecl.getDeclaration().getDeclaringType().getABaseClass() = + hiddenDecl.getDeclaration().getDeclaringType() + ) and + // Limit the results to the declarations and not the definitions, if any. + (overridingDecl.getDeclaration().hasDefinition() implies not overridingDecl.isDefinition()) and + (hiddenDecl.getDeclaration().hasDefinition() implies not hiddenDecl.isDefinition()) and + message = + "Declaration for member '" + overridingDecl.getName() + + "' hides overridable inherited member function $@" and + hiddenDecl_string = hiddenDecl.getName() +} diff --git a/cpp/common/src/codingstandards/cpp/rules/identifierhidden/IdentifierHidden.qll b/cpp/common/src/codingstandards/cpp/rules/identifierhidden/IdentifierHidden.qll index dc71ba843e..39d24299b8 100644 --- a/cpp/common/src/codingstandards/cpp/rules/identifierhidden/IdentifierHidden.qll +++ b/cpp/common/src/codingstandards/cpp/rules/identifierhidden/IdentifierHidden.qll @@ -1,80 +1,19 @@ /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library with a `problems` predicate for the following issue: + * Use of an identifier declared in an inner scope with an identical name to an + * identifier in an outer scope can lead to inadvertent errors if the incorrect + * identifier is modified. */ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.Scope -import codingstandards.cpp.ConstHelpers abstract class IdentifierHiddenSharedQuery extends Query { } Query getQuery() { result instanceof IdentifierHiddenSharedQuery } -/** - * a `Variable` that is nonvolatile and const - * and of type `IntegralOrEnumType` - */ -class NonVolatileConstIntegralOrEnumVariable extends Variable { - NonVolatileConstIntegralOrEnumVariable() { - not this.isVolatile() and - this.isConst() and - this.getUnspecifiedType() instanceof IntegralOrEnumType - } -} - -/** - * Holds if declaration `innerDecl`, declared in a lambda, hides a declaration `outerDecl` by the lambda. - */ -predicate hiddenInLambda(UserVariable outerDecl, UserVariable innerDecl) { - exists( - Scope innerScope, LambdaExpression lambdaExpr, Scope lambdaExprScope, Scope outerScope, - Closure lambdaClosure - | - // The variable `innerDecl` is declared inside of the lambda. - innerScope.getADeclaration() = innerDecl and - // Because a lambda is compiled down to a closure, we need to use the closure to determine if the declaration - // is part of the lambda. - innerScope.getAnAncestor() = lambdaClosure and - // Next we determine the scope of the lambda expression to determine if `outerDecl` is visible in the scope of the lambda. - lambdaClosure.getLambdaExpression() = lambdaExpr and - lambdaExprScope.getAnExpr() = lambdaExpr and - outerScope.getADeclaration() = outerDecl and - lambdaExprScope.getStrictParent*() = outerScope and - ( - // A definition can be hidden if it is in scope and it is captured by the lambda, - exists(LambdaCapture cap | - lambdaExpr.getACapture() = cap and - // The outer declaration is captured by the lambda - outerDecl.getAnAccess() = cap.getInitializer() - ) - or - // it is is non-local, - outerDecl instanceof GlobalVariable - or - // it has static or thread local storage duration, - (outerDecl.isThreadLocal() or outerDecl.isStatic()) - or - //it is a reference that has been initialized with a constant expression. - outerDecl.getType().stripTopLevelSpecifiers() instanceof ReferenceType and - outerDecl.getInitializer().getExpr() instanceof Literal - or - // //it const non-volatile integral or enumeration type and has been initialized with a constant expression - outerDecl instanceof NonVolatileConstIntegralOrEnumVariable and - outerDecl.getInitializer().getExpr() instanceof Literal - or - //it is constexpr and has no mutable members - outerDecl.isConstexpr() and - not exists(Class c | - c = outerDecl.getType() and not c.getAMember() instanceof MutableVariable - ) - ) and - // Finally, the variables must have the same names. - innerDecl.getName() = outerDecl.getName() - ) -} - query predicate problems( UserVariable innerDecl, string message, UserVariable outerDecl, string varName ) { @@ -83,7 +22,7 @@ query predicate problems( //ignore template variables for this rule not outerDecl instanceof TemplateVariable and not innerDecl instanceof TemplateVariable and - (hidesStrict(outerDecl, innerDecl) or hiddenInLambda(outerDecl, innerDecl)) and + hidesStrict(outerDecl, innerDecl) and not excludedViaNestedNamespaces(outerDecl, innerDecl) and varName = outerDecl.getName() and message = "Variable is hiding variable $@." diff --git a/cpp/common/src/codingstandards/cpp/rules/identifierwithexternallinkageonedefinitionshared/IdentifierWithExternalLinkageOneDefinitionShared.qll b/cpp/common/src/codingstandards/cpp/rules/identifierwithexternallinkageonedefinitionshared/IdentifierWithExternalLinkageOneDefinitionShared.qll index 17808841eb..806315b43c 100644 --- a/cpp/common/src/codingstandards/cpp/rules/identifierwithexternallinkageonedefinitionshared/IdentifierWithExternalLinkageOneDefinitionShared.qll +++ b/cpp/common/src/codingstandards/cpp/rules/identifierwithexternallinkageonedefinitionshared/IdentifierWithExternalLinkageOneDefinitionShared.qll @@ -1,5 +1,7 @@ /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library with a `problems` predicate for the following issue: + * An identifier with multiple definitions in different translation units + * leads to undefined behavior. */ import cpp diff --git a/cpp/common/src/codingstandards/cpp/rules/ifelseterminationconstruct/IfElseTerminationConstruct.qll b/cpp/common/src/codingstandards/cpp/rules/ifelseterminationconstruct/IfElseTerminationConstruct.qll index 5755ed8f38..3c6f25e151 100644 --- a/cpp/common/src/codingstandards/cpp/rules/ifelseterminationconstruct/IfElseTerminationConstruct.qll +++ b/cpp/common/src/codingstandards/cpp/rules/ifelseterminationconstruct/IfElseTerminationConstruct.qll @@ -1,5 +1,6 @@ /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library with a `problems` predicate for the following issue: + * The final else statement is a defensive programming technique. */ import cpp diff --git a/cpp/common/src/codingstandards/cpp/rules/initializeallvirtualbaseclasses/InitializeAllVirtualBaseClasses.qll b/cpp/common/src/codingstandards/cpp/rules/initializeallvirtualbaseclasses/InitializeAllVirtualBaseClasses.qll new file mode 100644 index 0000000000..ffb08283cd --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/initializeallvirtualbaseclasses/InitializeAllVirtualBaseClasses.qll @@ -0,0 +1,48 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * All constructors of a class should explicitly initialize all of its virtual base + * classes and immediate base classes. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Constructor + +abstract class InitializeAllVirtualBaseClassesSharedQuery extends Query { } + +Query getQuery() { result instanceof InitializeAllVirtualBaseClassesSharedQuery } + +query predicate problems( + Constructor c, string message, Class declaringType, string declaringType_string, Class baseClass, + string baseClass_string +) { + exists(string type | + not isExcluded(c, getQuery()) and + declaringType = c.getDeclaringType() and + ( + declaringType.getABaseClass() = baseClass and type = "" + or + baseClass.(VirtualBaseClass).getAVirtuallyDerivedClass().getADerivedClass+() = declaringType and + type = " virtual" + ) and + // There is not an initializer on the constructor for this particular base class + not exists(ConstructorBaseClassInit init | + c.getAnInitializer() = init and + init.getInitializedClass() = baseClass and + not init.isCompilerGenerated() + ) and + // Must be a defined constructor + c.hasDefinition() and + // Not a compiler-generated constructor + not c.isCompilerGenerated() and + // Not a defaulted constructor + not c.isDefaulted() and + // Not a deleted constructor + not c.isDeleted() and + declaringType_string = declaringType.getSimpleName() and + baseClass_string = baseClass.getSimpleName() and + message = + "Constructor for $@ does not explicitly call constructor for" + type + " base class $@." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/initializerlistconstructoristheonlyconstructor/InitializerListConstructorIsTheOnlyConstructor.qll b/cpp/common/src/codingstandards/cpp/rules/initializerlistconstructoristheonlyconstructor/InitializerListConstructorIsTheOnlyConstructor.qll new file mode 100644 index 0000000000..e9579fcfba --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/initializerlistconstructoristheonlyconstructor/InitializerListConstructorIsTheOnlyConstructor.qll @@ -0,0 +1,65 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * A class shall only define an initializer-list constructor when it is the only + * constructor. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class InitializerListConstructorIsTheOnlyConstructorSharedQuery extends Query { } + +Query getQuery() { result instanceof InitializerListConstructorIsTheOnlyConstructorSharedQuery } + +class StdInitializerList extends Class { + StdInitializerList() { hasQualifiedName("std", "initializer_list") } +} + +/** + * An _initializer-list constructor_ according to `[dcl.init.list]`. + * + * A `Constructor` where the first parameter refers to `std::initializer_list`, and any remaining + * parameters have default arguments. + */ +class InitializerListConstructor extends Constructor { + InitializerListConstructor() { + // The first parameter is a `std::intializer_list` parameter + exists(Type firstParamType | firstParamType = getParameter(0).getType() | + // Either directly `std::initializer_list` + firstParamType instanceof StdInitializerList + or + //A reference to `std::initializer_list` + firstParamType.(ReferenceType).getBaseType().getUnspecifiedType() instanceof + StdInitializerList + ) and + // All parameters other than the fi + forall(Parameter other | other = getParameter([1 .. (getNumberOfParameters() - 1)]) | + exists(other.getInitializer()) + ) + } +} + +query predicate problems( + Constructor c, string message, InitializerListConstructor stdInitializerConstructor, + string stdInitializerConstructor_string +) { + exists(string paramList | + not isExcluded(c, getQuery()) and + // Not an initializer-list constructor + not c instanceof InitializerListConstructor and + // Constructor is not a special member function constructor + not c instanceof CopyConstructor and + not c instanceof MoveConstructor and + not c.getNumberOfParameters() = 0 and // default constructor + // And there is an initalizer-list constructor + stdInitializerConstructor = c.getDeclaringType().getAConstructor() and + // Determine the parameter type list of the constructor + paramList = + concat(string parameter | parameter = c.getAParameter().getType().getName() | parameter, ",") and + message = + "The constructor " + c.getQualifiedName() + "(" + paramList + + ") may be ignored in favour of $@ when using braced initialization." and + stdInitializerConstructor_string = "the constructor accepting std::initializer_list" + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.qll b/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.qll index 81a3251355..50b27d819d 100644 --- a/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.qll +++ b/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.qll @@ -6,7 +6,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow abstract class InvalidatedEnvStringPointersSharedQuery extends Query { } @@ -45,6 +45,12 @@ predicate incompatibleFunctions(GetenvFunction f1, GetenvFunction f2) { or f1.getName() = ["setlocale", "localeconv"] and f2.getName() = ["setlocale", "localeconv"] + or + f1.getName() = ["asctime", "ctime"] and + f2.getName() = ["asctime", "ctime"] + or + f1.getName() = ["gmtime", "localtime"] and + f2.getName() = ["gmtime", "localtime"] } query predicate problems( @@ -63,10 +69,10 @@ query predicate problems( // The two calls are incompatible fc1 != fc2 and incompatibleFunctions(fc1.getTarget(), fc2.getFunction()) and - // The pointer returned by fc1 accessed in `e` afer the second `GetenvFunctionCall` + // The pointer returned by fc1 accessed in `e` after the second `GetenvFunctionCall` DataFlow::localExprFlow(fc1, e) and e = fc2.getASuccessor+() and - message = "This pointer was returned by a $@ and may have been overwritten by the susequent $@." and + message = "This pointer was returned by a $@ and may have been overwritten by the subsequent $@." and fc1text = fc1.toString() and fc2text = fc2.toString() } diff --git a/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.qll b/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.qll index fd8a969d00..759bc08deb 100644 --- a/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.qll +++ b/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.qll @@ -6,7 +6,6 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.dataflow.DataFlow import codingstandards.cpp.rules.invalidatedenvstringpointers.InvalidatedEnvStringPointers as EnvString abstract class InvalidatedEnvStringPointersWarnSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/iofstreammissingpositioning/IOFstreamMissingPositioning.qll b/cpp/common/src/codingstandards/cpp/rules/iofstreammissingpositioning/IOFstreamMissingPositioning.qll index 3a7e225369..b26421c72c 100644 --- a/cpp/common/src/codingstandards/cpp/rules/iofstreammissingpositioning/IOFstreamMissingPositioning.qll +++ b/cpp/common/src/codingstandards/cpp/rules/iofstreammissingpositioning/IOFstreamMissingPositioning.qll @@ -5,7 +5,7 @@ */ import cpp -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import codingstandards.cpp.Exclusions import codingstandards.cpp.standardlibrary.FileStreams import codingstandards.cpp.standardlibrary.FileAccess @@ -51,23 +51,26 @@ class WriteFunctionCall extends ReadWriteCall { } } -pragma[inline] +bindingset[a, b] +pragma[inline_late] predicate sameSource(FunctionCall a, FunctionCall b) { sameStreamSource(a, b) or sameFileSource(a, b) } +bindingset[a, b] predicate sameAccessDirection(ReadWriteCall a, ReadWriteCall b) { a.getAccessDirection() = b.getAccessDirection() } +bindingset[a, b] predicate oppositeAccessDirection(ReadWriteCall a, ReadWriteCall b) { not sameAccessDirection(a, b) } /** * A write operation reaching a read and vice versa - * without intervening filepositioning + * without intervening file positioning calls. */ ControlFlowNode reachesInExOperator(ReadWriteCall op) { result = op diff --git a/cpp/common/src/codingstandards/cpp/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.qll b/cpp/common/src/codingstandards/cpp/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.qll new file mode 100644 index 0000000000..5ccbe83c72 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.qll @@ -0,0 +1,49 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Joining or detaching a previously joined or detached thread can lead to undefined + * program behavior. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Concurrency + +abstract class JoinOrDetachThreadOnlyOnceSharedQuery extends Query { } + +Query getQuery() { result instanceof JoinOrDetachThreadOnlyOnceSharedQuery } + +// OK +// 1) Thread calls detach parent DOES NOT call join +// 2) Parent calls join, thread does NOT call detach() +// NOT OK +// 1) Thread calls detach, parent calls join +// 2) Thread calls detach twice, parent does not call join +// 3) Parent calls join twice, thread does not call detach +query predicate problems(C11ThreadCreateCall tcc, string message) { + not isExcluded(tcc, getQuery()) and + message = "Thread may call join or detach after the thread is joined or detached." and + ( + // Note: These cases can be simplified but they are presented like this for clarity + // case 1 - calls to `thrd_join` and `thrd_detach` within the parent or + // within the parent / child CFG. + exists(C11ThreadWait tw, C11ThreadDetach dt | + tw = getAThreadContextAwareSuccessor(tcc) and + dt = getAThreadContextAwareSuccessor(tcc) + ) + or + // case 2 - multiple calls to `thrd_detach` within the threaded CFG. + exists(C11ThreadDetach dt1, C11ThreadDetach dt2 | + dt1 = getAThreadContextAwareSuccessor(tcc) and + dt2 = getAThreadContextAwareSuccessor(tcc) and + not dt1 = dt2 + ) + or + // case 3 - multiple calls to `thrd_join` within the threaded CFG. + exists(C11ThreadWait tw1, C11ThreadWait tw2 | + tw1 = getAThreadContextAwareSuccessor(tcc) and + tw2 = getAThreadContextAwareSuccessor(tcc) and + not tw1 = tw2 + ) + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/linesplicingusedincomments/LineSplicingUsedInComments.qll b/cpp/common/src/codingstandards/cpp/rules/linesplicingusedincomments/LineSplicingUsedInComments.qll new file mode 100644 index 0000000000..52dcf9a3f1 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/linesplicingusedincomments/LineSplicingUsedInComments.qll @@ -0,0 +1,19 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Entering a newline following a '\\' character can erroneously commenting out + * regions of code. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class LineSplicingUsedInCommentsSharedQuery extends Query { } + +Query getQuery() { result instanceof LineSplicingUsedInCommentsSharedQuery } + +query predicate problems(CppStyleComment c, string message) { + not isExcluded(c, getQuery()) and + exists(c.getContents().regexpFind("\\\n", _, _)) and + message = "C++ comment includes \\ as the last character of a line" +} diff --git a/cpp/common/src/codingstandards/cpp/rules/loopcompoundcondition/LoopCompoundCondition.qll b/cpp/common/src/codingstandards/cpp/rules/loopcompoundcondition/LoopCompoundCondition.qll new file mode 100644 index 0000000000..b71c193c8e --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/loopcompoundcondition/LoopCompoundCondition.qll @@ -0,0 +1,19 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * If the body of a loop is not enclosed in braces, then this can lead to incorrect + * execution, and hard for developers to maintain. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class LoopCompoundConditionSharedQuery extends Query { } + +Query getQuery() { result instanceof LoopCompoundConditionSharedQuery } + +query predicate problems(Loop loop, string message) { + not isExcluded(loop, getQuery()) and + not loop.getStmt() instanceof BlockStmt and + message = "Loop body not enclosed within braces." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/lowercaselstartsinliteralsuffix/LowercaseLStartsInLiteralSuffix.qll b/cpp/common/src/codingstandards/cpp/rules/lowercaselstartsinliteralsuffix/LowercaseLStartsInLiteralSuffix.qll new file mode 100644 index 0000000000..b12cddba0b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/lowercaselstartsinliteralsuffix/LowercaseLStartsInLiteralSuffix.qll @@ -0,0 +1,20 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The lowercase form of L shall not be used as the first character in a literal + * suffix. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Literals + +abstract class LowercaseLStartsInLiteralSuffixSharedQuery extends Query { } + +Query getQuery() { result instanceof LowercaseLStartsInLiteralSuffixSharedQuery } + +query predicate problems(IntegerLiteral l, string message) { + not isExcluded(l, getQuery()) and + exists(l.getValueText().indexOf("l")) and + message = "Lowercase 'l' used as a literal suffix." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/macrooffsetofused/MacroOffsetofUsed.qll b/cpp/common/src/codingstandards/cpp/rules/macrooffsetofused/MacroOffsetofUsed.qll new file mode 100644 index 0000000000..b475dc655e --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/macrooffsetofused/MacroOffsetofUsed.qll @@ -0,0 +1,18 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The macro offsetof shall not be used. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class MacroOffsetofUsedSharedQuery extends Query { } + +Query getQuery() { result instanceof MacroOffsetofUsedSharedQuery } + +query predicate problems(MacroInvocation mi, string message) { + not isExcluded(mi, getQuery()) and + mi.getMacroName() = "offsetof" and + message = "Use of banned macro " + mi.getMacroName() + "." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/macroparameterfollowinghash/MacroParameterFollowingHash.qll b/cpp/common/src/codingstandards/cpp/rules/macroparameterfollowinghash/MacroParameterFollowingHash.qll new file mode 100644 index 0000000000..ae20368e67 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/macroparameterfollowinghash/MacroParameterFollowingHash.qll @@ -0,0 +1,24 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * A macro parameter immediately following a # operator shall not be immediately + * followed by a ## operator. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Macro + +abstract class MacroParameterFollowingHashSharedQuery extends Query { } + +Query getQuery() { result instanceof MacroParameterFollowingHashSharedQuery } + +query predicate problems(Macro m, string message) { + not isExcluded(m, getQuery()) and + exists(StringizingOperator one, TokenPastingOperator two | + one.getMacro() = m and + two.getMacro() = m and + one.getOffset() < two.getOffset() + ) and + message = "Macro definition uses an # operator followed by a ## operator." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/macroparameternotenclosedinparentheses/MacroParameterNotEnclosedInParentheses.qll b/cpp/common/src/codingstandards/cpp/rules/macroparameternotenclosedinparentheses/MacroParameterNotEnclosedInParentheses.qll index 693ae36906..314d1dbe4c 100644 --- a/cpp/common/src/codingstandards/cpp/rules/macroparameternotenclosedinparentheses/MacroParameterNotEnclosedInParentheses.qll +++ b/cpp/common/src/codingstandards/cpp/rules/macroparameternotenclosedinparentheses/MacroParameterNotEnclosedInParentheses.qll @@ -1,5 +1,8 @@ /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library with a `problems` predicate for the following issue: + * In the definition of a function-like macro, each instance of a parameter + * shall be enclosed in parentheses, otherwise the result of preprocessor macro + * substitition may not be as expected. */ import cpp diff --git a/cpp/common/src/codingstandards/cpp/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.qll b/cpp/common/src/codingstandards/cpp/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.qll new file mode 100644 index 0000000000..90f28e6cc8 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.qll @@ -0,0 +1,27 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Declaring an identifier with internal linkage without the static storage class + * specifier is an obselescent feature. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class MissingStaticSpecifierObjectRedeclarationSharedSharedQuery extends Query { } + +Query getQuery() { result instanceof MissingStaticSpecifierObjectRedeclarationSharedSharedQuery } + +query predicate problems( + VariableDeclarationEntry redeclaration, string message, VariableDeclarationEntry de, + string deString +) { + not isExcluded(redeclaration, getQuery()) and + //following implies de != redeclaration + de.hasSpecifier("static") and + not redeclaration.hasSpecifier("static") and + de.getDeclaration().isTopLevel() and + redeclaration.getDeclaration() = de.getDeclaration() and + message = "The redeclaration of $@ with internal linkage misses the static specifier." and + deString = de.getName() +} diff --git a/cpp/common/src/codingstandards/cpp/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.qll b/cpp/common/src/codingstandards/cpp/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.qll new file mode 100644 index 0000000000..eecd349ad7 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.qll @@ -0,0 +1,141 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Possible misuse of a generate infinite floating point value. + */ + +import cpp +import codeql.util.Boolean +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.RestrictedRangeAnalysis +import codingstandards.cpp.FloatingPoint +import codingstandards.cpp.AlertReporting +import semmle.code.cpp.controlflow.Guards +import semmle.code.cpp.dataflow.new.DataFlow +import semmle.code.cpp.dataflow.new.TaintTracking +import semmle.code.cpp.controlflow.Dominance + +module InvalidInfinityUsage implements DataFlow::ConfigSig { + /** + * An operation which does not have Infinity as an input, but may produce Infinity, according + * to the `RestrictedRangeAnalysis` module. + */ + predicate isSource(DataFlow::Node node) { + potentialSource(node) and + not exists(DataFlow::Node prior | + isAdditionalFlowStep(prior, node) and + potentialSource(prior) + ) + } + + /** + * An operation which may produce Infinity acconding to the `RestrictedRangeAnalysis` module. + */ + additional predicate potentialSource(DataFlow::Node node) { + node.asExpr() instanceof Operation and + exprMayEqualInfinity(node.asExpr(), _) + } + + predicate isBarrierOut(DataFlow::Node node) { + guardedNotFPClass(node.asExpr(), TInfinite()) + or + exists(Expr e | + e.getType() instanceof IntegralType and + e = node.asConvertedExpr() + ) + } + + /** + * An additional flow step to handle operations which propagate Infinity. + * + * This double checks that an Infinity may propagate by checking the `RestrictedRangeAnalysis` + * value estimate. This is conservative, since `RestrictedRangeAnalysis` is performed locally + * in scope with unanalyzable values in a finite range. However, this conservative approach + * leverages analysis of guards and other local conditions to avoid false positives. + */ + predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node sink) { + exists(Operation o | + o.getAnOperand() = source.asExpr() and + o = sink.asExpr() and + potentialSource(sink) + ) + } + + predicate isSink(DataFlow::Node node) { + node instanceof InvalidInfinityUsage and + ( + // Require that range analysis finds this value potentially infinite, to avoid false positives + // in the presence of guards. This may induce false negatives. + exprMayEqualInfinity(node.asExpr(), _) + or + // Unanalyzable expressions are not checked against range analysis, which assumes a finite + // range. + not RestrictedRangeAnalysis::canBoundExpr(node.asExpr()) + or + node.asExpr().(VariableAccess).getTarget() instanceof Parameter + ) + } +} + +class InvalidInfinityUsage extends DataFlow::Node { + string description; + + InvalidInfinityUsage() { + // Case 2: NaNs and infinities shall not be cast to integers + exists(Conversion c | + asExpr() = c.getUnconverted() and + c.getExpr().getType() instanceof FloatingPointType and + c.getType() instanceof IntegralType and + description = "cast to integer." + ) + or + // Case 3: Infinities shall not underflow or otherwise produce finite values + exists(BinaryOperation op | + asExpr() = op.getRightOperand() and + op.getOperator() = "/" and + description = "divisor, which would silently underflow and produce zero." + ) + } + + string getDescription() { result = description } +} + +module InvalidInfinityFlow = DataFlow::Global; + +import InvalidInfinityFlow::PathGraph + +abstract class MisuseOfInfiniteFloatingPointValueSharedQuery extends Query { } + +Query getQuery() { result instanceof MisuseOfInfiniteFloatingPointValueSharedQuery } + +query predicate problems( + Element elem, InvalidInfinityFlow::PathNode source, InvalidInfinityFlow::PathNode sink, + string message, Expr sourceExpr, string sourceString, Function function, string functionName +) { + not isExcluded(elem, getQuery()) and + exists(InvalidInfinityUsage usage, string computedInFunction | + elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and + not InvalidInfinityFlow::PathGraph::edges(_, source, _, _) and + not InvalidInfinityFlow::PathGraph::edges(sink, _, _, _) and + not sourceExpr.isFromTemplateInstantiation(_) and + not usage.asExpr().isFromTemplateInstantiation(_) and + usage = sink.getNode() and + sourceExpr = source.getNode().asExpr() and + function = sourceExpr.getEnclosingFunction() and + InvalidInfinityFlow::flow(source.getNode(), usage) and + ( + if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction() + then computedInFunction = "computed in function $@ " + else computedInFunction = "" + ) and + ( + if sourceExpr instanceof DivExpr + then sourceString = "from division by zero" + else sourceString = sourceExpr.toString() + ) and + message = + "Possibly infinite float value $@ " + computedInFunction + "flows to " + + usage.getDescription() and + functionName = function.getName() + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.qll b/cpp/common/src/codingstandards/cpp/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.qll new file mode 100644 index 0000000000..19ec4e1986 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.qll @@ -0,0 +1,201 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Possible mishandling of an undetected NaN value produced by a floating point + * operation. + */ + +import cpp +import codeql.util.Boolean +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.RestrictedRangeAnalysis +import codingstandards.cpp.FloatingPoint +import codingstandards.cpp.AlertReporting +import semmle.code.cpp.controlflow.Guards +import semmle.code.cpp.dataflow.new.DataFlow +import semmle.code.cpp.dataflow.new.TaintTracking +import semmle.code.cpp.controlflow.Dominance + +abstract class PotentiallyNaNExpr extends Expr { + abstract string getReason(); +} + +class DomainErrorFunctionCall extends FunctionCall, PotentiallyNaNExpr { + string reason; + + DomainErrorFunctionCall() { RestrictedDomainError::hasDomainError(this, reason) } + + override string getReason() { result = reason } +} + +// IEEE 754-1985 Section 7.1 invalid operations +class InvalidOperationExpr extends BinaryOperation, PotentiallyNaNExpr { + string reason; + + InvalidOperationExpr() { + // Usual arithmetic conversions in both languages mean that if either operand is a floating + // type, the other one is converted to a floating type as well. + getAnOperand().getFullyConverted().getType() instanceof FloatingPointType and + ( + // 7.1.1 propagates signaling NaNs, we rely on flow analysis and/or assume quiet NaNs, so we + // intentionally do not cover this case. + // 7.1.2: magnitude subtraction of infinities, such as +Inf + -Inf + getOperator() = "+" and + exists(Boolean sign | + exprMayEqualInfinity(getLeftOperand(), sign) and + exprMayEqualInfinity(getRightOperand(), sign.booleanNot()) + ) and + reason = "from addition of infinity and negative infinity" + or + // 7.1.2 continued + getOperator() = "-" and + exists(Boolean sign | + exprMayEqualInfinity(getLeftOperand(), sign) and + exprMayEqualInfinity(getRightOperand(), sign) + ) and + reason = "from subtraction of an infinity from itself" + or + // 7.1.3: multiplication of zero by infinity + getOperator() = "*" and + exists(Expr zeroOp, Expr infinityOp | + zeroOp = getAnOperand() and + infinityOp = getAnOperand() and + not zeroOp = infinityOp and + exprMayEqualZero(zeroOp) and + exprMayEqualInfinity(infinityOp, _) + ) and + reason = "from multiplication of zero by infinity" + or + // 7.1.4: Division of zero by zero, or infinity by infinity + getOperator() = "/" and + exprMayEqualZero(getLeftOperand()) and + exprMayEqualZero(getRightOperand()) and + reason = "from division of zero by zero" + or + // 7.1.4 continued + getOperator() = "/" and + exprMayEqualInfinity(getLeftOperand(), _) and + exprMayEqualInfinity(getRightOperand(), _) and + reason = "from division of infinity by infinity" + or + // 7.1.5: x % y where y is zero or x is infinite + getOperator() = "%" and + exprMayEqualInfinity(getLeftOperand(), _) and + reason = "from modulus of infinity" + or + // 7.1.5 continued + getOperator() = "%" and + exprMayEqualZero(getRightOperand()) and + reason = "from modulus by zero" + // 7.1.6 handles the sqrt function, not covered here. + // 7.1.7 declares exceptions during invalid conversions, which we catch as sinks in our flow + // analysis. + // 7.1.8 declares exceptions for unordered comparisons, which we catch as sinks in our flow + // analysis. + ) + } + + override string getReason() { result = reason } +} + +module InvalidNaNUsage implements DataFlow::ConfigSig { + /** + * An expression which has non-NaN inputs and may produce a NaN output. + */ + predicate isSource(DataFlow::Node node) { + potentialSource(node) and + not exists(DataFlow::Node prior | + isAdditionalFlowStep(prior, node) and + potentialSource(prior) + ) + } + + /** + * An expression which may produce a NaN output. + */ + additional predicate potentialSource(DataFlow::Node node) { + node.asExpr() instanceof PotentiallyNaNExpr + } + + predicate isBarrierOut(DataFlow::Node node) { + guardedNotFPClass(node.asExpr(), TNaN()) + or + exists(Expr e | + e.getType() instanceof IntegralType and + e = node.asConvertedExpr() + ) + } + + /** + * Add an additional flow step to handle NaN propagation through floating point operations. + */ + predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node sink) { + exists(Operation o | + o.getAnOperand() = source.asExpr() and + o = sink.asExpr() and + o.getType() instanceof FloatingPointType + ) + } + + predicate isSink(DataFlow::Node node) { + not guardedNotFPClass(node.asExpr(), TNaN()) and + node instanceof InvalidNaNUsage + } +} + +class InvalidNaNUsage extends DataFlow::Node { + string description; + + InvalidNaNUsage() { + // Case 1: NaNs shall not be compared, except to themselves + exists(ComparisonOperation cmp | + this.asExpr() = cmp.getAnOperand() and + not hashCons(cmp.getLeftOperand()) = hashCons(cmp.getRightOperand()) and + description = "comparison, which would always evaluate to false." + ) + or + // Case 2: NaNs and infinities shall not be cast to integers + exists(Conversion c | + this.asExpr() = c.getUnconverted() and + c.getExpr().getType() instanceof FloatingPointType and + c.getType() instanceof IntegralType and + description = "a cast to integer." + ) + } + + string getDescription() { result = description } +} + +module InvalidNaNFlow = DataFlow::Global; + +import InvalidNaNFlow::PathGraph + +abstract class MisuseOfNaNFloatingPointValueSharedQuery extends Query { } + +Query getQuery() { result instanceof MisuseOfNaNFloatingPointValueSharedQuery } + +query predicate problems( + Element elem, InvalidNaNFlow::PathNode source, InvalidNaNFlow::PathNode sink, string message, + Expr sourceExpr, string sourceString, Function function, string functionName +) { + not isExcluded(elem, getQuery()) and + exists(InvalidNaNUsage usage, string computedInFunction | + not InvalidNaNFlow::PathGraph::edges(_, source, _, _) and + not InvalidNaNFlow::PathGraph::edges(sink, _, _, _) and + not sourceExpr.isFromTemplateInstantiation(_) and + not usage.asExpr().isFromTemplateInstantiation(_) and + elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and + usage = sink.getNode() and + sourceExpr = source.getNode().asExpr() and + sourceString = source.getNode().asExpr().(PotentiallyNaNExpr).getReason() and + function = sourceExpr.getEnclosingFunction() and + InvalidNaNFlow::flow(source.getNode(), usage) and + ( + if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction() + then computedInFunction = "computed in function $@ " + else computedInFunction = "" + ) and + message = "Possible NaN value $@ " + computedInFunction + "flows to " + usage.getDescription() and + functionName = function.getName() + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/movedfromobjectsunspecifiedstate/MovedFromObjectsUnspecifiedState.qll b/cpp/common/src/codingstandards/cpp/rules/movedfromobjectsunspecifiedstate/MovedFromObjectsUnspecifiedState.qll index a0006eb643..f17da7e457 100644 --- a/cpp/common/src/codingstandards/cpp/rules/movedfromobjectsunspecifiedstate/MovedFromObjectsUnspecifiedState.qll +++ b/cpp/common/src/codingstandards/cpp/rules/movedfromobjectsunspecifiedstate/MovedFromObjectsUnspecifiedState.qll @@ -4,7 +4,7 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.Exclusions import codingstandards.cpp.standardlibrary.Utility diff --git a/cpp/common/src/codingstandards/cpp/rules/multipleglobalormemberdeclarators/MultipleGlobalOrMemberDeclarators.qll b/cpp/common/src/codingstandards/cpp/rules/multipleglobalormemberdeclarators/MultipleGlobalOrMemberDeclarators.qll new file mode 100644 index 0000000000..05821d7270 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/multipleglobalormemberdeclarators/MultipleGlobalOrMemberDeclarators.qll @@ -0,0 +1,66 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * A declaration should not declare more than one variable or member variable. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class MultipleGlobalOrMemberDeclaratorsSharedQuery extends Query { } + +Query getQuery() { result instanceof MultipleGlobalOrMemberDeclaratorsSharedQuery } + +/* + * Unfortunately, we do not have an equivalent of `DeclStmt` for non-local declarations, so we + * cannot determine whether a declaration was declared with another declaration. + * + * However, we can use location trickery to figure out if the declaration occurs close enough to + * another declaration that it _must_ have been declared within the same declaration sequence. + * + * We do this by requiring that the end location of a previous declaration is within a certain + * number of characters of the start location of the current declaration. + */ + +/** + * A `Declaration` which is not in a local scope, and is written directly by the user. + * + * These act as "candidates" for declarations that could plausibly occur in a declaration sequence + * with other candidates. + */ +class NonLocalUserDeclaration extends Declaration { + NonLocalUserDeclaration() { + not this instanceof StackVariable and + not this instanceof TemplateParameter and + not this instanceof EnumConstant and + not this instanceof TypedefType and + not any(LambdaCapture lc).getField() = this and + not this.(Function).isCompilerGenerated() and + not this.(Variable).isCompilerGenerated() and + not this.(Parameter).getFunction().isCompilerGenerated() and + not this.isInMacroExpansion() and + not exists(Struct s, TypedefType t | + s.isAnonymous() and + t.getBaseType() = s and + this = s.getAMemberVariable() + ) + } +} + +/** + * Holds if `d1` is followed directly by `d2`. + */ +predicate isFollowingDeclaration(NonLocalUserDeclaration d1, NonLocalUserDeclaration d2) { + exists(string filepath, int startline, int startcolumn, int endline, int endcolumn | + d1.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and + d2.getLocation().hasLocationInfo(filepath, startline, endcolumn + [2 .. 3], endline, _) + ) and + not d1.(UserType).stripType() = d2.(Variable).getType().stripType() +} + +query predicate problems(NonLocalUserDeclaration d1, string message) { + not isExcluded(d1, getQuery()) and + isFollowingDeclaration(d1, _) and + not isFollowingDeclaration(_, d1) and + message = "Multiple declarations after " + d1.getName() + " in this declaration sequence." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/multiplelocaldeclarators/MultipleLocalDeclarators.qll b/cpp/common/src/codingstandards/cpp/rules/multiplelocaldeclarators/MultipleLocalDeclarators.qll new file mode 100644 index 0000000000..2269f36d97 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/multiplelocaldeclarators/MultipleLocalDeclarators.qll @@ -0,0 +1,20 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * A declaration should not declare more than one variable or member variable. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class MultipleLocalDeclaratorsSharedQuery extends Query { } + +Query getQuery() { result instanceof MultipleLocalDeclaratorsSharedQuery } + +query predicate problems(DeclStmt ds, string message) { + not isExcluded(ds, getQuery()) and + count(Declaration d | d = ds.getADeclaration()) > 1 and + // Not a compiler generated `DeclStmt`, such as in the range-based for loop + not ds.isCompilerGenerated() and + message = "Declaration list contains more than one declaration." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/namedbitfieldswithsignedintegertype/NamedBitFieldsWithSignedIntegerType.qll b/cpp/common/src/codingstandards/cpp/rules/namedbitfieldswithsignedintegertype/NamedBitFieldsWithSignedIntegerType.qll new file mode 100644 index 0000000000..326886dda6 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/namedbitfieldswithsignedintegertype/NamedBitFieldsWithSignedIntegerType.qll @@ -0,0 +1,20 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * A named bit-field with signed integer type shall not have a length of one bit. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class NamedBitFieldsWithSignedIntegerTypeSharedQuery extends Query { } + +Query getQuery() { result instanceof NamedBitFieldsWithSignedIntegerTypeSharedQuery } + +query predicate problems(BitField bitField, string message) { + not isExcluded(bitField, getQuery()) and + bitField.getDeclaredNumBits() = 1 and // Single-bit, + not bitField.isAnonymous() and // named, + bitField.getType().(IntegralType).isSigned() and // but its type is signed. + message = "A named bit-field with signed integral type should have at least 2 bits of storage." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/namenotreferredusingaqualifiedidorthis/NameNotReferredUsingAQualifiedIdOrThis.qll b/cpp/common/src/codingstandards/cpp/rules/namenotreferredusingaqualifiedidorthis/NameNotReferredUsingAQualifiedIdOrThis.qll new file mode 100644 index 0000000000..a4c9255c89 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/namenotreferredusingaqualifiedidorthis/NameNotReferredUsingAQualifiedIdOrThis.qll @@ -0,0 +1,37 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Not using a qualified-id or `this->` syntax for identifiers used in a class template + * makes the code more difficult to understand. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.NameInDependentBase + +abstract class NameNotReferredUsingAQualifiedIdOrThisSharedQuery extends Query { } + +Query getQuery() { result instanceof NameNotReferredUsingAQualifiedIdOrThisSharedQuery } + +query predicate problems( + NameQualifiableElement fn, string message, Element actualTarget, string targetName, + Element dependentTypeMemberWithSameName, string dependentType_string +) { + not isExcluded(fn, getQuery()) and + missingNameQualifier(fn) and + exists(TemplateClass c | + fn = getConfusingFunctionAccess(c, targetName, actualTarget, dependentTypeMemberWithSameName) + or + fn = getConfusingFunctionCall(c, targetName, actualTarget, dependentTypeMemberWithSameName) and + not exists(Expr e | e = fn.(FunctionCall).getQualifier()) + or + fn = + getConfusingMemberVariableAccess(c, targetName, actualTarget, dependentTypeMemberWithSameName) and + not exists(Expr e | e = fn.(VariableAccess).getQualifier()) + ) and + not fn.isAffectedByMacro() and + message = + "Use of unqualified identifier " + targetName + + " targets $@ but a member with the name also exists $@." and + dependentType_string = "in the dependent base class" +} diff --git a/cpp/common/src/codingstandards/cpp/rules/namenotreferredusingaqualifiedidorthisaudit/NameNotReferredUsingAQualifiedIdOrThisAudit.qll b/cpp/common/src/codingstandards/cpp/rules/namenotreferredusingaqualifiedidorthisaudit/NameNotReferredUsingAQualifiedIdOrThisAudit.qll new file mode 100644 index 0000000000..d0a6251908 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/namenotreferredusingaqualifiedidorthisaudit/NameNotReferredUsingAQualifiedIdOrThisAudit.qll @@ -0,0 +1,38 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Not using a qualified-id or `this->` syntax for identifiers used in a class template + * makes the code more difficult to understand. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.NameInDependentBase + +abstract class NameNotReferredUsingAQualifiedIdOrThisAuditSharedQuery extends Query { } + +Query getQuery() { result instanceof NameNotReferredUsingAQualifiedIdOrThisAuditSharedQuery } + +query predicate problems( + NameQualifiableElement fn, string message, Element actualTarget, string targetName, + Element dependentTypeMemberWithSameName, string dependentType_string +) { + not isExcluded(fn, getQuery()) and + not isCustomExcluded(fn) and + missingNameQualifier(fn) and + exists(TemplateClass c | + fn = getConfusingFunctionAccess(c, targetName, actualTarget, dependentTypeMemberWithSameName) + or + fn = getConfusingFunctionCall(c, targetName, actualTarget, dependentTypeMemberWithSameName) and + not exists(Expr e | e = fn.(FunctionCall).getQualifier()) + or + not fn.(VariableAccess).getTarget() instanceof Parameter and + fn = + getConfusingMemberVariableAccess(c, targetName, actualTarget, dependentTypeMemberWithSameName) and + not exists(Expr e | e = fn.(VariableAccess).getQualifier()) + ) and + message = + "Use of unqualified identifier " + targetName + + " targets $@ but a member with the name also exists $@." and + dependentType_string = "in the dependent base class" +} diff --git a/cpp/common/src/codingstandards/cpp/rules/noexceptfunctionshouldnotpropagatetothecaller/NoexceptFunctionShouldNotPropagateToTheCaller.qll b/cpp/common/src/codingstandards/cpp/rules/noexceptfunctionshouldnotpropagatetothecaller/NoexceptFunctionShouldNotPropagateToTheCaller.qll new file mode 100644 index 0000000000..bc3b620718 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/noexceptfunctionshouldnotpropagatetothecaller/NoexceptFunctionShouldNotPropagateToTheCaller.qll @@ -0,0 +1,38 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * If a function is declared to be noexcept, noexcept(true) or noexcept(), then it shall not exit with an exception. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.exceptions.ExceptionFlow +import ExceptionPathGraph +import codingstandards.cpp.exceptions.ExceptionSpecifications + +abstract class NoexceptFunctionShouldNotPropagateToTheCallerSharedQuery extends Query { } + +Query getQuery() { result instanceof NoexceptFunctionShouldNotPropagateToTheCallerSharedQuery } + +class NoExceptThrowingFunction extends ExceptionThrowingFunction { + NoExceptThrowingFunction() { + // Can exit with an exception + exists(getAFunctionThrownType(_, _)) and + // But is marked noexcept(true) or equivalent + isNoExceptTrue(this) + } +} + +query predicate problems( + NoExceptThrowingFunction f, ExceptionFlowNode exceptionSource, ExceptionFlowNode functionNode, + string message +) { + exists(ExceptionType exceptionType | + not isExcluded(f, getQuery()) and + f.hasExceptionFlow(exceptionSource, functionNode, exceptionType) and + message = + "Function " + f.getName() + " is declared noexcept(true) but can throw exceptions of type " + + exceptionType.getExceptionName() + "." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/nonconstantformat/NonConstantFormat.qll b/cpp/common/src/codingstandards/cpp/rules/nonconstantformat/NonConstantFormat.qll index 91b2b05a3f..248cde106f 100644 --- a/cpp/common/src/codingstandards/cpp/rules/nonconstantformat/NonConstantFormat.qll +++ b/cpp/common/src/codingstandards/cpp/rules/nonconstantformat/NonConstantFormat.qll @@ -1,7 +1,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import semmle.code.cpp.commons.Printf abstract class NonConstantFormatSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/nonglobalfunctionmain/NonGlobalFunctionMain.qll b/cpp/common/src/codingstandards/cpp/rules/nonglobalfunctionmain/NonGlobalFunctionMain.qll new file mode 100644 index 0000000000..7366849d0c --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/nonglobalfunctionmain/NonGlobalFunctionMain.qll @@ -0,0 +1,20 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The identifier main shall not be used for a function other than the global function + * main. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class NonGlobalFunctionMainSharedQuery extends Query { } + +Query getQuery() { result instanceof NonGlobalFunctionMainSharedQuery } + +query predicate problems(Function f, string message) { + not isExcluded(f, getQuery()) and + f.hasName("main") and + not f.hasGlobalName("main") and + message = "Identifier main used for a function other than the global function main." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/nonterminatedescapesequences/NonTerminatedEscapeSequences.qll b/cpp/common/src/codingstandards/cpp/rules/nonterminatedescapesequences/NonTerminatedEscapeSequences.qll new file mode 100644 index 0000000000..f23965ea7c --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/nonterminatedescapesequences/NonTerminatedEscapeSequences.qll @@ -0,0 +1,44 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Octal escape sequences, hexadecimal escape sequences, and universal character names + * shall be terminated. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class NonTerminatedEscapeSequencesSharedQuery extends Query { } + +Query getQuery() { result instanceof NonTerminatedEscapeSequencesSharedQuery } + +bindingset[s] +predicate isOctalEscape(string s) { + s.charAt(0) = "\\" and + exists(int i | i = [0 .. 7] | i.toString() = s.charAt(1)) +} + +bindingset[s] +predicate isHexEscape(string s) { s.indexOf("\\x") = 0 } + +query predicate problems(Literal l, string message) { + not isExcluded(l, getQuery()) and + exists(int idx, string sl, string escapeKind, string s | + sl = l.getValueText() and + idx = sl.indexOf("\\") and + s = sl.substring(idx, sl.length()) and + // Note: Octal representations must be 1-3 digits. There is no limitation on a + // Hex literal as long as the characters are valid. This query does not consider + // if the hex literal being constructed will overflow. + ( + isHexEscape(s) and + not s.regexpMatch("^((\\\\x[0-9A-F]+(?=[\"'\\\\])))[\\s\\S]*") and + escapeKind = "hexadecimal" + or + isOctalEscape(s) and + not s.regexpMatch("^(((\\\\[0-7]{1,3})(?=[\"'\\\\])))[\\s\\S]*") and + escapeKind = "octal" + ) and + message = "Invalid " + escapeKind + " escape in string literal at '" + s + "'." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/nonuniqueenumerationconstant/NonUniqueEnumerationConstant.qll b/cpp/common/src/codingstandards/cpp/rules/nonuniqueenumerationconstant/NonUniqueEnumerationConstant.qll new file mode 100644 index 0000000000..f7afe8b3e7 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/nonuniqueenumerationconstant/NonUniqueEnumerationConstant.qll @@ -0,0 +1,38 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Within an enumerator list, the value of an implicitly-specified enumeration constant + * shall be unique. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class NonUniqueEnumerationConstantSharedQuery extends Query { } + +Query getQuery() { result instanceof NonUniqueEnumerationConstantSharedQuery } + +/** + * An `EnumConstant` that has an implicitly specified value: + * `enum e { explicit = 1, implicit }` + */ +class ImplicitlySpecifiedEnumConstant extends EnumConstant { + ImplicitlySpecifiedEnumConstant() { + //implicitly specified have an initializer with location: `file://:0:0:0:0` + not this.getInitializer().getLocation().getFile() = this.getFile() + } +} + +query predicate problems( + ImplicitlySpecifiedEnumConstant imp, string message, EnumConstant exp, string exp_string +) { + not isExcluded(imp, getQuery()) and + not isExcluded(exp, getQuery()) and + not exp = imp and + imp.getValue() = exp.getValue() and + imp.getDeclaringEnum() = exp.getDeclaringEnum() and + //can technically be the same declared enum across multiple headers but those are not relevant to this rule + imp.getFile() = exp.getFile() and + message = "Nonunique value of enum constant compared to $@" and + exp_string = exp.getName() +} diff --git a/cpp/common/src/codingstandards/cpp/rules/notdistinctidentifier/NotDistinctIdentifier.qll b/cpp/common/src/codingstandards/cpp/rules/notdistinctidentifier/NotDistinctIdentifier.qll index 2d6767f664..102c53428b 100644 --- a/cpp/common/src/codingstandards/cpp/rules/notdistinctidentifier/NotDistinctIdentifier.qll +++ b/cpp/common/src/codingstandards/cpp/rules/notdistinctidentifier/NotDistinctIdentifier.qll @@ -1,5 +1,6 @@ /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library with a `problems` predicate for the following issue: + * Using nondistinct external identifiers results in undefined behaviour. */ import cpp @@ -11,6 +12,16 @@ abstract class NotDistinctIdentifierSharedQuery extends Query { } Query getQuery() { result instanceof NotDistinctIdentifierSharedQuery } +bindingset[d, d2] +pragma[inline_late] +private predicate after(ExternalIdentifiers d, ExternalIdentifiers d2) { + exists(int dStartLine, int d2StartLine | + d.getLocation().hasLocationInfo(_, dStartLine, _, _, _) and + d2.getLocation().hasLocationInfo(_, d2StartLine, _, _, _) and + dStartLine >= d2StartLine + ) +} + query predicate problems( ExternalIdentifiers d, string message, ExternalIdentifiers d2, string nameplaceholder ) { @@ -19,10 +30,10 @@ query predicate problems( d.getName().length() >= 31 and d2.getName().length() >= 31 and not d = d2 and - d.getLocation().getStartLine() >= d2.getLocation().getStartLine() and d.getSignificantName() = d2.getSignificantName() and not d.getName() = d2.getName() and nameplaceholder = d2.getName() and + after(d, d2) and message = "External identifer " + d.getName() + " is nondistinct in characters at or over 31 limit, compared to $@" diff --git a/cpp/common/src/codingstandards/cpp/rules/nullptrnottheonlyformofthenullpointerconstant/NullptrNotTheOnlyFormOfTheNullPointerConstant.qll b/cpp/common/src/codingstandards/cpp/rules/nullptrnottheonlyformofthenullpointerconstant/NullptrNotTheOnlyFormOfTheNullPointerConstant.qll new file mode 100644 index 0000000000..2b24aa9410 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/nullptrnottheonlyformofthenullpointerconstant/NullptrNotTheOnlyFormOfTheNullPointerConstant.qll @@ -0,0 +1,25 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * nullptr shall be the only form of the null-pointer-constant. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import semmle.code.cpp.commons.NULL + +abstract class NullptrNotTheOnlyFormOfTheNullPointerConstantSharedQuery extends Query { } + +Query getQuery() { result instanceof NullptrNotTheOnlyFormOfTheNullPointerConstantSharedQuery } + +query predicate problems(Literal l, string message) { + not isExcluded(l, getQuery()) and // Not the type of the nullptr literal + not l.getType() instanceof NullPointerType and + // Converted to a pointer type + l.getConversion().getType().getUnspecifiedType() instanceof PointerType and + // Value of zero + l.getValue() = "0" and + // Not the StringLiteral "0" + not l instanceof StringLiteral and + message = l.getValueText() + " is used as the null-pointer-constant but is not nullptr." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/objectsdynamictypeusedfromconstructorordestructor/ObjectsDynamicTypeUsedFromConstructorOrDestructor.qll b/cpp/common/src/codingstandards/cpp/rules/objectsdynamictypeusedfromconstructorordestructor/ObjectsDynamicTypeUsedFromConstructorOrDestructor.qll new file mode 100644 index 0000000000..1303646ef5 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/objectsdynamictypeusedfromconstructorordestructor/ObjectsDynamicTypeUsedFromConstructorOrDestructor.qll @@ -0,0 +1,91 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * An object’s dynamic type shall not be used from within its constructor or + * destructor. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class ObjectsDynamicTypeUsedFromConstructorOrDestructorSharedQuery extends Query { } + +Query getQuery() { result instanceof ObjectsDynamicTypeUsedFromConstructorOrDestructorSharedQuery } + +predicate thisCall(FunctionCall c) { + c.getQualifier() instanceof ThisExpr or + c.getQualifier().(PointerDereferenceExpr).getChild(0) instanceof ThisExpr +} + +predicate virtualThisCall(FunctionCall c, Function overridingFunction) { + c.isVirtual() and + thisCall(c) and + overridingFunction = c.getTarget().(VirtualFunction).getAnOverridingFunction() +} + +class DynamicTypeExpr extends Expr { + DynamicTypeExpr() { + this instanceof TypeidOperator and + this.getEnclosingFunction().getDeclaringType().isPolymorphic() + or + this instanceof DynamicCast + or + virtualThisCall(this.(FunctionCall), _) + } +} + +/* + * Catch most cases: go into functions in the same class, but only catch direct + * references to "this". + */ + +predicate nonVirtualMemberFunction(MemberFunction mf, Class c) { + mf = c.getAMemberFunction() and + not mf instanceof Constructor and + not mf instanceof Destructor and + not mf.isVirtual() +} + +predicate callFromNonVirtual(MemberFunction source, Class c, MemberFunction targ) { + exists(FunctionCall fc | + fc.getEnclosingFunction() = source and fc.getTarget() = targ and thisCall(fc) + ) and + targ = c.getAMemberFunction() and + nonVirtualMemberFunction(source, c) +} + +predicate indirectlyInvokesDynamicTypeExpr(MemberFunction caller, DynamicTypeExpr target) { + target = + any(DynamicTypeExpr expr | + expr.getEnclosingFunction() = caller and + nonVirtualMemberFunction(caller, caller.getDeclaringType()) + ) + or + exists(MemberFunction mid | + indirectlyInvokesDynamicTypeExpr(mid, target) and + callFromNonVirtual(caller, caller.getDeclaringType(), mid) + ) +} + +query predicate problems( + DynamicTypeExpr expr, string explanation, MemberFunction mf, string mf_string +) { + not isExcluded(expr, getQuery()) and + ( + mf instanceof Constructor or + mf instanceof Destructor + ) and + mf_string = mf.getQualifiedName() and + exists(FunctionCall call | + mf = expr.getEnclosingFunction() and + explanation = "$@ uses the dynamic type of its own object." + or + mf != expr.getEnclosingFunction() and + mf = call.getEnclosingFunction() and + thisCall(call) and + indirectlyInvokesDynamicTypeExpr(call.getTarget(), expr) and + explanation = + "$@ calls " + call.getTarget().getQualifiedName() + + ", which uses the dynamic type of its own object." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/onlyfreememoryallocateddynamicallyshared/OnlyFreeMemoryAllocatedDynamicallyShared.qll b/cpp/common/src/codingstandards/cpp/rules/onlyfreememoryallocateddynamicallyshared/OnlyFreeMemoryAllocatedDynamicallyShared.qll index bede451e24..89c732ff5a 100644 --- a/cpp/common/src/codingstandards/cpp/rules/onlyfreememoryallocateddynamicallyshared/OnlyFreeMemoryAllocatedDynamicallyShared.qll +++ b/cpp/common/src/codingstandards/cpp/rules/onlyfreememoryallocateddynamicallyshared/OnlyFreeMemoryAllocatedDynamicallyShared.qll @@ -7,7 +7,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.Allocations -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import NonDynamicPointerToFreeFlow::PathGraph /** diff --git a/cpp/common/src/codingstandards/cpp/rules/orderingpredicatemustbestrictlyweak/OrderingPredicateMustBeStrictlyWeak.qll b/cpp/common/src/codingstandards/cpp/rules/orderingpredicatemustbestrictlyweak/OrderingPredicateMustBeStrictlyWeak.qll index aa4b646ec6..1e9c025e4d 100644 --- a/cpp/common/src/codingstandards/cpp/rules/orderingpredicatemustbestrictlyweak/OrderingPredicateMustBeStrictlyWeak.qll +++ b/cpp/common/src/codingstandards/cpp/rules/orderingpredicatemustbestrictlyweak/OrderingPredicateMustBeStrictlyWeak.qll @@ -14,19 +14,19 @@ abstract class OrderingPredicateMustBeStrictlyWeakSharedQuery extends Query { } Query getQuery() { result instanceof OrderingPredicateMustBeStrictlyWeakSharedQuery } +class IsStrictlyWeaklyOrderedComment extends Comment { + IsStrictlyWeaklyOrderedComment() { + exists(getContents().regexpFind("(?m)^\\s*(//|\\*)\\s*@IsStrictlyWeaklyOrdered\\s*$", _, _)) + } +} + /** * User annotated class indicating a comparator is axiomatically strictly weakly * ordering. */ class UserDefinedStrictlyWeakOrderingComparator extends Class { UserDefinedStrictlyWeakOrderingComparator() { - exists(Comment c, string contents | - c.getCommentedElement() = this.getADeclarationEntry() and - contents = - c.getContents() - .splitAt("\n") - .regexpFind("^\\s*(//|\\*)\\s*@IsStrictlyWeaklyOrdered\\s*$", _, _) - ) + exists(IsStrictlyWeaklyOrderedComment c | c.getCommentedElement() = this.getADeclarationEntry()) } } diff --git a/cpp/common/src/codingstandards/cpp/rules/overridingshallspecifydifferentdefaultarguments/OverridingShallSpecifyDifferentDefaultArguments.qll b/cpp/common/src/codingstandards/cpp/rules/overridingshallspecifydifferentdefaultarguments/OverridingShallSpecifyDifferentDefaultArguments.qll new file mode 100644 index 0000000000..acfa177561 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/overridingshallspecifydifferentdefaultarguments/OverridingShallSpecifyDifferentDefaultArguments.qll @@ -0,0 +1,37 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Parameters in an overriding virtual function shall not specify different default + * arguments. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class OverridingShallSpecifyDifferentDefaultArgumentsSharedQuery extends Query { } + +Query getQuery() { result instanceof OverridingShallSpecifyDifferentDefaultArgumentsSharedQuery } + +query predicate problems(VirtualFunction f2, string message, VirtualFunction f1, string f1_string) { + not isExcluded(f2, getQuery()) and + not isExcluded(f1, getQuery()) and + f2 = f1.getAnOverridingFunction() and + exists(Parameter p1, Parameter p2 | + p1 = f1.getAParameter() and + p2 = f2.getParameter(p1.getIndex()) + | + if p1.hasInitializer() + then + // if there is no initializer + not p2.hasInitializer() + or + // if there is one and it doesn't match + not p1.getInitializer().getExpr().getValueText() = + p2.getInitializer().getExpr().getValueText() + else + // if p1 doesn't have an initializer p2 shouldn't either + p2.hasInitializer() + ) and + message = "Overriding function does not have the same default parameters as $@" and + f1_string = "overridden function" +} diff --git a/cpp/common/src/codingstandards/cpp/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.qll b/cpp/common/src/codingstandards/cpp/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.qll index e24fb91539..2ee92b1611 100644 --- a/cpp/common/src/codingstandards/cpp/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.qll +++ b/cpp/common/src/codingstandards/cpp/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.qll @@ -8,7 +8,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.SmartPointers -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import PointerToSmartPointerConstructorFlowFlow::PathGraph abstract class OwnedPointerValueStoredInUnrelatedSmartPointerSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/placementnewinsufficientstorage/PlacementNewInsufficientStorage.qll b/cpp/common/src/codingstandards/cpp/rules/placementnewinsufficientstorage/PlacementNewInsufficientStorage.qll index dc26d13b87..6b2c6c87c9 100644 --- a/cpp/common/src/codingstandards/cpp/rules/placementnewinsufficientstorage/PlacementNewInsufficientStorage.qll +++ b/cpp/common/src/codingstandards/cpp/rules/placementnewinsufficientstorage/PlacementNewInsufficientStorage.qll @@ -7,7 +7,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.allocations.PlacementNew -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import PlacementNewOriginFlow::PathGraph abstract class PlacementNewInsufficientStorageSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/placementnewnotproperlyaligned/PlacementNewNotProperlyAligned.qll b/cpp/common/src/codingstandards/cpp/rules/placementnewnotproperlyaligned/PlacementNewNotProperlyAligned.qll index 72286f2d79..d250061a23 100644 --- a/cpp/common/src/codingstandards/cpp/rules/placementnewnotproperlyaligned/PlacementNewNotProperlyAligned.qll +++ b/cpp/common/src/codingstandards/cpp/rules/placementnewnotproperlyaligned/PlacementNewNotProperlyAligned.qll @@ -7,7 +7,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.allocations.PlacementNew -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import PlacementNewOriginFlow::PathGraph abstract class PlacementNewNotProperlyAlignedSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.qll b/cpp/common/src/codingstandards/cpp/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.qll new file mode 100644 index 0000000000..6993778a4d --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.qll @@ -0,0 +1,42 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * A pointer to a virtual base class shall only be cast to a pointer to a derived class + * by means of dynamic_cast, otherwise the cast has undefined behavior. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class PointerToAVirtualBaseClassCastToAPointerSharedQuery extends Query { } + +Query getQuery() { result instanceof PointerToAVirtualBaseClassCastToAPointerSharedQuery } + +query predicate problems( + Cast cast, string message, VirtualClassDerivation derivation, string derivationDescription +) { + exists(Class castFrom, VirtualBaseClass virtualBaseClass, Class castTo, string type | + not isExcluded(cast, getQuery()) and + not cast instanceof DynamicCast and + castTo = virtualBaseClass.getADerivedClass+() and + virtualBaseClass = castFrom.getADerivedClass*() and + derivation = virtualBaseClass.getAVirtualDerivation() and + derivation.getDerivedClass().getADerivedClass*() = castTo and + derivationDescription = "derived through virtual base class " + virtualBaseClass.getName() and + message = + "dynamic_cast not used for cast from " + type + " to base class " + castFrom.getName() + + " to derived class " + castTo.getName() + " which is $@." + | + // Pointer cast + castFrom = cast.getExpr().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and + cast.getType().stripTopLevelSpecifiers().(PointerType).getBaseType() = castTo and + type = "pointer" + or + // Reference type cast + castFrom = cast.getExpr().getType().stripTopLevelSpecifiers() and + // Not actually represented as a reference type in our model - instead as the + // type itself + cast.getType().stripTopLevelSpecifiers() = castTo and + type = "reference" + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/potentiallyvirtualpointeronlycomparestonullptr/PotentiallyVirtualPointerOnlyComparesToNullptr.qll b/cpp/common/src/codingstandards/cpp/rules/potentiallyvirtualpointeronlycomparestonullptr/PotentiallyVirtualPointerOnlyComparesToNullptr.qll new file mode 100644 index 0000000000..667480a43a --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/potentiallyvirtualpointeronlycomparestonullptr/PotentiallyVirtualPointerOnlyComparesToNullptr.qll @@ -0,0 +1,32 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * A comparison of a potentially virtual pointer to member function shall only be with + * nullptr. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class PotentiallyVirtualPointerOnlyComparesToNullptrSharedQuery extends Query { } + +Query getQuery() { result instanceof PotentiallyVirtualPointerOnlyComparesToNullptrSharedQuery } + +query predicate problems( + EqualityOperation equalityComparison, string message, MemberFunction virtualFunction, + string virtualFunction_string, Expr otherOperand, string otherOperand_string +) { + not isExcluded(equalityComparison, getQuery()) and + exists(FunctionAccess accessOperand | + virtualFunction.isVirtual() and + equalityComparison.getAnOperand() = accessOperand and + accessOperand.getTarget() = virtualFunction and + otherOperand = equalityComparison.getAnOperand() and + not otherOperand = accessOperand and + not otherOperand.getType() instanceof NullPointerType and + message = + "A pointer to member virtual function $@ is tested for equality with non-null-pointer-constant $@." and + virtualFunction_string = virtualFunction.getName() and + otherOperand_string = otherOperand.toString() + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/predicatefunctionobjectsshouldnotbemutable/PredicateFunctionObjectsShouldNotBeMutable.qll b/cpp/common/src/codingstandards/cpp/rules/predicatefunctionobjectsshouldnotbemutable/PredicateFunctionObjectsShouldNotBeMutable.qll index a8b6ab7576..ba2f6ed82a 100644 --- a/cpp/common/src/codingstandards/cpp/rules/predicatefunctionobjectsshouldnotbemutable/PredicateFunctionObjectsShouldNotBeMutable.qll +++ b/cpp/common/src/codingstandards/cpp/rules/predicatefunctionobjectsshouldnotbemutable/PredicateFunctionObjectsShouldNotBeMutable.qll @@ -1,5 +1,7 @@ /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library with a `problems` predicate for the following issue: + * "Non-static data members or captured values of predicate function objects + * that are state related to this object's identity shall not be copied. */ import cpp @@ -7,6 +9,7 @@ import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.SideEffect import codingstandards.cpp.sideeffect.DefaultEffects +import semmle.code.cpp.dataflow.DataFlow abstract class PredicateFunctionObjectsShouldNotBeMutableSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/preprocessingdirectivewithinmacroargument/PreprocessingDirectiveWithinMacroArgument.qll b/cpp/common/src/codingstandards/cpp/rules/preprocessingdirectivewithinmacroargument/PreprocessingDirectiveWithinMacroArgument.qll index 8b8609ab7b..8361a07a31 100644 --- a/cpp/common/src/codingstandards/cpp/rules/preprocessingdirectivewithinmacroargument/PreprocessingDirectiveWithinMacroArgument.qll +++ b/cpp/common/src/codingstandards/cpp/rules/preprocessingdirectivewithinmacroargument/PreprocessingDirectiveWithinMacroArgument.qll @@ -1,5 +1,7 @@ /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library with a `problems` predicate for the following issue: + * Arguments to a function-like macro shall not contain tokens that look like + * pre-processing directives or else behaviour after macro expansion is unpredictable. */ import cpp diff --git a/cpp/common/src/codingstandards/cpp/rules/readofuninitializedmemory/ReadOfUninitializedMemory.qll b/cpp/common/src/codingstandards/cpp/rules/readofuninitializedmemory/ReadOfUninitializedMemory.qll index 9de640db9c..8d701cb26c 100644 --- a/cpp/common/src/codingstandards/cpp/rules/readofuninitializedmemory/ReadOfUninitializedMemory.qll +++ b/cpp/common/src/codingstandards/cpp/rules/readofuninitializedmemory/ReadOfUninitializedMemory.qll @@ -131,6 +131,8 @@ class UninitializedVariable extends LocalVariable { // Not static or thread local, because they are not initialized with indeterminate values not isStatic() and not isThreadLocal() and + // Not atomic, which have special initialization rules + not getType().hasSpecifier("atomic") and // Not a class type, because default initialization of a class calls the default constructor // The default constructor may leave certain fields uninitialized, but that would be a separate // field-wise analysis diff --git a/cpp/common/src/codingstandards/cpp/rules/reinterpretcastused/ReinterpretCastUsed.qll b/cpp/common/src/codingstandards/cpp/rules/reinterpretcastused/ReinterpretCastUsed.qll new file mode 100644 index 0000000000..b49a488ab2 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/reinterpretcastused/ReinterpretCastUsed.qll @@ -0,0 +1,16 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The statement reinterpret_cast shall not be used. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class ReinterpretCastUsedSharedQuery extends Query { } + +Query getQuery() { result instanceof ReinterpretCastUsedSharedQuery } + +query predicate problems(ReinterpretCast rc, string message) { + not isExcluded(rc, getQuery()) and message = "Use of reinterpret_cast." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/resultofanassignmentoperatorshouldnotbeused/ResultOfAnAssignmentOperatorShouldNotBeUsed.qll b/cpp/common/src/codingstandards/cpp/rules/resultofanassignmentoperatorshouldnotbeused/ResultOfAnAssignmentOperatorShouldNotBeUsed.qll new file mode 100644 index 0000000000..04a106b5c4 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/resultofanassignmentoperatorshouldnotbeused/ResultOfAnAssignmentOperatorShouldNotBeUsed.qll @@ -0,0 +1,18 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The result of an assignment operator should not be used. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class ResultOfAnAssignmentOperatorShouldNotBeUsedSharedQuery extends Query { } + +Query getQuery() { result instanceof ResultOfAnAssignmentOperatorShouldNotBeUsedSharedQuery } + +query predicate problems(AssignExpr e, string message) { + not isExcluded(e, getQuery()) and + not exists(ExprStmt s | s.getExpr() = e) and + message = "Use of an assignment operator's result." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/returnreferenceorpointertoautomaticlocalvariable/ReturnReferenceOrPointerToAutomaticLocalVariable.qll b/cpp/common/src/codingstandards/cpp/rules/returnreferenceorpointertoautomaticlocalvariable/ReturnReferenceOrPointerToAutomaticLocalVariable.qll new file mode 100644 index 0000000000..b37a9cd02b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/returnreferenceorpointertoautomaticlocalvariable/ReturnReferenceOrPointerToAutomaticLocalVariable.qll @@ -0,0 +1,36 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Functions that return a reference or a pointer to an automatic variable (including + * parameters) potentially lead to undefined behaviour. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class ReturnReferenceOrPointerToAutomaticLocalVariableSharedQuery extends Query { } + +Query getQuery() { result instanceof ReturnReferenceOrPointerToAutomaticLocalVariableSharedQuery } + +query predicate problems( + ReturnStmt rs, string message, Function f, string f_string, StackVariable auto, string auto_string +) { + exists(VariableAccess va, string returnType | + not isExcluded(rs, getQuery()) and + f = rs.getEnclosingFunction() and + ( + f.getType() instanceof ReferenceType and va = rs.getExpr() and returnType = "reference" + or + f.getType() instanceof PointerType and + va = rs.getExpr().(AddressOfExpr).getOperand() and + returnType = "pointer" + ) and + auto = va.getTarget() and + not auto.isStatic() and + not f.isCompilerGenerated() and + not auto.getType() instanceof ReferenceType and + message = "The $@ returns a " + returnType + "to an $@ variable" and + f_string = f.getName() and + auto_string = "automatic" + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/stringnumberconversionmissingerrorcheck/StringNumberConversionMissingErrorCheck.qll b/cpp/common/src/codingstandards/cpp/rules/stringnumberconversionmissingerrorcheck/StringNumberConversionMissingErrorCheck.qll index 98fd51a58f..fd56f5d899 100644 --- a/cpp/common/src/codingstandards/cpp/rules/stringnumberconversionmissingerrorcheck/StringNumberConversionMissingErrorCheck.qll +++ b/cpp/common/src/codingstandards/cpp/rules/stringnumberconversionmissingerrorcheck/StringNumberConversionMissingErrorCheck.qll @@ -7,7 +7,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import semmle.code.cpp.valuenumbering.GlobalValueNumbering -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import codingstandards.cpp.standardlibrary.CharStreams abstract class StringNumberConversionMissingErrorCheckSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/switchcasepositioncondition/SwitchCasePositionCondition.qll b/cpp/common/src/codingstandards/cpp/rules/switchcasepositioncondition/SwitchCasePositionCondition.qll index 68ba9850af..979621762d 100644 --- a/cpp/common/src/codingstandards/cpp/rules/switchcasepositioncondition/SwitchCasePositionCondition.qll +++ b/cpp/common/src/codingstandards/cpp/rules/switchcasepositioncondition/SwitchCasePositionCondition.qll @@ -1,5 +1,6 @@ /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library with a `problems` predicate for the following issue: + * The switch statement syntax is weak and may lead to unspecified behaviour. */ import cpp diff --git a/cpp/common/src/codingstandards/cpp/rules/switchcompoundcondition/SwitchCompoundCondition.qll b/cpp/common/src/codingstandards/cpp/rules/switchcompoundcondition/SwitchCompoundCondition.qll new file mode 100644 index 0000000000..ab888abfec --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/switchcompoundcondition/SwitchCompoundCondition.qll @@ -0,0 +1,46 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * If the body of a switch is not enclosed in braces, then this can lead to incorrect + * execution, and hard for developers to maintain. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class SwitchCompoundConditionSharedQuery extends Query { } + +Query getQuery() { result instanceof SwitchCompoundConditionSharedQuery } + +/** + * Class to differentiate between extractor generated blockstmt and actual blockstmt. The extractor + * will generate an artificial blockstmt when there is a single case and statement, e.g. + * ``` + * switch(x) + * case 1: + * f(); + * ``` + * This is because our AST model considers the `case` to be a statement in its own right, so the + * extractor needs an aritifical block to hold both the case and the statement. + */ +class ArtificialBlock extends BlockStmt { + ArtificialBlock() { + exists(Location block, Location firstStatement | + block = getLocation() and firstStatement = getStmt(0).getLocation() + | + // We can identify artificial blocks as those where the start of the statement is at the same + // location as the start of the first statement in the block i.e. there was no opening brace. + block.getStartLine() = firstStatement.getStartLine() and + block.getStartColumn() = firstStatement.getStartColumn() + ) + } +} + +query predicate problems(SwitchStmt switch, string message) { + ( + switch.getStmt() instanceof ArtificialBlock or + not switch.getStmt() instanceof BlockStmt + ) and + not isExcluded(switch, getQuery()) and + message = "Switch body not enclosed within braces." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/switchnotwellformed/SwitchNotWellFormed.qll b/cpp/common/src/codingstandards/cpp/rules/switchnotwellformed/SwitchNotWellFormed.qll index ee04228a95..cb2e61c3ad 100644 --- a/cpp/common/src/codingstandards/cpp/rules/switchnotwellformed/SwitchNotWellFormed.qll +++ b/cpp/common/src/codingstandards/cpp/rules/switchnotwellformed/SwitchNotWellFormed.qll @@ -1,5 +1,6 @@ /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library with a `problems` predicate for the following issue: + * The switch statement syntax is weak and may lead to unspecified behaviour. */ import cpp diff --git a/cpp/common/src/codingstandards/cpp/rules/throwingoperatornewreturnsnull/ThrowingOperatorNewReturnsNull.qll b/cpp/common/src/codingstandards/cpp/rules/throwingoperatornewreturnsnull/ThrowingOperatorNewReturnsNull.qll index 9dbefeaa75..e28ef7ab07 100644 --- a/cpp/common/src/codingstandards/cpp/rules/throwingoperatornewreturnsnull/ThrowingOperatorNewReturnsNull.qll +++ b/cpp/common/src/codingstandards/cpp/rules/throwingoperatornewreturnsnull/ThrowingOperatorNewReturnsNull.qll @@ -4,7 +4,7 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.allocations.CustomOperatorNewDelete import codingstandards.cpp.exceptions.ExceptionSpecifications import codingstandards.cpp.Customizations diff --git a/cpp/common/src/codingstandards/cpp/rules/typeomitted/TypeOmitted.qll b/cpp/common/src/codingstandards/cpp/rules/typeomitted/TypeOmitted.qll index 8c1cb3b80a..0906a1de4f 100644 --- a/cpp/common/src/codingstandards/cpp/rules/typeomitted/TypeOmitted.qll +++ b/cpp/common/src/codingstandards/cpp/rules/typeomitted/TypeOmitted.qll @@ -1,5 +1,6 @@ /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library with a `problems` predicate for the following issue: + * Omission of type specifiers may not be supported by some compilers. */ import cpp diff --git a/cpp/common/src/codingstandards/cpp/rules/uncheckedrangedomainpoleerrors/UncheckedRangeDomainPoleErrors.qll b/cpp/common/src/codingstandards/cpp/rules/uncheckedrangedomainpoleerrors/UncheckedRangeDomainPoleErrors.qll index ad93f70bd4..acc7888d2c 100644 --- a/cpp/common/src/codingstandards/cpp/rules/uncheckedrangedomainpoleerrors/UncheckedRangeDomainPoleErrors.qll +++ b/cpp/common/src/codingstandards/cpp/rules/uncheckedrangedomainpoleerrors/UncheckedRangeDomainPoleErrors.qll @@ -4,63 +4,14 @@ import cpp import codingstandards.cpp.CodingStandards +import codingstandards.cpp.FloatingPoint +import codingstandards.cpp.FloatingPoint::SimpleDomainError import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis abstract class UncheckedRangeDomainPoleErrorsSharedQuery extends Query { } Query getQuery() { result instanceof UncheckedRangeDomainPoleErrorsSharedQuery } -bindingset[name] -Function getMathVariants(string name) { result.hasGlobalOrStdName([name, name + "f", name + "l"]) } - -predicate hasDomainError(FunctionCall fc, string description) { - exists(Function functionWithDomainError | fc.getTarget() = functionWithDomainError | - functionWithDomainError = [getMathVariants(["acos", "asin", "atanh"])] and - not ( - upperBound(fc.getArgument(0)) <= 1.0 and - lowerBound(fc.getArgument(0)) >= -1.0 - ) and - description = - "the argument has a range " + lowerBound(fc.getArgument(0)) + "..." + - upperBound(fc.getArgument(0)) + " which is outside the domain of this function (-1.0...1.0)" - or - functionWithDomainError = getMathVariants(["atan2", "pow"]) and - ( - fc.getArgument(0).getValue().toFloat() = 0 and - fc.getArgument(1).getValue().toFloat() = 0 and - description = "both arguments are equal to zero" - ) - or - functionWithDomainError = getMathVariants("pow") and - ( - upperBound(fc.getArgument(0)) < 0.0 and - upperBound(fc.getArgument(1)) < 0.0 and - description = "both arguments are less than zero" - ) - or - functionWithDomainError = getMathVariants("acosh") and - upperBound(fc.getArgument(0)) < 1.0 and - description = "argument is less than 1" - or - //pole error is the same as domain for logb and tgamma (but not ilogb - no pole error exists) - functionWithDomainError = getMathVariants(["ilogb", "logb", "tgamma"]) and - fc.getArgument(0).getValue().toFloat() = 0 and - description = "argument is equal to zero" - or - functionWithDomainError = getMathVariants(["log", "log10", "log2", "sqrt"]) and - upperBound(fc.getArgument(0)) < 0.0 and - description = "argument is negative" - or - functionWithDomainError = getMathVariants("log1p") and - upperBound(fc.getArgument(0)) < -1.0 and - description = "argument is less than 1" - or - functionWithDomainError = getMathVariants("fmod") and - fc.getArgument(1).getValue().toFloat() = 0 and - description = "y is 0" - ) -} - predicate hasRangeError(FunctionCall fc, string description) { exists(Function functionWithRangeError | fc.getTarget() = functionWithRangeError | functionWithRangeError.hasGlobalOrStdName(["abs", "labs", "llabs", "imaxabs"]) and diff --git a/cpp/common/src/codingstandards/cpp/rules/unnecessaryexposedidentifierdeclarationshared/UnnecessaryExposedIdentifierDeclarationShared.qll b/cpp/common/src/codingstandards/cpp/rules/unnecessaryexposedidentifierdeclarationshared/UnnecessaryExposedIdentifierDeclarationShared.qll index a18ab593bb..695a8740b6 100644 --- a/cpp/common/src/codingstandards/cpp/rules/unnecessaryexposedidentifierdeclarationshared/UnnecessaryExposedIdentifierDeclarationShared.qll +++ b/cpp/common/src/codingstandards/cpp/rules/unnecessaryexposedidentifierdeclarationshared/UnnecessaryExposedIdentifierDeclarationShared.qll @@ -120,7 +120,10 @@ private predicate isTypeUse(Type t1, Type t2) { } newtype TDeclarationAccess = - ObjectAccess(Variable v, VariableAccess va) { va = v.getAnAccess() } or + ObjectAccess(Variable v, VariableAccess va) { + va = v.getAnAccess() or + v.(TemplateVariable).getAnInstantiation().getAnAccess() = va + } or /* Type access can be done in a declaration or an expression (e.g., static member function call) */ TypeAccess(Type t, Element access) { isTypeUse(access.(Variable).getUnspecifiedType(), t) @@ -205,9 +208,13 @@ class DeclarationAccess extends TDeclarationAccess { class CandidateDeclaration extends Declaration { CandidateDeclaration() { - this instanceof LocalVariable + this instanceof LocalVariable and + not this.(LocalVariable).isConstexpr() and + not this.isFromTemplateInstantiation(_) or - this instanceof GlobalOrNamespaceVariable + this instanceof GlobalOrNamespaceVariable and + not this.isFromTemplateInstantiation(_) and + not this.(GlobalOrNamespaceVariable).isConstexpr() or this instanceof Type and not this instanceof ClassTemplateInstantiation and @@ -229,7 +236,13 @@ Scope possibleScopesForDeclaration(CandidateDeclaration d) { result = scope.getStrictParent*() ) and // Limit the best scope to block statements and namespaces or control structures - (result instanceof BlockStmt or result instanceof Namespace) + ( + result instanceof BlockStmt and + // Template variables cannot be in block scope + not d instanceof TemplateVariable + or + result instanceof Namespace + ) } /* Gets the smallest scope that includes all the declaration accesses of declaration `d`. */ diff --git a/cpp/common/src/codingstandards/cpp/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.qll b/cpp/common/src/codingstandards/cpp/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.qll new file mode 100644 index 0000000000..a9535d9bfc --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.qll @@ -0,0 +1,31 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Unsigned integer literals shall be appropriately suffixed. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Cpp14Literal + +abstract class UnsignedIntegerLiteralsNotAppropriatelySuffixedSharedQuery extends Query { } + +Query getQuery() { result instanceof UnsignedIntegerLiteralsNotAppropriatelySuffixedSharedQuery } + +query predicate problems(Cpp14Literal::NumericLiteral nl, string message) { + exists(string literalKind | + not isExcluded(nl, getQuery()) and + ( + nl instanceof Cpp14Literal::OctalLiteral and literalKind = "Octal" + or + nl instanceof Cpp14Literal::HexLiteral and literalKind = "Hex" + or + nl instanceof Cpp14Literal::BinaryLiteral and literalKind = "Binary" + ) and + // This either directly has an unsigned integer type, or it is converted to an unsigned integer type + nl.getType().getUnspecifiedType().(IntegralType).isUnsigned() and + // The literal already has a `u` or `U` suffix. + not nl.getValueText().regexpMatch(".*[lL]*[uU][lL]*") and + message = literalKind + " literal is an unsigned integer but does not include a 'U' suffix." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/unsignedoperationwithconstantoperandswraps/UnsignedOperationWithConstantOperandsWraps.qll b/cpp/common/src/codingstandards/cpp/rules/unsignedoperationwithconstantoperandswraps/UnsignedOperationWithConstantOperandsWraps.qll new file mode 100644 index 0000000000..bc0c6d8fc1 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/unsignedoperationwithconstantoperandswraps/UnsignedOperationWithConstantOperandsWraps.qll @@ -0,0 +1,33 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * An unsigned arithmetic operation with constant operands should not wrap. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Overflow +import semmle.code.cpp.controlflow.Guards +import semmle.code.cpp.valuenumbering.GlobalValueNumbering + +abstract class UnsignedOperationWithConstantOperandsWrapsSharedQuery extends Query { } + +Query getQuery() { result instanceof UnsignedOperationWithConstantOperandsWrapsSharedQuery } + +query predicate problems(InterestingOverflowingOperation op, string message) { + not isExcluded(op, getQuery()) and + op.getType().getUnderlyingType().(IntegralType).isUnsigned() and + // Not within a guard condition + not exists(GuardCondition gc | gc.getAChild*() = op) and + // Not guarded by a check, where the check is not an invalid overflow check + not op.hasValidPreCheck() and + // Is not checked after the operation + not op.hasValidPostCheck() and + // Permitted by exception 3 + not op instanceof LShiftExpr and + // Permitted by exception 2 - zero case is handled in separate query + not op instanceof DivExpr and + not op instanceof RemExpr and + message = + "Operation " + op.getOperator() + " of type " + op.getType().getUnderlyingType() + " may wrap." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/unusedtypedeclarations/UnusedTypeDeclarations.qll b/cpp/common/src/codingstandards/cpp/rules/unusedtypedeclarations/UnusedTypeDeclarations.qll index 85ffb7b992..b6d085619a 100644 --- a/cpp/common/src/codingstandards/cpp/rules/unusedtypedeclarations/UnusedTypeDeclarations.qll +++ b/cpp/common/src/codingstandards/cpp/rules/unusedtypedeclarations/UnusedTypeDeclarations.qll @@ -5,7 +5,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.TypeUses +import codingstandards.cpp.types.Uses abstract class UnusedTypeDeclarationsSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/useofnonzerooctalliteral/UseOfNonZeroOctalLiteral.qll b/cpp/common/src/codingstandards/cpp/rules/useofnonzerooctalliteral/UseOfNonZeroOctalLiteral.qll new file mode 100644 index 0000000000..f5d1834723 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/useofnonzerooctalliteral/UseOfNonZeroOctalLiteral.qll @@ -0,0 +1,19 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Octal constants shall not be used. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Cpp14Literal + +abstract class UseOfNonZeroOctalLiteralSharedQuery extends Query { } + +Query getQuery() { result instanceof UseOfNonZeroOctalLiteralSharedQuery } + +query predicate problems(Cpp14Literal::OctalLiteral octalLiteral, string message) { + not isExcluded(octalLiteral, getQuery()) and + not octalLiteral.getValue() = "0" and + message = "Non zero octal literal " + octalLiteral.getValueText() + "." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.qll b/cpp/common/src/codingstandards/cpp/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.qll index c421ae3cc9..3b0abbad0d 100644 --- a/cpp/common/src/codingstandards/cpp/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.qll +++ b/cpp/common/src/codingstandards/cpp/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.qll @@ -6,7 +6,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow abstract class UseOnlyArrayIndexingForPointerArithmeticSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll b/cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll new file mode 100644 index 0000000000..047d501a22 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll @@ -0,0 +1,52 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The basic numerical types of signed/unsigned char, int, short, long are not supposed + * to be used. The specific-length types from header need be used instead. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.EncapsulatingFunctions +import codingstandards.cpp.BuiltInNumericTypes +import codingstandards.cpp.Type +import codingstandards.cpp.Operator + +abstract class VariableWidthIntegerTypesUsedSharedQuery extends Query { } + +Query getQuery() { result instanceof VariableWidthIntegerTypesUsedSharedQuery } + +query predicate problems(Element e, string message) { + not isExcluded(e, getQuery()) and + exists(Type typeStrippedOfSpecifiers, Type rawType | + typeStrippedOfSpecifiers = stripSpecifiers(rawType) and + ( + typeStrippedOfSpecifiers instanceof BuiltInIntegerType or + typeStrippedOfSpecifiers instanceof UnsignedCharType or + typeStrippedOfSpecifiers instanceof SignedCharType + ) + | + exists(Variable v | v = e | + v.getType() = rawType and + not v instanceof ExcludedVariable and + // Dont consider template instantiations because instantiations with + // Fixed Width Types are recorded after stripping their typedef'd type, + // thereby, causing false positives (#540). + not v.isFromTemplateInstantiation(_) and + //post-increment/post-decrement operators are required by the standard to have a dummy int parameter + not v.(Parameter).getFunction() instanceof PostIncrementOperator and + not v.(Parameter).getFunction() instanceof PostDecrementOperator and + message = "Variable '" + v.getName() + "' has variable-width type." + ) + or + exists(Function f | f = e | + f.getType() = rawType and + not f instanceof ExcludedFunction and + // Dont consider template instantiations because instantiations with + // Fixed Width Types are recorded after stripping their typedef'd type, + // thereby, causing false positives (#540). + not f.isFromTemplateInstantiation(_) and + message = "Function '" + f.getName() + "' has variable-width return type." + ) + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/vectorshouldnotbespecializedwithbool/VectorShouldNotBeSpecializedWithBool.qll b/cpp/common/src/codingstandards/cpp/rules/vectorshouldnotbespecializedwithbool/VectorShouldNotBeSpecializedWithBool.qll new file mode 100644 index 0000000000..ca23306c55 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/vectorshouldnotbespecializedwithbool/VectorShouldNotBeSpecializedWithBool.qll @@ -0,0 +1,36 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The std::vector specialization differs from all other containers + * std::vector such that sizeof bool is implementation defined which causes errors + * when using some STL algorithms. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.StdNamespace + +abstract class VectorShouldNotBeSpecializedWithBoolSharedQuery extends Query { } + +Query getQuery() { result instanceof VectorShouldNotBeSpecializedWithBoolSharedQuery } + +predicate isVectorBool(ClassTemplateInstantiation c) { + c.getNamespace() instanceof StdNS and + c.getTemplateArgument(0) instanceof BoolType and + c.getSimpleName() = "vector" +} + +predicate isUsingVectorBool(ClassTemplateInstantiation c) { + isVectorBool(c) or + isUsingVectorBool(c.getTemplateArgument(_)) +} + +query predicate problems(Variable v, string message) { + exists(ClassTemplateInstantiation c | + not isExcluded(v, getQuery()) and + v.getUnderlyingType() = c and + not v.isFromTemplateInstantiation(_) and + isUsingVectorBool(c) and + message = "Use of std::vector specialization." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/virtualandnonvirtualclassinthehierarchy/VirtualAndNonVirtualClassInTheHierarchy.qll b/cpp/common/src/codingstandards/cpp/rules/virtualandnonvirtualclassinthehierarchy/VirtualAndNonVirtualClassInTheHierarchy.qll new file mode 100644 index 0000000000..f29d69d1ac --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/virtualandnonvirtualclassinthehierarchy/VirtualAndNonVirtualClassInTheHierarchy.qll @@ -0,0 +1,40 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * An accessible base class shall not be both virtual and non-virtual in the same + * hierarchy. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class VirtualAndNonVirtualClassInTheHierarchySharedQuery extends Query { } + +Query getQuery() { result instanceof VirtualAndNonVirtualClassInTheHierarchySharedQuery } + +query predicate problems( + Class c3, string message, Class base, string base_string, ClassDerivation cd1, string cd1_string, + Class c2, string c2_string +) { + exists(Class c1, ClassDerivation cd2 | + not isExcluded(c3, getQuery()) and + // for each pair of classes, get all of their derivations + cd1 = c1.getADerivation() and + cd2 = c2.getADerivation() and + // where they share the same base class + base = cd1.getBaseClass() and + base = cd2.getBaseClass() and + // but one is virtual, and one is not, and the derivations are in different classes + cd1.isVirtual() and + not cd2.isVirtual() and + // and there is some 'other class' that derives from both of these classes + c3.derivesFrom*(c1) and + c3.derivesFrom*(c2) and + // and the base class is accessible from the 'other class' + c3.getAMemberFunction().getEnclosingAccessHolder().canAccessClass(base, c3) and + message = "Class inherits base class $@, which is derived virtual by $@ and non-virtual by $@." and + base_string = base.getName() and + cd1_string = cd1.getDerivedClass().toString() and + c2_string = cd2.getDerivedClass().toString() + ) +} diff --git a/cpp/common/src/codingstandards/cpp/standardlibrary/FileStreams.qll b/cpp/common/src/codingstandards/cpp/standardlibrary/FileStreams.qll index c4724d36c2..99eec1f5e0 100644 --- a/cpp/common/src/codingstandards/cpp/standardlibrary/FileStreams.qll +++ b/cpp/common/src/codingstandards/cpp/standardlibrary/FileStreams.qll @@ -10,8 +10,8 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow -import codingstandards.cpp.dataflow.TaintTracking +private import semmle.code.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.TaintTracking private import codingstandards.cpp.Operator /** diff --git a/cpp/common/src/codingstandards/cpp/trustboundary/UninitializedField.qll b/cpp/common/src/codingstandards/cpp/trustboundary/UninitializedField.qll index e6a2bbe706..f58f1352a7 100644 --- a/cpp/common/src/codingstandards/cpp/trustboundary/UninitializedField.qll +++ b/cpp/common/src/codingstandards/cpp/trustboundary/UninitializedField.qll @@ -5,7 +5,7 @@ */ import cpp -private import codingstandards.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow private import semmle.code.cpp.controlflow.SubBasicBlocks private import semmle.code.cpp.padding.Padding as Padding private import semmle.code.cpp.dataflow.internal.FlowVar diff --git a/cpp/common/src/codingstandards/cpp/types/CanonicalTypes.qll b/cpp/common/src/codingstandards/cpp/types/CanonicalTypes.qll new file mode 100644 index 0000000000..a5f6dbfe40 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/types/CanonicalTypes.qll @@ -0,0 +1,23 @@ +import cpp + +/** + * One of the 10 canonical integer types, which are the standard integer types. + */ +class CanonicalIntegralType extends IntegralType { + CanonicalIntegralType() { this = this.getCanonicalArithmeticType() } + + /** + * Holds if this is the canonical integer type with the shortest name for its size. + */ + predicate isMinimal() { + not exists(CanonicalIntegralType other | + other.getSize() = this.getSize() and + ( + other.isSigned() and this.isSigned() + or + other.isUnsigned() and this.isUnsigned() + ) and + other.getName().length() < this.getName().length() + ) + } +} diff --git a/cpp/common/src/codingstandards/cpp/types/Compatible.qll b/cpp/common/src/codingstandards/cpp/types/Compatible.qll new file mode 100644 index 0000000000..eb6fa6446f --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/types/Compatible.qll @@ -0,0 +1,532 @@ +import cpp +import codeql.util.Boolean +import codingstandards.cpp.types.Graph +import codingstandards.cpp.types.Type +import codingstandards.cpp.types.FunctionType + +module TypeNamesMatchConfig implements TypeEquivalenceSig { + predicate resolveTypedefs() { + // We don't want to resolve typedefs here, as we want to compare the names of the types. + none() + } +} + +/** + * The set of types that are used in function signatures. + */ +class FunctionSignatureType extends Type { + FunctionSignatureType() { + exists(FunctionDeclarationEntry f | + this = f.getType() or this = f.getAParameterDeclarationEntry().getType() + ) + } +} + +class VariableType extends Type { + VariableType() { this = any(VariableDeclarationEntry v).getType() } +} + +predicate parameterNamesUnmatched(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { + pragma[only_bind_into](f1).getDeclaration() = pragma[only_bind_into](f2).getDeclaration() and + exists(string p1Name, string p2Name, int i | + p1Name = f1.getParameterDeclarationEntry(i).getName() and + p2Name = f2.getParameterDeclarationEntry(i).getName() + | + not p1Name = p2Name + ) +} + +/** + * Implements type compatibility as defined in C17, assuming typedefs have already been resolved. + * + * The default TypeEquivalence already handles the following: + * - A type is compatible with itself + * - All specifiers must match, but the order does not matter + * - Function types are compatible if they have the same return type and compatible parameters. + * + * Additional override for array sizes and enums are added here. + */ +module TypesCompatibleConfig implements TypeEquivalenceSig { + bindingset[t1, t2] + predicate equalLeafTypes(Type t1, Type t2) { + t1 = t2 + or + t1.(IntegralType).getCanonicalArithmeticType() = t2.(IntegralType).getCanonicalArithmeticType() + or + // Enum types are compatible with one of char, int, or signed int, but the implementation + // decides. + t1 instanceof Enum and + (t2 instanceof CharType or t2 instanceof IntType) + or + t2 instanceof Enum and + (t1 instanceof CharType or t1 instanceof IntType) + } + + bindingset[t1, t2] + predicate equalArrayTypes(ArrayType t1, ArrayType t2, Boolean baseTypesEqual) { + baseTypesEqual = true and + // Compatible array types have compatible element types. If both have a constant size then that + // size must match. + count(int i | i = [t1, t2].(ArrayType).getSize()) < 2 + } +} + +/** + * Utilize QlBuiltins::InternSets to efficiently compare the sets of specifiers on two types. + */ +bindingset[t1, t2] +private predicate specifiersMatchExactly(Type t1, Type t2) { + t1 = t2 + or + SpecifierSet::getSet(t1) = SpecifierSet::getSet(t2) +} + +/** + * Base predicate for `QlBuiltins::InternSets` to get the specifier set for a type. + * + * Note that this also efficiently handles complex typedef cases, where a specified type points to + * a typedef that points to another specified type. In this case, `getASpecifier()` will return all + * of specifiers, not just those above the TypedefType. + */ +Specifier getASpecifier(SpecifiedType key) { result = key.getASpecifier() } + +module SpecifierSet = QlBuiltins::InternSets; + +/** + * Signature module for handling various kinds of potentially recursive type equivalence using the + * module `TypeEquivalence`. + * + * The various kinds of types to be compared all have an overridable predicate with default + * behavior here, and a boolean flag that indicates whether the base types are equal. This pattern + * is used because we can't make a default implementation of a predicate such as + * `equalPointerTypes` that recurses into the `TypeEquivalence` module. Instead, the + * `TypeEquivalence` module drives all of the recursion, and these predicates take the result of + * that recursion and use it to determine whether the types are equivalent. + */ +signature module TypeEquivalenceSig { + /** + * Whether two leaf types are equivalent, such as `int`s and structs. By default, we assume only + * that types are equal to themselves and that equivalent arithmetic types are equal. + */ + bindingset[t1, t2] + default predicate equalLeafTypes(Type t1, Type t2) { + t1 = t2 + or + t1.(IntegralType).getCanonicalArithmeticType() = t2.(IntegralType).getCanonicalArithmeticType() + } + + /** + * A predicate to arbitrarily override the default behavior of the `TypeEquivalence` module, + * including preventing recursion. If this predicate holds for a pair of types, then + * `TypeEquivalence::equalTypes()` holds only if `areEqual` is true. + */ + bindingset[t1, t2] + default predicate overrideTypeComparison(Type t1, Type t2, Boolean areEqual) { none() } + + /** + * Whether two specified types are equivalent. By default, we assume that the specifier sets are + * exactly the same, and the inner types also match. + */ + bindingset[t1, t2] + default predicate equalSpecifiedTypes( + SpecifiedType t1, SpecifiedType t2, Boolean unspecifiedTypesEqual + ) { + specifiersMatchExactly(t1, t2) and + unspecifiedTypesEqual = true + } + + /** + * Whether two specified types are equivalent. By default, we only require that the base (pointed + * to) types match. + */ + bindingset[t1, t2] + default predicate equalPointerTypes(PointerType t1, PointerType t2, Boolean baseTypesEqual) { + baseTypesEqual = true + } + + /** + * Whether two array types are equivalent. By default, we only require that the element types and + * array sizes match. + */ + bindingset[t1, t2] + default predicate equalArrayTypes(ArrayType t1, ArrayType t2, Boolean baseTypesEqual) { + t1.getSize() = t2.getSize() and + baseTypesEqual = true + } + + /** + * Whether two reference types are equivalent. By default, we only require that the base types match. + */ + bindingset[t1, t2] + default predicate equalReferenceTypes(ReferenceType t1, ReferenceType t2, Boolean baseTypesEqual) { + baseTypesEqual = true + } + + /** + * Whether typedefs should be resolved before comparison. By default, we assume `TypeEquivalence` + * should resolve typedefs before comparison. + */ + default predicate resolveTypedefs() { any() } + + /** + * Whether two typedef types are equivalent. + * + * This predicate is only used if `resolveTypedefs()` is false. If so, then we assume two + * typedefs are the same if they have the same name and their base types are equal. + */ + bindingset[t1, t2] + default predicate equalTypedefTypes(TypedefType t1, TypedefType t2, Boolean baseTypesEqual) { + t1.getName() = t2.getName() and + baseTypesEqual = true + } + + /** + * Whether two routine types are equivalent. By default, we only require that the return types and + * parameter types match. + */ + bindingset[t1, t2] + default predicate equalRoutineTypes( + RoutineType t1, RoutineType t2, Boolean returnTypeEqual, Boolean parameterTypesEqual + ) { + returnTypeEqual = true and parameterTypesEqual = true + } + + /** + * Whether two function pointer/reference types are equivalent. By default, we only require that + * the return types and parameter types match. + */ + bindingset[t1, t2] + default predicate equalFunctionPointerIshTypes( + FunctionPointerIshType t1, FunctionPointerIshType t2, Boolean returnTypeEqual, + Boolean parameterTypesEqual + ) { + returnTypeEqual = true and parameterTypesEqual = true + } +} + +/** + * The default equivalence behavior for the `TypeEquivalence` module. + */ +module DefaultEquivalence implements TypeEquivalenceSig { } + +/** + * A signature predicate used to restrict the set of types considered by `TypeEquivalence`, for + * performance reasons. + */ +signature predicate interestedInEquality(Type a, Type b); + +/** + * A module to check the equivalence of two types, as defined by the provided `TypeEquivalenceSig`. + * + * For performance reasons, this module is designed to be used with a predicate + * `interestedInEquality` that restricts the set of considered pairwise comparisons. + * + * To use this module, define a `TypeEquivalenceSig` module and implement a subset of `Type` that + * selects the relevant root types to be considered. Then use the predicate `equalTypes(a, b)`. + * Note that `equalTypes(a, b)` only holds if `interestedIn(a, b)` holds. A type is always + * considered to be equal to itself, and this module does not support configurations that declare + * otherwise. Additionally, `interestedIn(a, b)` implies `interestedIn(b, a)`. + * + * This module will recursively select pairs of types to be compared. For instance, if + * `interestedInEquality(a, b)` holds, then types `a` and `b` will be compared. If + * `Config::equalPointerTypes(a, b, true)` holds, then the pointed-to types of `a` and `b` will be + * compared. However, if `Config::equalPointerTypes(a, b, false)` holds, then `a` and `b` will be + * compared, but their pointed-to types will not. Similarly, inner types will not be compared if + * `Config::overrideTypeComparison(a, b, _)` holds. For detail, see the module predicates + * `shouldRecurseOn` and `interestedInNestedTypes`. + */ +module TypeEquivalence { + /** + * Performance-related predicate that holds for a pair of types `(a, b)` such that + * `interestedIn(a, b)` holds, or there exists a pair of types `(c, d)` such that + * `interestedIn(c, d)` holds, and computing `equalTypes(a, b)` requires computing + * `equalTypes(c, d)`. + * + * The goal of this predicate is to force top down rather than bottom up evaluation of type + * equivalence. That is to say, if we compare array types `int[]` and `int[]`, we to compare that + * both types are arrays first, and then compare that their base types are equal. Naively, CodeQL + * is liable to compute this kind of recursive equality in a bottom up fashion, where the cross + * product of all types is considered in computing `equalTypes(a, b)`. + * + * This interoperates with the predicate `shouldRecurseOn` to find types that will be compared, + * along with the inner types of those types that will be compared. See `shouldRecurseOn` for + * cases where this algorithm will or will not recurse. We still need to know which types are + * compared, even if we do not recurse on them, in order to properly constrain `equalTypes(x, y)` + * to hold for types such as leaf types, where we do not recurse during comparison. + * + * At each stage of recursion, we specify `pragma[only_bind_into]` to ensure that the + * prior `shouldRecurseOn` results are considered first in the pipeline. + */ + private predicate interestedInNestedTypes(Type t1, Type t2) { + // Base case: config specifies that these root types will be compared. + interestedInUnordered(t1, t2) + or + // If derived types are compared, their base types must be compared. + exists(DerivedType t1Derived, DerivedType t2Derived | + not t1Derived instanceof SpecifiedType and + not t2Derived instanceof SpecifiedType and + shouldRecurseOn(pragma[only_bind_into](t1Derived), pragma[only_bind_into](t2Derived)) and + t1 = t1Derived.getBaseType() and + t2 = t2Derived.getBaseType() + ) + or + // If specified types are compared, their unspecified types must be compared. + exists(SpecifiedType t1Spec, SpecifiedType t2Spec | + shouldRecurseOn(pragma[only_bind_into](t1Spec), pragma[only_bind_into](t2Spec)) and + ( + t1 = unspecify(t1Spec) and + t2 = unspecify(t2Spec) + ) + ) + or + // If function types are compared, their return types and parameter types must be compared. + exists(FunctionType t1Func, FunctionType t2Func | + shouldRecurseOn(pragma[only_bind_into](t1Func), pragma[only_bind_into](t2Func)) and + ( + t1 = t1Func.getReturnType() and + t2 = t2Func.getReturnType() + or + exists(int i | + t1 = t1Func.getParameterType(pragma[only_bind_out](i)) and + t2 = t2Func.getParameterType(i) + ) + ) + ) + or + // If the config says to resolve typedefs, and a typedef type is compared to a non-typedef + // type, then the non-typedef type must be compared to the base type of the typedef. + Config::resolveTypedefs() and + exists(TypedefType tdtype | + tdtype.getBaseType() = t1 and + shouldRecurseOn(pragma[only_bind_into](tdtype), t2) + or + tdtype.getBaseType() = t2 and + shouldRecurseOn(t1, pragma[only_bind_into](tdtype)) + ) + or + // If two typedef types are compared, then their base types must be compared. + exists(TypedefType t1Typedef, TypedefType t2Typedef | + shouldRecurseOn(pragma[only_bind_into](t1Typedef), pragma[only_bind_into](t2Typedef)) and + ( + t1 = t1Typedef.getBaseType() and + t2 = t2Typedef.getBaseType() + ) + ) + } + + /** + * Performance related predicate to force top down rather than bottom up evaluation of type + * equivalence. + * + * This predicate is used to determine whether we should recurse on a type. It is used in + * conjunction with the `interestedInNestedTypes` predicate to only recurse on types that are + * being compared. + * + * We don't recurse on identical types, as they are already equal. We also don't recurse on + * types that are overriden by `Config::overrideTypeComparison`, as that predicate determines + * their equalivance. + * + * For the other types, we have a set of predicates such as `Config::equalPointerTypes` that + * holds for `(x, y, true)` if the types `x` and `y` should be considered equivalent when the + * pointed-to types of `x` and `y` are equivalent. If the predicate does not hold, or holds for + * `(x, y, false)`, then we do not recurse on the types. + * + * We do not recurse on leaf types. + */ + private predicate shouldRecurseOn(Type t1, Type t2) { + // We only recurse on types we are comparing. + interestedInNestedTypes(pragma[only_bind_into](t1), pragma[only_bind_into](t2)) and + // We don't recurse on identical types, as they are already equal. + not t1 = t2 and + // We don't recurse on overriden comparisons + not Config::overrideTypeComparison(t1, t2, _) and + ( + // These pointer types are equal if their base types are equal: recurse. + Config::equalPointerTypes(t1, t2, true) + or + // These array types are equal if their base types are equal: recurse. + Config::equalArrayTypes(t1, t2, true) + or + // These reference types are equal if their base types are equal: recurse. + Config::equalReferenceTypes(t1, t2, true) + or + // These routine types are equal if their return and parameter types are equal: recurse. + Config::equalRoutineTypes(t1, t2, true, true) + or + // These function pointer-ish types are equal if their return and parameter types are equal: recurse. + Config::equalFunctionPointerIshTypes(t1, t2, true, true) + or + // These typedef types are equal if their base types are equal: recurse. + Config::equalTypedefTypes(t1, t2, true) + or + // These specified types are equal if their unspecified types are equal: recurse. + Config::equalSpecifiedTypes(t1, t2, true) + or + // We resolve typedefs, and one of these types is a typedef type: recurse. + Config::resolveTypedefs() and + ( + t1 instanceof TypedefType + or + t2 instanceof TypedefType + ) + ) + } + + /** + * Check whether two types are equivalent, as defined by the `TypeEquivalenceSig` module. + * + * This only holds if the specified predicate `interestedIn` holds for the types, or + * `interestedInNestedTypes` holds for the types, and holds if `t1` and `t2` are identical, + * regardless of how `TypeEquivalenceSig` is defined. + */ + predicate equalTypes(Type t1, Type t2) { + interestedInNestedTypes(pragma[only_bind_into](t1), pragma[only_bind_into](t2)) and + ( + t1 = t2 + or + not t1 = t2 and + if Config::overrideTypeComparison(t1, t2, _) + then Config::overrideTypeComparison(t1, t2, true) + else ( + equalLeafRelation(t1, t2) + or + equalDerivedTypes(t1, t2) + or + equalFunctionTypes(t1, t2) + or + Config::resolveTypedefs() and + ( + equalTypes(t1.(TypedefType).getBaseType(), t2) + or + equalTypes(t1, t2.(TypedefType).getBaseType()) + ) + or + not Config::resolveTypedefs() and + equalTypedefTypes(t1, t2) + ) + ) + } + + /** Whether two types will be compared, regardless of order (a, b) or (b, a). */ + private predicate interestedInUnordered(Type t1, Type t2) { + interestedIn(t1, t2) or + interestedIn(t2, t1) + } + + bindingset[t1, t2] + private predicate equalLeafRelation(LeafType t1, LeafType t2) { Config::equalLeafTypes(t1, t2) } + + bindingset[t] + private Type unspecify(SpecifiedType t) { + // This subtly and importantly handles the complicated cases of typedefs. Under most scenarios, + // if we see a typedef in `equalTypes()` we can simply get the base type and continue. However, + // there is an exception if we have a specified type that points to a typedef that points to + // another specified type. In this case, `SpecifiedType::getASpecifier()` will return all of + // specifiers, not just those above the TypedefType, and `stripTopLevelSpecifiers` will return + // the innermost type that is not a TypedefType or a SpecifiedType, which is what we want, as + // all specifiers have already been accounted for when we visit the outermost `SpecifiedType`. + if Config::resolveTypedefs() + then result = t.(SpecifiedType).stripTopLevelSpecifiers() + else result = t.(SpecifiedType).getBaseType() + } + + bindingset[t1, t2] + private predicate equalDerivedTypes(DerivedType t1, DerivedType t2) { + exists(Boolean baseTypesEqual | + (baseTypesEqual = true implies equalTypes(t1.getBaseType(), t2.getBaseType())) and + ( + Config::equalPointerTypes(t1, t2, baseTypesEqual) + or + Config::equalArrayTypes(t1, t2, baseTypesEqual) + or + Config::equalReferenceTypes(t1, t2, baseTypesEqual) + ) + ) + or + exists(Boolean unspecifiedTypesEqual | + // Note that this case is different from the above, in that we don't merely get the base + // type (as that could be a TypedefType that points to another SpecifiedType). We need to + // unspecify the type to see if the base types are equal. + (unspecifiedTypesEqual = true implies equalTypes(unspecify(t1), unspecify(t2))) and + Config::equalSpecifiedTypes(t1, t2, unspecifiedTypesEqual) + ) + } + + bindingset[t1, t2] + private predicate equalFunctionTypes(FunctionType t1, FunctionType t2) { + exists(Boolean returnTypeEqual, Boolean parameterTypesEqual | + (returnTypeEqual = true implies equalTypes(t1.getReturnType(), t2.getReturnType())) and + ( + parameterTypesEqual = true + implies + forall(int i | exists([t1, t2].getParameterType(i)) | + equalTypes(t1.getParameterType(i), t2.getParameterType(i)) + ) + ) and + ( + Config::equalRoutineTypes(t1, t2, returnTypeEqual, parameterTypesEqual) + or + Config::equalFunctionPointerIshTypes(t1, t2, returnTypeEqual, parameterTypesEqual) + ) + ) + } + + bindingset[t1, t2] + private predicate equalTypedefTypes(TypedefType t1, TypedefType t2) { + exists(Boolean baseTypesEqual | + (baseTypesEqual = true implies equalTypes(t1.getBaseType(), t2.getBaseType())) and + Config::equalTypedefTypes(t1, t2, baseTypesEqual) + ) + } +} + +signature predicate interestedInFunctionDeclarations( + FunctionDeclarationEntry f1, FunctionDeclarationEntry f2 +); + +module FunctionDeclarationTypeEquivalence< + TypeEquivalenceSig Config, interestedInFunctionDeclarations/2 interestedInFunctions> +{ + private predicate interestedInReturnTypes(Type a, Type b) { + exists(FunctionDeclarationEntry aFun, FunctionDeclarationEntry bFun | + interestedInFunctions(pragma[only_bind_into](aFun), pragma[only_bind_into](bFun)) and + a = aFun.getType() and + b = bFun.getType() + ) + } + + private predicate interestedInParameterTypes(Type a, Type b) { + exists(FunctionDeclarationEntry aFun, FunctionDeclarationEntry bFun, int i | + interestedInFunctions(pragma[only_bind_into](aFun), pragma[only_bind_into](bFun)) and + a = aFun.getParameterDeclarationEntry(i).getType() and + b = bFun.getParameterDeclarationEntry(i).getType() + ) + } + + predicate equalReturnTypes(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { + interestedInFunctions(f1, f2) and + TypeEquivalence::equalTypes(f1.getType(), f2.getType()) + } + + predicate equalParameterTypes(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { + interestedInFunctions(f1, f2) and + f1.getDeclaration() = f2.getDeclaration() and + forall(int i | exists([f1, f2].getParameterDeclarationEntry(i)) | + equalParameterTypesAt(f1, f2, pragma[only_bind_into](i)) + ) + } + + predicate equalParameterTypesAt(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2, int i) { + interestedInFunctions(f1, f2) and + f1.getDeclaration() = f2.getDeclaration() and + TypeEquivalence::equalTypes(f1.getParameterDeclarationEntry(pragma[only_bind_into](i)) + .getType(), f2.getParameterDeclarationEntry(pragma[only_bind_into](i)).getType()) + } +} + +private class LeafType extends Type { + LeafType() { + not this instanceof DerivedType and + not this instanceof FunctionType + } +} diff --git a/cpp/common/src/codingstandards/cpp/types/FunctionType.qll b/cpp/common/src/codingstandards/cpp/types/FunctionType.qll new file mode 100644 index 0000000000..20166322f1 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/types/FunctionType.qll @@ -0,0 +1,19 @@ +import cpp + +/** + * Convenience class to reduce the awkwardness of how `RoutineType` and `FunctionPointerIshType` + * don't have a common ancestor. + */ +class FunctionType extends Type { + FunctionType() { this instanceof RoutineType or this instanceof FunctionPointerIshType } + + Type getReturnType() { + result = this.(RoutineType).getReturnType() or + result = this.(FunctionPointerIshType).getReturnType() + } + + Type getParameterType(int i) { + result = this.(RoutineType).getParameterType(i) or + result = this.(FunctionPointerIshType).getParameterType(i) + } +} diff --git a/cpp/common/src/codingstandards/cpp/types/Graph.qll b/cpp/common/src/codingstandards/cpp/types/Graph.qll new file mode 100644 index 0000000000..70c51a40ba --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/types/Graph.qll @@ -0,0 +1,15 @@ +import cpp + +predicate typeGraph(Type t, Type refersTo) { + refersTo = t.(DerivedType).getBaseType() + or + refersTo = t.(RoutineType).getReturnType() + or + refersTo = t.(RoutineType).getAParameterType() + or + refersTo = t.(FunctionPointerIshType).getReturnType() + or + refersTo = t.(FunctionPointerIshType).getAParameterType() + or + refersTo = t.(TypedefType).getBaseType() +} diff --git a/cpp/common/src/codingstandards/cpp/types/LvalueConversion.qll b/cpp/common/src/codingstandards/cpp/types/LvalueConversion.qll new file mode 100644 index 0000000000..252e783438 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/types/LvalueConversion.qll @@ -0,0 +1,38 @@ +import cpp + +/** + * Get the type of an lvalue after lvalue conversion. + * + * This will return the type itself if no conversion is performed. + */ +Type getLvalueConverted(Type t) { + if exists(performLvalueConversion(t, _)) + then result = performLvalueConversion(t, _) + else result = t +} + +/** + * Perform lvalue conversion on a type, allowing for a description of why the type was converted + * if it was. + * + * Does not return a value if no lvalue conversion was performed. + * + * Warning: This predicate may not return a result if the resulting type is not in the database. + * For convenience, this is accepted here, otherwise we would have to create a new type to return + * that wouldn't implement the type APIs and likely wouldn't be very useful. + */ +Type performLvalueConversion(Type t, string reason) { + result.(PointerType).getBaseType() = t.(ArrayType).getBaseType() and + reason = "array-to-pointer decay" + or + t instanceof RoutineType and + result.(PointerType).getBaseType() = t and + reason = "function-to-function-pointer decay" + or + isObjectType(t) and + exists(t.getASpecifier()) and + result = t.stripTopLevelSpecifiers() and + reason = "qualifiers removed" +} + +private predicate isObjectType(Type t) { not t.stripTopLevelSpecifiers() instanceof PointerType } diff --git a/c/common/src/codingstandards/c/Pointers.qll b/cpp/common/src/codingstandards/cpp/types/Pointers.qll similarity index 82% rename from c/common/src/codingstandards/c/Pointers.qll rename to cpp/common/src/codingstandards/cpp/types/Pointers.qll index 034080363e..28b6abc340 100644 --- a/c/common/src/codingstandards/c/Pointers.qll +++ b/cpp/common/src/codingstandards/cpp/types/Pointers.qll @@ -6,7 +6,7 @@ import cpp import codingstandards.cpp.Type /** - * A type that is a pointer or array type. + * A type that is a pointer or array type after stripping top-level specifiers. */ class PointerOrArrayType extends DerivedType { PointerOrArrayType() { @@ -15,6 +15,16 @@ class PointerOrArrayType extends DerivedType { } } +/** + * A type that is a pointer or array type. + */ +class UnspecifiedPointerOrArrayType extends DerivedType { + UnspecifiedPointerOrArrayType() { + this instanceof PointerType or + this instanceof ArrayType + } +} + /** * An expression which performs pointer arithmetic */ @@ -62,12 +72,9 @@ class ArrayPointerArithmeticExpr extends PointerArithmeticExpr, ArrayExpr { predicate isNullPointerConstant(Expr e) { e.findRootCause() instanceof NullMacro or - exists(CStyleCast c | - not c.isImplicit() and - c.getExpr() = e and - e instanceof Zero and - c.getType() instanceof VoidPointerType - ) + // 8.11 Pointer type conversions states: + // A null pointer constant, i.e. the value 0, optionally cast to void *. + e instanceof Zero or isNullPointerConstant(e.(Conversion).getExpr()) } @@ -83,9 +90,9 @@ predicate isCastNullPointerConstant(Cast c) { class PointerToObjectType extends PointerType { PointerToObjectType() { not ( - this.getUnderlyingType() instanceof FunctionPointerType or - this.getUnderlyingType() instanceof VoidPointerType or - this.getBaseType().getUnderlyingType() instanceof IncompleteType + this.getUnspecifiedType() instanceof FunctionPointerType or + this.getUnspecifiedType() instanceof VoidPointerType or + this.getBaseType().getUnspecifiedType() instanceof IncompleteType ) } } diff --git a/cpp/common/src/codingstandards/cpp/types/SimpleAssignment.qll b/cpp/common/src/codingstandards/cpp/types/SimpleAssignment.qll new file mode 100644 index 0000000000..a31400a340 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/types/SimpleAssignment.qll @@ -0,0 +1,77 @@ +/** + * Helper predicates related to C11/C17 constraints on simple assignment between two types. + * + * Currently only a subset of the constraints are implemented, specifically those + * related to pointer types. + */ + +import codingstandards.cpp.types.LvalueConversion +import codingstandards.cpp.types.Compatible + +module SimpleAssignment { + /** + * Whether a pair of qualified or unqualified pointer types satisfy the simple assignment + * constraints from 6.5.16.1. + * + * There are additional constraints not implemented here involving one or more arithmetic types. + */ + predicate satisfiesSimplePointerAssignment(Type left, Type right) { + checksAssignment(left, right) and + simplePointerAssignmentImpl(getLvalueConverted(left), right) + } + + private predicate satisfiedWhenTypesCompatible(Type left, Type right, Type checkA, Type checkB) { + interestedInTypes(left, right) and + exists(Type leftBase, Type rightBase | + // The left operand has atomic, qualified, or unqualified pointer type: + leftBase = left.stripTopLevelSpecifiers().(PointerType).getBaseType() and + rightBase = right.stripTopLevelSpecifiers().(PointerType).getBaseType() and + ( + // and both operands are pointers to qualified or unqualified versions of compatible types: + checkA = leftBase.stripTopLevelSpecifiers() and + checkB = rightBase.stripTopLevelSpecifiers() + ) and + // and the type pointed to by the left has all the qualifiers of the type pointed to by the + // right: + forall(Specifier s | s = rightBase.getASpecifier() | s = leftBase.getASpecifier()) + ) + } + + predicate interestedInTypes(Type left, Type right) { + exists(Type unconverted | + left = getLvalueConverted(unconverted) and + checksAssignment(unconverted, right) + ) + } + + predicate checksCompatibility(Type left, Type right) { + // Check if the types are compatible + exists(Type assignA, Type assignB | + checksAssignment(assignA, assignB) and + satisfiedWhenTypesCompatible(assignA, assignB, left, right) + ) + } + + /** + * Implementation of 6.5.16.1 for a pair of pointer types, that assumes lvalue conversion has been + * performed on the left operand. + */ + bindingset[left, right] + private predicate simplePointerAssignmentImpl(Type left, Type right) { + exists(Type checkA, Type checkB | + satisfiedWhenTypesCompatible(left, right, checkA, checkB) and + TypeEquivalence::equalTypes(checkA, checkB) + ) + or + exists(Type leftBase, Type rightBase | + // The left operand has atomic, qualified, or unqualified pointer type: + leftBase = left.stripTopLevelSpecifiers().(PointerType).getBaseType() and + rightBase = right.stripTopLevelSpecifiers().(PointerType).getBaseType() and + // or one operand is a pointer to a qualified or unqualified version of void + [leftBase, rightBase].stripTopLevelSpecifiers() instanceof VoidType and + // and the type pointed to by the left has all the qualifiers of the type pointed to by the + // right: + forall(Specifier s | s = rightBase.getASpecifier() | s = leftBase.getASpecifier()) + ) + } +} diff --git a/cpp/common/src/codingstandards/cpp/TrivialType.qll b/cpp/common/src/codingstandards/cpp/types/TrivialType.qll similarity index 100% rename from cpp/common/src/codingstandards/cpp/TrivialType.qll rename to cpp/common/src/codingstandards/cpp/types/TrivialType.qll diff --git a/cpp/common/src/codingstandards/cpp/types/Type.qll b/cpp/common/src/codingstandards/cpp/types/Type.qll new file mode 100644 index 0000000000..0e55b3ad58 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/types/Type.qll @@ -0,0 +1,126 @@ +/** + * A module for representing different `Type`s. + */ + +import cpp + +/** + * A fundamental type, as defined by `[basic.fundamental]`. + */ +class FundamentalType extends BuiltInType { + FundamentalType() { + // A fundamental type is any `BuiltInType` except types indicating errors during extraction, or + // "unknown" types inserted into uninstantiated templates + not this instanceof ErroneousType and + not this instanceof UnknownType + } +} + +/** + * A type that is incomplete. + */ +class IncompleteType extends Class { + IncompleteType() { not hasDefinition() } +} + +/** + * A type that implements the BitmaskType trait. + * https://en.cppreference.com/w/cpp/named_req/BitmaskType + */ +abstract class BitmaskType extends Type { } + +/** + * Holds if `enum` implements required overload `overload` to implement + * the BitmaskType trait. + */ +private predicate isRequiredEnumOverload(Enum enum, Function overload) { + overload.getName().regexpMatch("operator([&|^~]|&=|\\|=)") and + forex(Parameter p | p = overload.getAParameter() | + ( + p.getType() = enum + or + p.getType().(ReferenceType).getBaseType() = enum + ) + ) +} + +private class EnumBitmaskType extends BitmaskType, Enum { + EnumBitmaskType() { + // Implements all the required overload + count(Function overload | isRequiredEnumOverload(this, overload)) = 6 + } +} + +/** + * A type without `const` and `volatile` specifiers. + */ +Type stripSpecifiers(Type type) { + if type instanceof SpecifiedType + then result = stripSpecifiers(type.(SpecifiedType).getBaseType()) + else result = type +} + +signature class PossiblySpecifiedBaseType extends Type; + +/** + * This module defines a class `Type` which holds for types `T` and `const/volatile T` etc. + * + * Similar to `getUnspecifiedType()`, but does not resolve typedefs. Useful for matching + * potentially qualified versions of standard typedef types, such as `const mtx_t`. + * + * Example usage: `someType.(PossiblySpecified::Type).strip()` + */ +module PossiblySpecified { + import cpp as cpp + + final class CppType = cpp::Type; + + class Type extends CppType { + BaseType baseType; + + Type() { baseType = stripSpecifiers(this) } + + BaseType strip() { result = baseType } + } +} + +/** + * Get the precision of an integral type, where precision is defined as the number of bits + * that can be used to represent the numeric value. + * https://wiki.sei.cmu.edu/confluence/display/c/INT35-C.+Use+correct+integer+precisions + */ +int getPrecision(IntegralType type) { + type.isExplicitlyUnsigned() and result = type.getSize() * 8 + or + type.isExplicitlySigned() and result = type.getSize() * 8 - 1 +} + +/** + * Determines the lower and upper bounds of an integral type. + */ +predicate integralTypeBounds(IntegralType integralType, QlBuiltins::BigInt lb, QlBuiltins::BigInt ub) { + exists(QlBuiltins::BigInt limit | limit = 2.toBigInt().pow(8 * integralType.getSize()) | + if integralType instanceof BoolType + then lb = 0.toBigInt() and ub = 1.toBigInt() + else + if integralType.isSigned() + then ( + lb = -(limit / 2.toBigInt()) and ub = (limit / 2.toBigInt()) - 1.toBigInt() + ) else ( + lb = 0.toBigInt() and ub = limit - 1.toBigInt() + ) + ) +} + +/** + * The size of the smallest `int` type in the database in bytes. + */ +int sizeOfInt() { + // The size of int is implementation-defined + result = + min(int size | + size = any(IntType i | i.isSigned()).getCanonicalArithmeticType().getSize() + | + size + ) +} diff --git a/cpp/common/src/codingstandards/cpp/TypeUses.qll b/cpp/common/src/codingstandards/cpp/types/Uses.qll similarity index 100% rename from cpp/common/src/codingstandards/cpp/TypeUses.qll rename to cpp/common/src/codingstandards/cpp/types/Uses.qll diff --git a/cpp/common/src/codingstandards/cpp/types/VariablyModifiedTypes.qll b/cpp/common/src/codingstandards/cpp/types/VariablyModifiedTypes.qll new file mode 100644 index 0000000000..9de533d050 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/types/VariablyModifiedTypes.qll @@ -0,0 +1,224 @@ +import cpp + +/** + * A declaration involving a variably-modified type. + * + * Note, this holds for both VLA variable and VLA typedefs. + */ +class VmtDeclarationEntry extends DeclarationEntry { + Expr sizeExpr; + CandidateVlaType vlaType; + // `before` and `after` are captured for debugging, see doc comment for + // `declarationSubsumes`. + Location before; + Location after; + + VmtDeclarationEntry() { + // Most of this library looks for candidate VLA types, by looking for arrays + // without a size. These may or may not be VLA types. To confirm an a + // candidate type is really a VLA type, we check that the location of the + // declaration subsumes a `VlaDimensionStmt` which indicates a real VLA. + sizeExpr = any(VlaDimensionStmt vla).getDimensionExpr() and + declarationSubsumes(this, sizeExpr.getLocation(), before, after) and + ( + if this instanceof ParameterDeclarationEntry + then vlaType = this.getType().(VariablyModifiedTypeIfAdjusted).getInnerVlaType() + else vlaType = this.getType().(VariablyModifiedTypeIfUnadjusted).getInnerVlaType() + ) + } + + Expr getSizeExpr() { result = sizeExpr } + + CandidateVlaType getVlaType() { result = vlaType } + + /* VLAs may occur in macros, and result in duplication that messes up our analysis. */ + predicate appearsDuplicated() { + exists(VmtDeclarationEntry other | + other != this and + other.getSizeExpr() = getSizeExpr() + ) + } +} + +/** + * Check that the declaration entry, which may be a parameter or a variable + * etc., seems to subsume the location of `inner`, including the declaration + * type text. + * + * The location of the `DeclarationEntry` itself points to the _identifier_ + * that is declared. This range will not include the type of the declaration. + * + * For parameters, the `before` and `end` `Location` objects will be + * constrained to the closest earlier element (parameter or function body), + * these values can therefore be captured and inspected for debugging. + * + * For declarations which occur in statements, the `before` and `end` + * `Location` objects will be both constrained to be equal, and equal to, + * the `Location` of the containing `DeclStmt`. + */ +private predicate declarationSubsumes( + DeclarationEntry entry, Location inner, Location before, Location after +) { + inner.getFile() = entry.getLocation().getFile() and + ( + exists(ParameterDeclarationEntry param, FunctionDeclarationEntry func, int i | + param = entry and + func = param.getFunctionDeclarationEntry() and + func.getParameterDeclarationEntry(i) = param and + before = entry.getLocation() and + ( + after = func.getParameterDeclarationEntry(i + 1).getLocation() + or + not exists(ParameterDeclarationEntry afterParam | + afterParam = func.getParameterDeclarationEntry(i + 1) + ) and + after = func.getBlock().getLocation() + ) + ) and + before.isBefore(inner, _) and + inner.isBefore(after, _) + or + exists(DeclStmt s | + s.getADeclaration() = entry.getDeclaration() and + before = s.getLocation() and + after = before and + before.subsumes(inner) + ) + ) +} + +/** + * A candidate to be a variably length array type (VLA). + * + * This class represents a candidate only, for a few reasons. + * + * Firstly, the `ArrayType` class does not know when it has variable size, so + * this class matches all array types with unknown size, including `x[]` which + * is not a VLA. To determine the difference, we must compare locations between + * where * these types are declared, and the location of `VlaDecl`s etc. + * + * Secondly, function parameters of array type are adjusted into pointers. This + * means that while a parameter type can be a `CandidateVlaType`, that + * parameter is not a VLA. + */ +class CandidateVlaType extends ArrayType { + CandidateVlaType() { not hasArraySize() } + + Type getVariableBaseType() { result = this.getBaseType() } +} + +/** + * A type that is a variably modified type (VMT) if it does not undergo + * parameter type adjustment. + * + * A variably modified type is a VLA type, or a type containing a VMT type, for + * instance, a pointer to a VLA or a pointer to a pointer to a VLA. + * + * Function parameters and function type parameters of type `T[]` are adjusted + * to type `T*`, which can turn VMTs into non-VMTs. To check if a parameter + * type is a VMT, use `VariablyModifiedTypeIfAdjusted`. + */ +class VariablyModifiedTypeIfUnadjusted extends Type { + CandidateVlaType innerVlaType; + + VariablyModifiedTypeIfUnadjusted() { + // Take care that `int[x][y]` only matches for `innerVlaType = int[y]`. + if this instanceof CandidateVlaType + then innerVlaType = this + else innerVlaType = this.(NoAdjustmentVariablyModifiedType).getInnerVlaType() + } + + CandidateVlaType getInnerVlaType() { result = innerVlaType } +} + +/** + * A type that is a variably modified type (VMT) if it undergoes parameter type + * adjustment. + * + * A variably modified type is a VLA type, or a type containing a VMT type, for + * instance, a pointer to a VLA or a pointer to a pointer to a VLA. + * + * Function parameters and function type parameters of type `T[]` are adjusted + * to type `T*`, which can turn VMTs into non-VMTs. To check if a non-parameter + * type (for instance, the type of a local variable) is a VMT, use + * `VariablyModifiedTypeIfUnadjusted`. + */ +class VariablyModifiedTypeIfAdjusted extends Type { + CandidateVlaType innerVlaType; + + VariablyModifiedTypeIfAdjusted() { + innerVlaType = this.(ParameterAdjustedVariablyModifiedType).getInnerVlaType() + or + innerVlaType = this.(NoAdjustmentVariablyModifiedType).getInnerVlaType() + } + + CandidateVlaType getInnerVlaType() { result = innerVlaType } +} + +/** + * A variably modified type candidate which is unaffected by parameter type + * adjustment (from `T[]` to `*T`). + * + * Parameter adjustment (from `T[]` to `*T`) occurs on all function parameter + * types for exactly one level of depth. + * + * A variably-modified type (VMT) is a type which includes an inner type that is + * a VLA type. That is to say, a pointer to a VLA is a VMT, and a pointer to a + * VMT is a VMT. + * + * Note: This class does *not* match all VLA types. While VLA types *are* VMTs, + * VMTs can be parameter-adjusted to pointers, which are not VLA types. This + * class *will* match multidimensional VLAs, as those are adjusted to pointers + * to VLAs, and pointers to VLAs are VMTs. + */ +class NoAdjustmentVariablyModifiedType extends Type { + CandidateVlaType vlaType; + + NoAdjustmentVariablyModifiedType() { + exists(Type innerType | + ( + innerType = this.(DerivedType).getBaseType() + or + innerType = this.(RoutineType).getReturnType() + or + innerType = this.(FunctionPointerType).getReturnType() + or + innerType = this.(TypedefType).getBaseType() + ) and + vlaType = innerType.(VariablyModifiedTypeIfUnadjusted).getInnerVlaType() + ) + or + vlaType = + this.(FunctionPointerType) + .getAParameterType() + .(VariablyModifiedTypeIfAdjusted) + .getInnerVlaType() + or + vlaType = + this.(RoutineType).getAParameterType().(VariablyModifiedTypeIfAdjusted).getInnerVlaType() + } + + CandidateVlaType getInnerVlaType() { result = vlaType } +} + +/** + * An array type that adjusts to a variably-modified type (a type which is or + * contains a VLA type) when it is a parameter type. + * + * A variably-modified type (VMT) is a VLA type or a type which has an inner type + * that is a VMT type, for instance, a pointer to a VLA type. + * + * Parameter adjustment occurs on all function parameter types, changing type + * `T[]` to `*T` for exactly one level of depth. Therefore, a VLA type will not + * be a VLA type/VMT after parameter adjustment, unless it is an array of VMTs, + * such that it parameter adjustment produces a pointer to a VMT. + */ +class ParameterAdjustedVariablyModifiedType extends ArrayType { + CandidateVlaType innerVlaType; + + ParameterAdjustedVariablyModifiedType() { + innerVlaType = getBaseType().(VariablyModifiedTypeIfUnadjusted).getInnerVlaType() + } + + CandidateVlaType getInnerVlaType() { result = innerVlaType } +} diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index 2fe01c68ff..21663a5186 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,7 +1,7 @@ name: codeql/common-cpp-coding-standards -version: 2.32.0-dev +version: 2.52.0-dev license: MIT dependencies: - codeql/cpp-all: 0.9.3 + codeql/cpp-all: 4.0.3 dataExtensions: - - ext/*.model.yml \ No newline at end of file +- ext/*.model.yml diff --git a/cpp/common/test/codeql-pack.lock.yml b/cpp/common/test/codeql-pack.lock.yml index 514e6963d0..a45ea8f438 100644 --- a/cpp/common/test/codeql-pack.lock.yml +++ b/cpp/common/test/codeql-pack.lock.yml @@ -2,13 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.9.3 + version: 4.0.3 codeql/dataflow: - version: 0.0.4 + version: 2.0.3 + codeql/mad: + version: 1.0.19 + codeql/rangeanalysis: + version: 1.0.19 codeql/ssa: - version: 0.1.5 + version: 1.0.19 codeql/tutorial: - version: 0.1.5 + version: 1.0.19 + codeql/typeflow: + version: 1.0.19 + codeql/typetracking: + version: 2.0.3 codeql/util: - version: 0.1.5 + version: 2.0.6 + codeql/xml: + version: 1.0.19 compiled: false diff --git a/cpp/common/test/deviations/deviation_permits_basic_test/UnusedReturnValue.ql b/cpp/common/test/deviations/deviation_permits_basic_test/UnusedReturnValue.ql index 2517965fc1..469a7f7f73 100644 --- a/cpp/common/test/deviations/deviation_permits_basic_test/UnusedReturnValue.ql +++ b/cpp/common/test/deviations/deviation_permits_basic_test/UnusedReturnValue.ql @@ -16,7 +16,6 @@ import cpp import codingstandards.cpp.CodingStandards -import codingstandards.cpp.dataflow.DataFlow import codingstandards.cpp.exclusions.cpp.RuleMetadata /* This is a copy of an AUTOSAR rule, which we are using for testing purposes. */ diff --git a/cpp/common/test/deviations/deviations_basic_test/ListDeviationRecords.expected b/cpp/common/test/deviations/deviations_basic_test/ListDeviationRecords.expected index 3a095d8fb9..5115cc8a70 100644 --- a/cpp/common/test/deviations/deviations_basic_test/ListDeviationRecords.expected +++ b/cpp/common/test/deviations/deviations_basic_test/ListDeviationRecords.expected @@ -1,3 +1,3 @@ -| A0-1-1 | cpp/autosar/useless-assignment | Applies to the following file paths: deviations/deviations_basic_test | | This useless assignment is required. | | | -| A0-1-2 | cpp/autosar/unused-return-value | Applies to the following file paths: deviations/deviations_basic_test/nested/nested1,deviations/deviations_basic_test/nested/nested2 | | Unused return value. | | | +| A0-1-1 | cpp/autosar/useless-assignment | Applies to the following file paths: (root) | | This useless assignment is required. | | | +| A0-1-2 | cpp/autosar/unused-return-value | Applies to the following file paths: nested/nested1,nested/nested2 | | Unused return value. | | | | A0-4-2 | cpp/autosar/type-long-double-used | Identified by the use of the code-identifier: a-0-4-2-deviation | | long double is required for interaction with third-party libraries. | | | diff --git a/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected b/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected index 7b78d54892..afc613642a 100644 --- a/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected +++ b/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected @@ -1 +1,14 @@ +| attribute_syntax.cpp:6:15:6:17 | dd1 | Use of long double type. | +| attribute_syntax.cpp:21:15:21:17 | d10 | Use of long double type. | +| attribute_syntax.cpp:29:15:29:17 | d14 | Use of long double type. | +| attribute_syntax.cpp:34:20:34:22 | d16 | Use of long double type. | +| attribute_syntax.cpp:55:15:55:16 | d1 | Use of long double type. | +| attribute_syntax.cpp:57:17:57:18 | d2 | Use of long double type. | +| attribute_syntax.cpp:60:17:60:18 | d3 | Use of long double type. | | main.cpp:13:15:13:16 | d1 | Use of long double type. | +| main.cpp:18:15:18:16 | d4 | Use of long double type. | +| main.cpp:21:15:21:16 | d6 | Use of long double type. | +| main.cpp:30:15:30:17 | d10 | Use of long double type. | +| main.cpp:38:15:38:17 | d14 | Use of long double type. | +| main.cpp:42:15:42:17 | d15 | Use of long double type. | +| main.cpp:43:113:43:115 | d18 | Use of long double type. | diff --git a/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected b/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected index 7cc5d2e1ab..fc7af4b197 100644 --- a/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected +++ b/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected @@ -1,3 +1,17 @@ +| attribute_syntax.cpp:5:3:5:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:16:5:16:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:18:5:18:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:24:5:24:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:26:5:26:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:30:3:30:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:42:3:42:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:49:5:49:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:61:5:61:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | | main.cpp:12:3:12:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | +| main.cpp:25:3:25:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | +| main.cpp:27:3:27:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | +| main.cpp:33:3:33:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | +| main.cpp:35:3:35:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | +| main.cpp:39:3:39:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | | nested/nested3/test3.h:5:3:5:7 | call to getZ3 | Return value from call to $@ is unused. | nested/nested3/test3.h:1:5:1:9 | getZ3 | getZ3 | | nested/test.h:5:3:5:6 | call to getY | Return value from call to $@ is unused. | nested/test.h:1:5:1:8 | getY | getY | diff --git a/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.ql b/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.ql index 2517965fc1..469a7f7f73 100644 --- a/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.ql +++ b/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.ql @@ -16,7 +16,6 @@ import cpp import codingstandards.cpp.CodingStandards -import codingstandards.cpp.dataflow.DataFlow import codingstandards.cpp.exclusions.cpp.RuleMetadata /* This is a copy of an AUTOSAR rule, which we are using for testing purposes. */ diff --git a/cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp b/cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp new file mode 100644 index 0000000000..e363de55af --- /dev/null +++ b/cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp @@ -0,0 +1,76 @@ +int getZ() { return 5; } + +int alt() { + int x = 0; // COMPLIANT[DEVIATED] + getZ(); // NON_COMPLIANT + long double dd1; // NON_COMPLIANT (A0-4-2) + + long double [[codeql::autosar_deviation( + "a-0-4-2-deviation")]] dd3; // COMPLIANT[DEVIATED] + + [[codeql::autosar_deviation( + "a-0-4-2-deviation")]] long double dd4; // COMPLIANT[DEVIATED] + + [[codeql::autosar_deviation("a-0-4-2-deviation")]] { + long double d7; // COMPLIANT[DEVIATED] + getZ(); // NON_COMPLIANT (A0-1-2) + long double d8; // COMPLIANT[DEVIATED] + getZ(); // NON_COMPLIANT (A0-1-2) + long double d9; // COMPLIANT[DEVIATED] + } + long double d10; // NON_COMPLIANT (A0-4-2) + [[codeql::autosar_deviation("a-0-4-2-deviation")]] { + long double d11; // COMPLIANT[DEVIATED] + getZ(); // NON_COMPLIANT (A0-1-2) + long double d12; // COMPLIANT[DEVIATED] + getZ(); // NON_COMPLIANT (A0-1-2) + long double d13; // COMPLIANT[DEVIATED] + } + long double d14; // NON_COMPLIANT (A0-4-2) + getZ(); // NON_COMPLIANT (A0-1-2) + [[codeql::autosar_deviation("a-0-4-2-deviation")]] for (long double d15 = 0.0; + true;) { + } // COMPLIANT[DEVIATED] + for (long double d16 = 0.0; true;) { // NON_COMPLIANT (A0-4-2) + } + return 0; +} + +[[codeql::autosar_deviation("a-0-4-2-deviation")]] int +test_function_deviation() { + int x = 0; // COMPLIANT[DEVIATED] + getZ(); // NON_COMPLIANT + long double dd1; // COMPLIANT[DEVIATED] +} + +[[codeql::autosar_deviation("a-0-4-2-deviation")]] void test_lambdas() { + auto l = []() { + long double d4; // COMPLIANT[DEVIATED] + getZ(); // NON_COMPLIANT + }; +} + +// Attributes are not supported on a class level at the moment +[[codeql::autosar_deviation("a-0-4-2-deviation")]] class ClassA { + long double d1; // COMPLIANT[DEVIATED - false positive] + class ClassNested { + long double d2; // COMPLIANT[DEVIATED - false positive] + }; + void test() { + long double d3; // COMPLIANT[DEVIATED - false positive] + getZ(); // NON_COMPLIANT + } +}; + +// static_assert, templates, noexcept, multiple declarations + +// Namespaces not currently supported by attributes +// [[codeql::autosar_deviation("a-0-4-2-deviation")]] namespace NS { +// long double d1; // COMPLIANT[DEVIATED] +// class ClassA { +// long double d1; // COMPLIANT[DEVIATED] +// }; +// void test() { +// long double d1; // COMPLIANT[DEVIATED] +// } +// } \ No newline at end of file diff --git a/cpp/common/test/deviations/deviations_basic_test/main.cpp b/cpp/common/test/deviations/deviations_basic_test/main.cpp index 0b302ea1f2..17126364f4 100644 --- a/cpp/common/test/deviations/deviations_basic_test/main.cpp +++ b/cpp/common/test/deviations/deviations_basic_test/main.cpp @@ -12,5 +12,35 @@ int main(int argc, char **argv) { getX(); // NON_COMPLIANT long double d1; // NON_COMPLIANT (A0-4-2) long double d2; // a-0-4-2-deviation COMPLIANT[DEVIATED] + + long double d3; // codeql::autosar_deviation(a-0-4-2-deviation) + // COMPLIANT[DEVIATED] + long double d4; // NON_COMPLIANT (A0-4-2) + // codeql::autosar_deviation_next_line(a-0-4-2-deviation) + long double d5; // COMPLIANT[DEVIATED] + long double d6; // NON_COMPLIANT (A0-4-2) + + // codeql::autosar_deviation_begin(a-0-4-2-deviation) + long double d7; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d8; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d9; // COMPLIANT[DEVIATED] + // codeql::autosar_deviation_end(a-0-4-2-deviation) + long double d10; // NON_COMPLIANT (A0-4-2) + // codeql::autosar_deviation_begin(a-0-4-2-deviation) + long double d11; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d12; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d13; // COMPLIANT[DEVIATED] + // codeql::autosar_deviation_end(a-0-4-2-deviation) + long double d14; // NON_COMPLIANT (A0-4-2) + getX(); // NON_COMPLIANT (A0-1-2) + + // clang-format off + long double d15; /* NON_COMPLIANT*/ /* codeql::autosar_deviation_begin(a-0-4-2-deviation) */ long double d16; // COMPLIANT[DEVIATED] + long double d17; /* COMPLIANT[DEVIATED] */ /* codeql::autosar_deviation_end(a-0-4-2-deviation) */ long double d18; // NON_COMPLIANT + // clang-format on return 0; } \ No newline at end of file diff --git a/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected index 50ceb35b9d..35fca84928 100644 --- a/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected +++ b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected @@ -1,7 +1,12 @@ -| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:12:1:12:58 | Deviation of cpp/autosar/type-long-double-used for comment // a-0-4-2-deviation COMPLIANT[DEVIATED]. | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:12:1:12:58 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 12 | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:14:1:14:65 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 14 | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:18:1:18:40 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 18 | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:21:3:27:53 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 21:3:27:53 | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:29:3:35:53 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 29:3:35:53 | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:40:39:41:99 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 40:39:41:99 | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/unused-return-value] | lgtm[cpp/autosar/unused-return-value] | nested/nested2/test2.h:1:1:6:1 | Deviation of cpp/autosar/unused-return-value for nested/nested2/test2.h. | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | coding-standards.xml:1:1:17:19 | Deviation of cpp/autosar/useless-assignment for coding-standards.xml. | -| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | main.cpp:1:1:14:1 | Deviation of cpp/autosar/useless-assignment for main.cpp. | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | main.cpp:1:1:44:1 | Deviation of cpp/autosar/useless-assignment for main.cpp. | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | nested/coding-standards.xml:1:1:13:19 | Deviation of cpp/autosar/useless-assignment for nested/coding-standards.xml. | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | nested/nested2/test2.h:1:1:6:1 | Deviation of cpp/autosar/useless-assignment for nested/nested2/test2.h. | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | nested/test.h:1:1:6:1 | Deviation of cpp/autosar/useless-assignment for nested/test.h. | diff --git a/cpp/common/test/deviations/deviations_report_deviated/TypeLongDoubleUsed.expected b/cpp/common/test/deviations/deviations_report_deviated/TypeLongDoubleUsed.expected new file mode 100644 index 0000000000..e9099fa64a --- /dev/null +++ b/cpp/common/test/deviations/deviations_report_deviated/TypeLongDoubleUsed.expected @@ -0,0 +1,18 @@ +| main.cpp:11:15:11:16 | d1 | Use of long double type. | +| main.cpp:12:15:12:16 | d2 | Use of long double type. | +| main.cpp:14:15:14:16 | d3 | Use of long double type. | +| main.cpp:16:15:16:16 | d4 | Use of long double type. | +| main.cpp:18:15:18:16 | d5 | Use of long double type. | +| main.cpp:19:15:19:16 | d6 | Use of long double type. | +| main.cpp:22:15:22:16 | d7 | Use of long double type. | +| main.cpp:24:15:24:16 | d8 | Use of long double type. | +| main.cpp:26:15:26:16 | d9 | Use of long double type. | +| main.cpp:28:15:28:17 | d10 | Use of long double type. | +| main.cpp:30:15:30:17 | d11 | Use of long double type. | +| main.cpp:32:15:32:17 | d12 | Use of long double type. | +| main.cpp:34:15:34:17 | d13 | Use of long double type. | +| main.cpp:36:15:36:17 | d14 | Use of long double type. | +| main.cpp:40:15:40:17 | d15 | Use of long double type. | +| main.cpp:40:108:40:110 | d16 | Use of long double type. | +| main.cpp:41:15:41:17 | d17 | Use of long double type. | +| main.cpp:41:113:41:115 | d18 | Use of long double type. | diff --git a/cpp/common/test/deviations/deviations_report_deviated/TypeLongDoubleUsed.ql b/cpp/common/test/deviations/deviations_report_deviated/TypeLongDoubleUsed.ql new file mode 100644 index 0000000000..0ff7b93251 --- /dev/null +++ b/cpp/common/test/deviations/deviations_report_deviated/TypeLongDoubleUsed.ql @@ -0,0 +1,38 @@ +/** + * @id cpp/autosar/type-long-double-used + * @name A0-4-2: Type long double shall not be used + * @description The type long double has an implementation-defined width and therefore shall not be + * used. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/autosar/id/a0-4-2 + * correctness + * readability + * external/autosar/allocated-target/implementation + * external/autosar/enforcement/automated + * external/autosar/obligation/required + */ + +import cpp +import codingstandards.cpp.CodingStandards +import codingstandards.cpp.exclusions.cpp.RuleMetadata + +predicate isUsingLongDouble(ClassTemplateInstantiation c) { + c.getATemplateArgument() instanceof LongDoubleType or + isUsingLongDouble(c.getATemplateArgument()) +} + +from Variable v +where + not isExcluded(v, BannedTypesPackage::typeLongDoubleUsedQuery()) and + ( + v.getUnderlyingType() instanceof LongDoubleType and + not v.isFromTemplateInstantiation(_) + or + exists(ClassTemplateInstantiation c | + c = v.getType() and + isUsingLongDouble(c) + ) + ) +select v, "Use of long double type." diff --git a/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.expected b/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.expected index 7b8860d5a3..ab75d81f6f 100644 --- a/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.expected +++ b/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.expected @@ -1,3 +1,8 @@ | main.cpp:10:3:10:6 | call to getX | Return value from call to $@ is unused. | main.cpp:6:5:6:8 | getX | getX | +| main.cpp:23:3:23:6 | call to getX | Return value from call to $@ is unused. | main.cpp:6:5:6:8 | getX | getX | +| main.cpp:25:3:25:6 | call to getX | Return value from call to $@ is unused. | main.cpp:6:5:6:8 | getX | getX | +| main.cpp:31:3:31:6 | call to getX | Return value from call to $@ is unused. | main.cpp:6:5:6:8 | getX | getX | +| main.cpp:33:3:33:6 | call to getX | Return value from call to $@ is unused. | main.cpp:6:5:6:8 | getX | getX | +| main.cpp:37:3:37:6 | call to getX | Return value from call to $@ is unused. | main.cpp:6:5:6:8 | getX | getX | | nested/nested2/test2.h:5:3:5:6 | call to getZ | Return value from call to $@ is unused. | nested/nested2/test2.h:1:5:1:8 | getZ | getZ | | nested/test.h:5:3:5:6 | call to getY | Return value from call to $@ is unused. | nested/test.h:1:5:1:8 | getY | getY | diff --git a/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.ql b/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.ql index 2517965fc1..469a7f7f73 100644 --- a/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.ql +++ b/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.ql @@ -16,7 +16,6 @@ import cpp import codingstandards.cpp.CodingStandards -import codingstandards.cpp.dataflow.DataFlow import codingstandards.cpp.exclusions.cpp.RuleMetadata /* This is a copy of an AUTOSAR rule, which we are using for testing purposes. */ diff --git a/cpp/common/test/deviations/deviations_report_deviated/main.cpp b/cpp/common/test/deviations/deviations_report_deviated/main.cpp index c59dea5609..d2f58d9db1 100644 --- a/cpp/common/test/deviations/deviations_report_deviated/main.cpp +++ b/cpp/common/test/deviations/deviations_report_deviated/main.cpp @@ -10,5 +10,35 @@ int main(int argc, char **argv) { getX(); // NON_COMPLIANT long double d1; // NON_COMPLIANT (A0-4-2) long double d2; // a-0-4-2-deviation COMPLIANT[DEVIATED] + + long double d3; // codeql::autosar_deviation(a-0-4-2-deviation) + // COMPLIANT[DEVIATED] + long double d4; // NON_COMPLIANT (A0-4-2) + // codeql::autosar_deviation_next_line(a-0-4-2-deviation) + long double d5; // COMPLIANT[DEVIATED] + long double d6; // NON_COMPLIANT (A0-4-2) + + // codeql::autosar_deviation_begin(a-0-4-2-deviation) + long double d7; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d8; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d9; // COMPLIANT[DEVIATED] + // codeql::autosar_deviation_end(a-0-4-2-deviation) + long double d10; // NON_COMPLIANT (A0-4-2) + // codeql::autosar_deviation_begin(a-0-4-2-deviation) + long double d11; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d12; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d13; // COMPLIANT[DEVIATED] + // codeql::autosar_deviation_end(a-0-4-2-deviation) + long double d14; // NON_COMPLIANT (A0-4-2) + getX(); // NON_COMPLIANT (A0-1-2) + + // clang-format off + long double d15; /* NON_COMPLIANT*/ /* codeql::autosar_deviation_begin(a-0-4-2-deviation) */ long double d16; // COMPLIANT[DEVIATED] + long double d17; /* COMPLIANT[DEVIATED] */ /* codeql::autosar_deviation_end(a-0-4-2-deviation) */ long double d18; // NON_COMPLIANT + // clang-format on return 0; } \ No newline at end of file diff --git a/cpp/common/test/deviations/invalid_deviations/InvalidDeviationCodeIdentifier.expected b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationCodeIdentifier.expected new file mode 100644 index 0000000000..1d7153bafd --- /dev/null +++ b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationCodeIdentifier.expected @@ -0,0 +1,13 @@ +| invalidcodeidentifiers.cpp:1:1:1:45 | // codeql::misra_deviation(x) - invalid, no x | Deviation marker does not match an expected format, or references an unknown code identifier. | +| invalidcodeidentifiers.cpp:2:1:2:47 | // codeql::autosar_deviation(x) - invalid, no x | Deviation marker does not match an expected format, or references an unknown code identifier. | +| invalidcodeidentifiers.cpp:3:1:3:44 | // codeql::cert_deviation(x) - invalid, no x | Deviation marker does not match an expected format, or references an unknown code identifier. | +| invalidcodeidentifiers.cpp:4:1:4:71 | // codeql::misra_deviation_next(a-0-4-2-deviation) - invalid, next_line | Deviation marker does not match an expected format, or references an unknown code identifier. | +| invalidcodeidentifiers.cpp:5:1:5:73 | // codeql::autosar_deviation_next(a-0-4-2-deviation) - invalid, next_line | Deviation marker does not match an expected format, or references an unknown code identifier. | +| invalidcodeidentifiers.cpp:6:1:6:70 | // codeql::cert_deviation_next(a-0-4-2-deviation) - invalid, next_line | Deviation marker does not match an expected format, or references an unknown code identifier. | +| invalidcodeidentifiers.cpp:14:1:14:74 | // codeql::misra_deviation_end(a-0-4-2-deviation) - invalid, unmatched end | Deviation end block is unmatched. | +| invalidcodeidentifiers.cpp:15:1:15:76 | // codeql::autosar_deviation_end(a-0-4-2-deviation) - invalid, unmatched end | Deviation end block is unmatched. | +| invalidcodeidentifiers.cpp:16:1:16:73 | // codeql::cert_deviation_end(a-0-4-2-deviation) - invalid, unmatched end | Deviation end block is unmatched. | +| invalidcodeidentifiers.cpp:17:1:17:78 | // codeql::misra_deviation_begin(a-0-4-2-deviation) - invalid, unmatched begin | Deviation start block is unmatched. | +| invalidcodeidentifiers.cpp:18:1:18:80 | // codeql::autosar_deviation_begin(a-0-4-2-deviation) - invalid, unmatched begin | Deviation start block is unmatched. | +| invalidcodeidentifiers.cpp:19:1:19:77 | // codeql::cert_deviation_begin(a-0-4-2-deviation) - invalid, unmatched begin | Deviation start block is unmatched. | +| invalidcodeidentifiers.cpp:21:3:21:25 | misra_deviation | Deviation attribute references unknown code identifier x. | diff --git a/cpp/common/test/deviations/invalid_deviations/InvalidDeviationCodeIdentifier.qlref b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationCodeIdentifier.qlref new file mode 100644 index 0000000000..c70989966f --- /dev/null +++ b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationCodeIdentifier.qlref @@ -0,0 +1 @@ +codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.ql \ No newline at end of file diff --git a/cpp/common/test/deviations/invalid_deviations/InvalidDeviationPermits.expected b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationPermits.expected index 433dc8a342..4378fdf11d 100644 --- a/cpp/common/test/deviations/invalid_deviations/InvalidDeviationPermits.expected +++ b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationPermits.expected @@ -1,2 +1,2 @@ -| coding-standards.xml:100:7:103:33 | deviation-permits-entry | deviations/invalid_deviations/coding-standards.xml: Deviation permit does not specify a permit identifier. | -| coding-standards.xml:104:7:107:33 | deviation-permits-entry | deviations/invalid_deviations/coding-standards.xml: Deviation permit specifies unknown property `invalid-property`. | +| coding-standards.xml:105:7:108:33 | deviation-permits-entry | coding-standards.xml: Deviation permit does not specify a permit identifier. | +| coding-standards.xml:109:7:112:33 | deviation-permits-entry | coding-standards.xml: Deviation permit specifies unknown property `invalid-property`. | diff --git a/cpp/common/test/deviations/invalid_deviations/InvalidDeviationRecords.expected b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationRecords.expected index c4f66eeaf5..2cd438c5c6 100644 --- a/cpp/common/test/deviations/invalid_deviations/InvalidDeviationRecords.expected +++ b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationRecords.expected @@ -1,14 +1,14 @@ -| coding-standards.xml:5:7:5:27 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: No rule-id and query-id specified for this deviation record. | -| coding-standards.xml:6:7:8:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: The rule-id `bad rule id` for this deviation matches none of the available queries. | -| coding-standards.xml:9:7:11:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: A query-id of `bad rule id` is specified for this deviation, but not rule-id is specified. | -| coding-standards.xml:15:7:17:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: A query-id of `cpp/autosar/useless-assignment` is specified for this deviation, but not rule-id is specified. | -| coding-standards.xml:22:7:26:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: A deviation `raised-by` is specified without providing an `approved-by`. | -| coding-standards.xml:22:7:26:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: A deviation `raised-by` is specified without providing both a `name` and `date`. | -| coding-standards.xml:27:7:33:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: A deviation `raised-by` is specified without providing an `approved-by`. | -| coding-standards.xml:27:7:33:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: A deviation `raised-by` is specified without providing both a `name` and `date`. | -| coding-standards.xml:34:7:41:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: A deviation `raised-by` is specified without providing an `approved-by`. | -| coding-standards.xml:42:7:50:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: A deviation `approved-by` is specified without providing both a `name` and `date`. | -| coding-standards.xml:51:7:61:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: A deviation `approved-by` is specified without providing both a `name` and `date`. | -| coding-standards.xml:74:7:78:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: There is no deviation permit with id `non-existing-permit`. | -| coding-standards.xml:79:7:81:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: No rule-id and query-id specified for this deviation record. | -| coding-standards.xml:85:7:88:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: The deviation is applied to a query with the rule category 'mandatory' that does not permit a deviation. | +| coding-standards.xml:5:7:5:27 | deviations-entry | coding-standards.xml: No rule-id and query-id specified for this deviation record. | +| coding-standards.xml:6:7:8:26 | deviations-entry | coding-standards.xml: The rule-id `bad rule id` for this deviation matches none of the available queries. | +| coding-standards.xml:9:7:11:26 | deviations-entry | coding-standards.xml: A query-id of `bad rule id` is specified for this deviation, but not rule-id is specified. | +| coding-standards.xml:15:7:17:26 | deviations-entry | coding-standards.xml: A query-id of `cpp/autosar/useless-assignment` is specified for this deviation, but not rule-id is specified. | +| coding-standards.xml:22:7:26:26 | deviations-entry | coding-standards.xml: A deviation `raised-by` is specified without providing an `approved-by`. | +| coding-standards.xml:22:7:26:26 | deviations-entry | coding-standards.xml: A deviation `raised-by` is specified without providing both a `name` and `date`. | +| coding-standards.xml:27:7:33:26 | deviations-entry | coding-standards.xml: A deviation `raised-by` is specified without providing an `approved-by`. | +| coding-standards.xml:27:7:33:26 | deviations-entry | coding-standards.xml: A deviation `raised-by` is specified without providing both a `name` and `date`. | +| coding-standards.xml:34:7:41:26 | deviations-entry | coding-standards.xml: A deviation `raised-by` is specified without providing an `approved-by`. | +| coding-standards.xml:42:7:50:26 | deviations-entry | coding-standards.xml: A deviation `approved-by` is specified without providing both a `name` and `date`. | +| coding-standards.xml:51:7:61:26 | deviations-entry | coding-standards.xml: A deviation `approved-by` is specified without providing both a `name` and `date`. | +| coding-standards.xml:74:7:78:26 | deviations-entry | coding-standards.xml: There is no deviation permit with id `non-existing-permit`. | +| coding-standards.xml:79:7:81:26 | deviations-entry | coding-standards.xml: No rule-id and query-id specified for this deviation record. | +| coding-standards.xml:85:7:88:26 | deviations-entry | coding-standards.xml: The deviation is applied to a query with the rule category 'mandatory' that does not permit a deviation. | diff --git a/cpp/common/test/deviations/invalid_deviations/coding-standards.xml b/cpp/common/test/deviations/invalid_deviations/coding-standards.xml index 179227a13d..ff0d69eaec 100644 --- a/cpp/common/test/deviations/invalid_deviations/coding-standards.xml +++ b/cpp/common/test/deviations/invalid_deviations/coding-standards.xml @@ -83,8 +83,13 @@ DP2 - RULE-13-6 - c/misra/sizeof-operand-with-side-effect + RULE-9-1 + c/misra/object-with-auto-storage-duration-read-before-init + + + A0-4-2 + long double is required for interaction with third-party libraries. + a-0-4-2-deviation diff --git a/cpp/common/test/deviations/invalid_deviations/coding-standards.yml b/cpp/common/test/deviations/invalid_deviations/coding-standards.yml index 7b12c7a8c2..ceea31c460 100644 --- a/cpp/common/test/deviations/invalid_deviations/coding-standards.yml +++ b/cpp/common/test/deviations/invalid_deviations/coding-standards.yml @@ -44,8 +44,11 @@ deviations: permit-id: non-existing-permit - permit-id: DP1 - permit-id: DP2 - - rule-id: RULE-13-6 - query-id: c/misra/sizeof-operand-with-side-effect + - rule-id: RULE-9-1 + query-id: c/misra/object-with-auto-storage-duration-read-before-init + - rule-id: A0-4-2 + justification: long double is required for interaction with third-party libraries. + code-identifier: a-0-4-2-deviation deviation-permits: - permit-id: DP1 justification: foo bar baz diff --git a/cpp/common/test/deviations/invalid_deviations/dummy.cpp b/cpp/common/test/deviations/invalid_deviations/dummy.cpp deleted file mode 100644 index 4a3cb36e40..0000000000 --- a/cpp/common/test/deviations/invalid_deviations/dummy.cpp +++ /dev/null @@ -1 +0,0 @@ -// Deliberately blank \ No newline at end of file diff --git a/cpp/common/test/deviations/invalid_deviations/invalidcodeidentifiers.cpp b/cpp/common/test/deviations/invalid_deviations/invalidcodeidentifiers.cpp new file mode 100644 index 0000000000..a4da098dcb --- /dev/null +++ b/cpp/common/test/deviations/invalid_deviations/invalidcodeidentifiers.cpp @@ -0,0 +1,24 @@ +// codeql::misra_deviation(x) - invalid, no x +// codeql::autosar_deviation(x) - invalid, no x +// codeql::cert_deviation(x) - invalid, no x +// codeql::misra_deviation_next(a-0-4-2-deviation) - invalid, next_line +// codeql::autosar_deviation_next(a-0-4-2-deviation) - invalid, next_line +// codeql::cert_deviation_next(a-0-4-2-deviation) - invalid, next_line + +// codeql::misra_deviation_begin(a-0-4-2-deviation) +// codeql::autosar_deviation_begin(a-0-4-2-deviation) +// codeql::cert_deviation_begin(a-0-4-2-deviation) +// codeql::misra_deviation_end(a-0-4-2-deviation) +// codeql::autosar_deviation_end(a-0-4-2-deviation) +// codeql::cert_deviation_end(a-0-4-2-deviation) +// codeql::misra_deviation_end(a-0-4-2-deviation) - invalid, unmatched end +// codeql::autosar_deviation_end(a-0-4-2-deviation) - invalid, unmatched end +// codeql::cert_deviation_end(a-0-4-2-deviation) - invalid, unmatched end +// codeql::misra_deviation_begin(a-0-4-2-deviation) - invalid, unmatched begin +// codeql::autosar_deviation_begin(a-0-4-2-deviation) - invalid, unmatched begin +// codeql::cert_deviation_begin(a-0-4-2-deviation) - invalid, unmatched begin + +[[codeql::misra_deviation("x")]] // invalid +void test() {} + +[[codeql::autosar_deviation("a-0-4-2-deviation")]] void test2() {} diff --git a/cpp/common/test/guideline_recategorizations/DisappliedQuery.ql b/cpp/common/test/guideline_recategorizations/DisappliedQuery.ql index 0254eca9bd..aa2caa8ad2 100644 --- a/cpp/common/test/guideline_recategorizations/DisappliedQuery.ql +++ b/cpp/common/test/guideline_recategorizations/DisappliedQuery.ql @@ -10,14 +10,14 @@ import cpp import codingstandards.cpp.CodingStandards -import codingstandards.cpp.TypeUses +import codingstandards.cpp.types.Uses import codingstandards.cpp.exclusions.cpp.RuleMetadata from UserType ut, string reason where isExcluded(ut, DeadCodePackage::unusedTypeDeclarationsQuery(), reason) and exists(ut.getFile()) and - not ut instanceof TemplateParameter and + not ut instanceof TypeTemplateParameter and not ut instanceof ProxyClass and not exists(getATypeUse(ut)) and not ut.isFromUninstantiatedTemplate(_) diff --git a/cpp/common/test/guideline_recategorizations/InvalidGuidelineRecategorizations.expected b/cpp/common/test/guideline_recategorizations/InvalidGuidelineRecategorizations.expected index 971c70a9b6..6d9c892eba 100644 --- a/cpp/common/test/guideline_recategorizations/InvalidGuidelineRecategorizations.expected +++ b/cpp/common/test/guideline_recategorizations/InvalidGuidelineRecategorizations.expected @@ -1,5 +1,5 @@ -| invalid/coding-standards.xml:5:7:8:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Invalid recategorization from 'required' to 'advisory'.' for rule A0-1-1. | -| invalid/coding-standards.xml:9:7:12:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Invalid recategorization from 'required' to 'disapplied'.' for rule A0-1-2. | -| invalid/coding-standards.xml:13:7:16:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Unknown rule id 'A1-4-3'.' for rule A1-4-3. | -| invalid/coding-standards.xml:17:7:20:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Invalid recategorization from 'mandatory' to 'required'.' for rule RULE-13-6. | -| invalid/coding-standards.xml:21:7:24:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Invalid recategorization from 'rule' to 'required'.' for rule CON50-CPP. | +| invalid/coding-standards.xml:5:7:8:43 | guideline-recategorizations-entry | invalid/coding-standards.xml: 'Invalid recategorization from 'required' to 'advisory'.' for rule A0-1-1. | +| invalid/coding-standards.xml:9:7:12:43 | guideline-recategorizations-entry | invalid/coding-standards.xml: 'Invalid recategorization from 'required' to 'disapplied'.' for rule A0-1-2. | +| invalid/coding-standards.xml:13:7:16:43 | guideline-recategorizations-entry | invalid/coding-standards.xml: 'Unknown rule id 'A1-4-3'.' for rule A1-4-3. | +| invalid/coding-standards.xml:17:7:20:43 | guideline-recategorizations-entry | invalid/coding-standards.xml: 'Invalid recategorization from 'mandatory' to 'required'.' for rule RULE-9-1. | +| invalid/coding-standards.xml:21:7:24:43 | guideline-recategorizations-entry | invalid/coding-standards.xml: 'Invalid recategorization from 'rule' to 'required'.' for rule CON50-CPP. | \ No newline at end of file diff --git a/cpp/common/test/guideline_recategorizations/ListGuidelineRecategorizations.expected b/cpp/common/test/guideline_recategorizations/ListGuidelineRecategorizations.expected index 0a8aeb9ba1..8e6a397620 100644 --- a/cpp/common/test/guideline_recategorizations/ListGuidelineRecategorizations.expected +++ b/cpp/common/test/guideline_recategorizations/ListGuidelineRecategorizations.expected @@ -5,4 +5,4 @@ | A10-4-1 | advisory | required | | A11-0-1 | advisory | mandatory | | CON50-CPP | rule | required | -| RULE-13-6 | mandatory | required | +| RULE-9-1 | mandatory | required | diff --git a/cpp/common/test/guideline_recategorizations/invalid/coding-standards.xml b/cpp/common/test/guideline_recategorizations/invalid/coding-standards.xml index d89f27050b..dfb7b6f13c 100644 --- a/cpp/common/test/guideline_recategorizations/invalid/coding-standards.xml +++ b/cpp/common/test/guideline_recategorizations/invalid/coding-standards.xml @@ -15,7 +15,7 @@ mandatory - RULE-13-6 + RULE-9-1 required diff --git a/cpp/common/test/guideline_recategorizations/invalid/coding-standards.yml b/cpp/common/test/guideline_recategorizations/invalid/coding-standards.yml index 89e562c05c..cd6abbf120 100644 --- a/cpp/common/test/guideline_recategorizations/invalid/coding-standards.yml +++ b/cpp/common/test/guideline_recategorizations/invalid/coding-standards.yml @@ -5,7 +5,7 @@ guideline-recategorizations: category: "disapplied" - rule-id: "A1-4-3" category: "mandatory" - - rule-id: "RULE-13-6" + - rule-id: "RULE-9-1" category: "required" - rule-id: "CON50-CPP" category: "required" diff --git a/cpp/common/test/includes/custom-library/custom_abort.h b/cpp/common/test/includes/custom-library/custom_abort.h new file mode 100644 index 0000000000..bab19a8e80 --- /dev/null +++ b/cpp/common/test/includes/custom-library/custom_abort.h @@ -0,0 +1,3 @@ +// Used for RULE-18-5-2 for library aborts +#include +#define LIBRARY_ABORT() std::abort() \ No newline at end of file diff --git a/cpp/common/test/includes/custom-library/gtest/gtest-internal.h b/cpp/common/test/includes/custom-library/gtest/gtest-internal.h new file mode 100644 index 0000000000..31d47b714f --- /dev/null +++ b/cpp/common/test/includes/custom-library/gtest/gtest-internal.h @@ -0,0 +1,29 @@ +#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ + +#define GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + test_suite_name##_##test_name##_Test + +#define GTEST_TEST_(test_suite_name, test_name, parent_class) \ + class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + : public parent_class { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() = default; \ + ~GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() override = default; \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + (const GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) &) = delete; \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) & operator=( \ + const GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name) &) = delete; /* NOLINT */ \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \ + (GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) &&) noexcept = delete; \ + GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) & operator=( \ + GTEST_TEST_CLASS_NAME_(test_suite_name, \ + test_name) &&) noexcept = delete; /* NOLINT */ \ + \ + private: \ + void TestBody() override; \ + }; \ + void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody() \ + +#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ diff --git a/cpp/common/test/includes/custom-library/gtest/gtest.h b/cpp/common/test/includes/custom-library/gtest/gtest.h new file mode 100644 index 0000000000..65fce9fc5a --- /dev/null +++ b/cpp/common/test/includes/custom-library/gtest/gtest.h @@ -0,0 +1,28 @@ +#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_H_ +#define GOOGLETEST_INCLUDE_GTEST_GTEST_H_ + +#include "gtest/gtest-internal.h" + +namespace testing { + +class Test +{ + public: + virtual ~Test(); + protected: + // Creates a Test object. + Test(); + private: + virtual void TestBody() = 0; + Test(const Test&) = delete; + Test& operator=(const Test&) = delete; +}; + +#define GTEST_TEST(test_suite_name, test_name) \ + GTEST_TEST_(test_suite_name, test_name, ::testing::Test) + +#define TEST(test_suite_name, test_name) GTEST_TEST(test_suite_name, test_name) + +} // namespace testing + +#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_H_ diff --git a/cpp/common/test/includes/standard-library/array b/cpp/common/test/includes/standard-library/array index ca4d3291ad..9465ccba97 100644 --- a/cpp/common/test/includes/standard-library/array +++ b/cpp/common/test/includes/standard-library/array @@ -8,8 +8,8 @@ namespace std { template struct array { typedef T &reference; typedef const T &const_reference; - typedef std::iterator iterator; - typedef std::iterator const_iterator; + typedef __iterator iterator; + typedef __iterator const_iterator; typedef size_t size_type; typedef ptrdiff_t difference_type; diff --git a/cpp/common/test/includes/standard-library/assert.h b/cpp/common/test/includes/standard-library/assert.h index e69de29bb2..e8ba88d635 100644 --- a/cpp/common/test/includes/standard-library/assert.h +++ b/cpp/common/test/includes/standard-library/assert.h @@ -0,0 +1,6 @@ +#ifndef _GHLIBCPP_ASSERT +#define _GHLIBCPP_ASSERT + +#define assert(x) (void)0 + +#endif // _GHLIBCPP_ASSERT \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cassert b/cpp/common/test/includes/standard-library/cassert index e69de29bb2..0477057664 100644 --- a/cpp/common/test/includes/standard-library/cassert +++ b/cpp/common/test/includes/standard-library/cassert @@ -0,0 +1 @@ +#include "assert.h" \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cctype b/cpp/common/test/includes/standard-library/cctype index 98e0805cfd..b45830acbe 100644 --- a/cpp/common/test/includes/standard-library/cctype +++ b/cpp/common/test/includes/standard-library/cctype @@ -1 +1,20 @@ -#include "ctype.h" \ No newline at end of file +#ifndef _GHLIBCPP_CCTYPE +#define _GHLIBCPP_CCTYPE +#include "ctype.h" +namespace std { +using ::isalnum; +using ::isalpha; +using ::isblank; +using ::iscntrl; +using ::isdigit; +using ::isgraph; +using ::islower; +using ::isprint; +using ::ispunct; +using ::isspace; +using ::isupper; +using ::isxdigit; +using ::tolower; +using ::toupper; +} // namespace std +#endif // _GHLIBCPP_CCTYPE diff --git a/cpp/common/test/includes/standard-library/cinttypes b/cpp/common/test/includes/standard-library/cinttypes index 8adb84dd2f..e9f7d45144 100644 --- a/cpp/common/test/includes/standard-library/cinttypes +++ b/cpp/common/test/includes/standard-library/cinttypes @@ -1 +1,12 @@ -#include \ No newline at end of file +#ifndef _GHLIBCPP_CINTTYPES +#define _GHLIBCPP_CINTTYPES +#include "inttypes.h" + +namespace std { +using ::strtoimax; +using ::strtoumax; +using ::wcstoimax; +using ::wcstoumax; +} // namespace std + +#endif // _GHLIBCPP_CINTTYPES \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/clocale b/cpp/common/test/includes/standard-library/clocale index 430c36daa0..8ec16234b8 100644 --- a/cpp/common/test/includes/standard-library/clocale +++ b/cpp/common/test/includes/standard-library/clocale @@ -1,4 +1,5 @@ -#pragma once +#ifndef _GHLIBCPP_CLOCALE +#define _GHLIBCPP_CLOCALE #define NULL 0 #define LC_ALL 0 @@ -15,3 +16,5 @@ using ::lconv; using ::localeconv; using ::setlocale; } // namespace std + +#endif // _GHLIBCPP_CLOCALE \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cmath b/cpp/common/test/includes/standard-library/cmath index e69de29bb2..9f3fffda8d 100644 --- a/cpp/common/test/includes/standard-library/cmath +++ b/cpp/common/test/includes/standard-library/cmath @@ -0,0 +1,19 @@ +namespace std { +#include + +int isinf(float x); +int isinf(double x); +int isinf(long double x); +bool isfinite(float x); +bool isfinite(double x); +bool isfinite(long double x); +bool isnan(float x); +bool isnan(double x); +bool isnan(long double x); +bool isnormal(float x); +bool isnormal(double x); +bool isnormal(long double x); +int fpclassify(float x); +int fpclassify(double x); +int fpclassify(long double x); +} \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/csetjmp b/cpp/common/test/includes/standard-library/csetjmp index e69de29bb2..c1f7ceed39 100644 --- a/cpp/common/test/includes/standard-library/csetjmp +++ b/cpp/common/test/includes/standard-library/csetjmp @@ -0,0 +1,12 @@ +#ifndef _GHLIBCPP_CSETJMP +#define _GHLIBCPP_CSETJMP + +#include "setjmp.h" + +// C++ std namespace declarations +namespace std { +using ::jmp_buf; +using ::longjmp; +} // namespace std + +#endif // _GHLIBCPP_CSETJMP \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cstdarg b/cpp/common/test/includes/standard-library/cstdarg index f2b84242a0..6dd883b683 100644 --- a/cpp/common/test/includes/standard-library/cstdarg +++ b/cpp/common/test/includes/standard-library/cstdarg @@ -1,9 +1,9 @@ #pragma once +#ifndef _GHLIBCPP_CSTDARG +#define _GHLIBCPP_CSTDARG +#include "stdarg.h" namespace std { - typedef __builtin_va_list va_list; +using ::va_list; } // namespace std - -#define va_arg(v, p) __builtin_va_arg(v, p) -#define va_end(v) __builtin_va_end(v) -#define va_start(v,l) __builtin_va_start(v,l) \ No newline at end of file +#endif // _GHLIBCPP_CSTDARG \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cstdint b/cpp/common/test/includes/standard-library/cstdint index fedf405ddb..cbaffaa8d0 100644 --- a/cpp/common/test/includes/standard-library/cstdint +++ b/cpp/common/test/includes/standard-library/cstdint @@ -1,6 +1,23 @@ -#ifndef _CPP_CSTDINT -#define _CPP_CSTDINT +#ifndef _GHLIBCPP_CSTDINT +#define _GHLIBCPP_CSTDINT +#include "stdint.h" +namespace std { +using ::int16_t; +using ::int32_t; +using ::int64_t; +using ::int8_t; +using ::intmax_t; +using ::uint16_t; +using ::uint32_t; +using ::uint64_t; +using ::uint8_t; +using ::uint_fast16_t; +using ::uint_fast32_t; +using ::uint_fast64_t; +using ::uint_fast8_t; +using ::uintmax_t; -#define MAX_INT -#include -#endif \ No newline at end of file +using ::intptr_t; +using ::uintptr_t; +} // namespace std +#endif // _GHLIBCPP_CSTDINT \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cstdint.h b/cpp/common/test/includes/standard-library/cstdint.h deleted file mode 100644 index 6a691637ff..0000000000 --- a/cpp/common/test/includes/standard-library/cstdint.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _GHLIBCPP_CSTDINT -#define _GHLIBCPP_CSTDINT -namespace std { -typedef signed char int8_t; -typedef unsigned char uint8_t; -typedef signed short int int16_t; -typedef unsigned short int uint16_t; -typedef signed int int32_t; -typedef unsigned int uint32_t; -typedef signed long int int64_t; -typedef unsigned long int uint64_t; -typedef int intmax_t; - -typedef uint8_t uint_fast8_t; -typedef uint16_t uint_fast16_t; -typedef uint32_t uint_fast32_t; -typedef uint64_t uint_fast64_t; -} // namespace std -#endif // _GHLIBCPP_CSTDINT \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cstdlib b/cpp/common/test/includes/standard-library/cstdlib index 23eab7eaca..3b1eefc4a9 100644 --- a/cpp/common/test/includes/standard-library/cstdlib +++ b/cpp/common/test/includes/standard-library/cstdlib @@ -1 +1,27 @@ -#include "cstdlib.h" \ No newline at end of file +#ifndef _GHLIBCPP_CSTDLIB +#define _GHLIBCPP_CSTDLIB +#include "stdlib.h" +namespace std { +using ::_Exit; +using ::abort; +using ::at_quick_exit; +using ::atexit; +using ::atof; +using ::atoi; +using ::atol; +using ::atoll; +using ::exit; +using ::free; +using ::malloc; +using ::quick_exit; +using ::rand; +using ::strtod; +using ::strtof; +using ::strtol; +using ::strtold; +using ::strtoll; +using ::strtoul; +using ::strtoull; +using ::system; +} // namespace std +#endif // _GHLIBCPP_CSTDLIB \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cstdlib.h b/cpp/common/test/includes/standard-library/cstdlib.h deleted file mode 100644 index 4a2d0cd9ee..0000000000 --- a/cpp/common/test/includes/standard-library/cstdlib.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _GHLIBCPP_CSTDLIB -#define _GHLIBCPP_CSTDLIB -#include "stdlib.h" -namespace std { -[[noreturn]] void _Exit(int status) noexcept; -[[noreturn]] void abort(void) noexcept; -[[noreturn]] void quick_exit(int status) noexcept; -extern "C++" int atexit(void (*f)(void)) noexcept; -extern "C++" int at_quick_exit(void (*f)(void)) noexcept; -using ::atof; -using ::atoi; -using ::atol; -using ::atoll; -using ::rand; -} // namespace std -#endif // _GHLIBCPP_CSTDLIB \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cstring b/cpp/common/test/includes/standard-library/cstring index 105e3e4693..1df2276077 100644 --- a/cpp/common/test/includes/standard-library/cstring +++ b/cpp/common/test/includes/standard-library/cstring @@ -1 +1,30 @@ -#include "cstring.h" \ No newline at end of file +#ifndef _GHLIBCPP_CSTRING +#define _GHLIBCPP_CSTRING + +#include + +namespace std { +using ::memcmp; +using ::memcpy; +using ::memmove; +using ::memset; +using ::size_t; +using ::strcat; +using ::strchr; +using ::strcmp; +using ::strcoll; +using ::strcpy; +using ::strcspn; +using ::strerror; +using ::strlen; +using ::strncat; +using ::strncmp; +using ::strncpy; +using ::strpbrk; +using ::strrchr; +using ::strspn; +using ::strstr; +using ::strtok; +using ::strxfrm; +} // namespace std +#endif // _GHLIBCPP_CSTRING \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cstring.h b/cpp/common/test/includes/standard-library/cstring.h deleted file mode 100644 index 2f3ffd393e..0000000000 --- a/cpp/common/test/includes/standard-library/cstring.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _GHLIBCPP_CSTRING -#define _GHLIBCPP_CSTRING - -#include - -namespace std { -using ::memcmp; -using ::memcpy; -using ::memmove; -using ::memset; -using ::size_t; -using ::strcat; -using ::strchr; -using ::strcmp; -using ::strcoll; -using ::strcpy; -using ::strcspn; -using ::strlen; -using ::strncat; -using ::strncmp; -using ::strncpy; -using ::strpbrk; -using ::strrchr; -using ::strspn; -using ::strstr; -using ::strtok; -using ::strxfrm; -} // namespace std -#endif // _GHLIBCPP_CSTRING diff --git a/cpp/common/test/includes/standard-library/ctime b/cpp/common/test/includes/standard-library/ctime index f99aab4fb3..9448e0615e 100644 --- a/cpp/common/test/includes/standard-library/ctime +++ b/cpp/common/test/includes/standard-library/ctime @@ -1,39 +1,17 @@ #ifndef _GHLIBCPP_CTIME #define _GHLIBCPP_CTIME - -namespace std -{ - typedef unsigned long clock_t; - typedef unsigned long time_t; - - typedef unsigned long size_t; - struct tm - { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; - }; - - - clock_t clock (void); - double difftime (clock_t end, clock_t beginning); - time_t mktime (struct tm * timeptr); - time_t time (time_t* timer); - char* asctime (const struct tm * timeptr); - - char* ctime (const time_t * timer); - struct tm * gmtime (const time_t * timer); - struct tm * localtime (const time_t * timer); - size_t strftime (char* ptr, size_t maxsize, const char* format, - const struct tm* timeptr ); - -} - - -#endif \ No newline at end of file +#include +namespace std { +using ::clock_t; +using ::clock; +using ::time_t; +using ::time; +using ::tm; +using ::difftime; +using ::asctime; +using ::ctime; +using ::localtime; +using ::gmtime; +using ::mktime; +} // namespace std +#endif // _GHLIBCPP_CTIME \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/ctype.h b/cpp/common/test/includes/standard-library/ctype.h index e9264fd7c6..d7dc851529 100644 --- a/cpp/common/test/includes/standard-library/ctype.h +++ b/cpp/common/test/includes/standard-library/ctype.h @@ -1,8 +1,9 @@ #ifndef _GHLIBCPP_CTYPE #define _GHLIBCPP_CTYPE -namespace std { + extern int isalnum(int); extern int isalpha(int); +extern int isblank(int); extern int iscntrl(int); extern int isdigit(int); extern int islower(int); @@ -14,5 +15,5 @@ extern int isupper(int); extern int isxdigit(int); extern int tolower(int); extern int toupper(int); -} // namespace std + #endif // _GHLIBCPP_CTYPE \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cwchar b/cpp/common/test/includes/standard-library/cwchar index e69de29bb2..bd85a9f507 100644 --- a/cpp/common/test/includes/standard-library/cwchar +++ b/cpp/common/test/includes/standard-library/cwchar @@ -0,0 +1,21 @@ +#ifndef _GHLIBCPP_CWCHAR +#define _GHLIBCPP_CWCHAR +#include "wchar.h" + +namespace std { +using ::fgetwc; +using ::fputwc; +using ::wcstod; +using ::wcstof; +using ::wcstol; +using ::wcstold; +using ::wcstoll; +using ::wcstoul; +using ::wcstoull; + +using ::mbstate_t; +using ::WEOF; +using ::wint_t; +} // namespace std + +#endif // _GHLIBCPP_CWCHAR \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cwctype b/cpp/common/test/includes/standard-library/cwctype index e69de29bb2..d2ce5c7e36 100644 --- a/cpp/common/test/includes/standard-library/cwctype +++ b/cpp/common/test/includes/standard-library/cwctype @@ -0,0 +1,38 @@ +#ifndef _GHLIBCPP_CWCTYPE +#define _GHLIBCPP_CWCTYPE +#include "wctype.h" + +namespace std { +// Types +using ::wint_t; +using ::wctype_t; +using ::wctrans_t; + +// Wide character classification functions +using ::iswalnum; +using ::iswalpha; +using ::iswblank; +using ::iswcntrl; +using ::iswdigit; +using ::iswgraph; +using ::iswlower; +using ::iswprint; +using ::iswpunct; +using ::iswspace; +using ::iswupper; +using ::iswxdigit; + +// Wide character conversion functions +using ::towlower; +using ::towupper; + +// Generic wide character classification functions +using ::iswctype; +using ::wctype; + +// Generic wide character mapping functions +using ::towctrans; +using ::wctrans; +} // namespace std + +#endif // _GHLIBCPP_CWCTYPE \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/inttypes.h b/cpp/common/test/includes/standard-library/inttypes.h index d613ea4dcc..2f32726a05 100644 --- a/cpp/common/test/includes/standard-library/inttypes.h +++ b/cpp/common/test/includes/standard-library/inttypes.h @@ -1,11 +1,12 @@ -#pragma once +#ifndef _GHLIBCPP_INTTYPES +#define _GHLIBCPP_INTTYPES +#include -typedef signed char int8_t; -typedef signed short int int16_t; -typedef signed long int int32_t; -typedef signed long long int int64_t; +// String conversion functions +intmax_t strtoimax(const char *str, char **endptr, int base); +uintmax_t strtoumax(const char *str, char **endptr, int base); -typedef unsigned char uint8_t; -typedef unsigned short int uint16_t; -typedef unsigned long int uint32_t; -typedef unsigned long long int uint64_t; \ No newline at end of file +// Wide character versions +intmax_t wcstoimax(const wchar_t *str, wchar_t **endptr, int base); +uintmax_t wcstoumax(const wchar_t *str, wchar_t **endptr, int base); +#endif // _GHLIBCPP_INTTYPES \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/ios.h b/cpp/common/test/includes/standard-library/ios.h index 1a78db28aa..08d32a6c36 100644 --- a/cpp/common/test/includes/standard-library/ios.h +++ b/cpp/common/test/includes/standard-library/ios.h @@ -5,6 +5,9 @@ namespace std { typedef size_t streamsize; typedef int pos_type; +typedef long long streamoff; +typedef pos_type streampos; +typedef pos_type wstreampos; // Bitmask type as specified by [bitmask.types] // Operators omitted as not required for our test cases @@ -67,5 +70,8 @@ template class basic_ios : public std::ios_base { ios_base &hex(ios_base &str); +std::ios_base &boolalpha(std::ios_base &str); +std::ios_base &noboolalpha(std::ios_base &str); + } // namespace std #endif // _GHLIBCPP_IOS \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/locale b/cpp/common/test/includes/standard-library/locale new file mode 100644 index 0000000000..755c5f6ee1 --- /dev/null +++ b/cpp/common/test/includes/standard-library/locale @@ -0,0 +1,61 @@ + +#ifndef _GHLIBCPP_LOCALE +#define _GHLIBCPP_LOCALE + +#include + +namespace std { + +class locale { +public: + class facet; + class id; + typedef int category; + + static const category none = 0, collate = 0x010, ctype = 0x020, + monetary = 0x040, numeric = 0x080, time = 0x100, + messages = 0x200, + all = collate | ctype | monetary | numeric | time | + messages; + + locale() noexcept; + locale(const locale &other) noexcept; + explicit locale(const char *std_name); + explicit locale(const string &std_name); + locale(const locale &other, const char *std_name, category); + locale(const locale &other, const string &std_name, category); + template locale(const locale &other, Facet *f); + locale(const locale &other, const locale &one, category); + ~locale(); + const locale &operator=(const locale &other) noexcept; + template locale combine(const locale &other) const; + + basic_string name() const; + + bool operator==(const locale &other) const; + bool operator!=(const locale &other) const; + template + bool operator()(const basic_string &s1, + const basic_string &s2) const; + + static locale global(const locale &); + static const locale &classic(); +}; + +template bool isspace(charT c, const locale &loc); +template bool isprint(charT c, const locale &loc); +template bool iscntrl(charT c, const locale &loc); +template bool isupper(charT c, const locale &loc); +template bool islower(charT c, const locale &loc); +template bool isalpha(charT c, const locale &loc); +template bool isdigit(charT c, const locale &loc); +template bool ispunct(charT c, const locale &loc); +template bool isxdigit(charT c, const locale &loc); +template bool isalnum(charT c, const locale &loc); +template bool isgraph(charT c, const locale &loc); +template bool isblank(charT c, const locale &loc); +template charT toupper(charT c, const locale &loc); +template charT tolower(charT c, const locale &loc); +} // namespace std + +#endif // _GHLIBCPP_LOCALE \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/locale.h b/cpp/common/test/includes/standard-library/locale.h index 346c4eeef5..2501c9c5d5 100644 --- a/cpp/common/test/includes/standard-library/locale.h +++ b/cpp/common/test/includes/standard-library/locale.h @@ -1,8 +1,37 @@ -#ifndef _GHLIBCPP_LOCALE -#define _GHLIBCPP_LOCALE +#ifndef _GHLIBCPP_LOCALE_H +#define _GHLIBCPP_LOCALE_H + +#define LC_ALL 6 + +struct lconv { + char *decimal_point; + char *thousands_sep; + char *grouping; + + char *int_curr_symbol; + char *currency_symbol; + char *mon_decimal_point; + char *mon_thousands_sep; + char *mon_grouping; + char *positive_sign; + char *negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; + char int_p_cs_precedes; + char int_p_sep_by_space; + char int_n_cs_precedes; + char int_n_sep_by_space; + char int_p_sign_posn; + char int_n_sign_posn; +}; -struct lconv; char *setlocale(int, const char *); -lconv *localeconv(); +struct lconv *localeconv(void); -#endif // _GHLIBCPP_LOCALE \ No newline at end of file +#endif // _GHLIBCPP_LOCALE_H \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/math.h b/cpp/common/test/includes/standard-library/math.h index 460c0a9c2f..7ff0ef8357 100644 --- a/cpp/common/test/includes/standard-library/math.h +++ b/cpp/common/test/includes/standard-library/math.h @@ -17,6 +17,9 @@ long double acoshl(long double x); double atanh(double x); float atanhf(float x); long double atanhl(long double x); +float cos(float x); +double cos(double x); +long double cos(long double x); double fmod(double x, double y); float fmodf(float x, float y); long double fmodl(long double x, long double y); @@ -47,6 +50,9 @@ long double logbl(long double x); double pow(double x, double y); float powf(float x, float y); long double powl(long double x, long double y); +float sin(float x); +double sin(double x); +long double sin(long double x); double sqrt(double x); float sqrtf(float x); long double sqrtl(long double x); diff --git a/cpp/common/test/includes/standard-library/memory.h b/cpp/common/test/includes/standard-library/memory.h index 985ee41602..494f428422 100644 --- a/cpp/common/test/includes/standard-library/memory.h +++ b/cpp/common/test/includes/standard-library/memory.h @@ -23,6 +23,7 @@ class unique_ptr { unique_ptr(T *ptr) {} unique_ptr(const unique_ptr &t) = delete; unique_ptr(unique_ptr &&t) {} + unique_ptr(pointer p, Deleter d) noexcept {} ~unique_ptr() {} T &operator*() const { return *ptr; } T *operator->() const noexcept { return ptr; } @@ -93,8 +94,10 @@ template class shared_ptr : public __shared_ptr { shared_ptr(T *ptr); shared_ptr(const shared_ptr &r) noexcept; template shared_ptr(const shared_ptr &r) noexcept; + template shared_ptr(const shared_ptr &r, T *p) noexcept; shared_ptr(shared_ptr &&r) noexcept; template shared_ptr(shared_ptr &&r) noexcept; + template shared_ptr(T *p, D d); shared_ptr(unique_ptr &&t) {} ~shared_ptr() {} T &operator*() const noexcept; diff --git a/cpp/common/test/includes/standard-library/mutex.h b/cpp/common/test/includes/standard-library/mutex.h index 4c49819ddd..d21042dcf7 100644 --- a/cpp/common/test/includes/standard-library/mutex.h +++ b/cpp/common/test/includes/standard-library/mutex.h @@ -1,6 +1,6 @@ #ifndef _GHLIBCPP_MUTEX #define _GHLIBCPP_MUTEX -#include "chrono.h" +#include namespace std { @@ -77,6 +77,14 @@ template class lock_guard { mutex_type &_m; }; +template class scoped_lock { +public: + explicit scoped_lock(MutexTypes &...m); + scoped_lock(const scoped_lock &) = delete; + scoped_lock &operator=(const scoped_lock &) = delete; + ~scoped_lock(); +}; + } // namespace std #endif // _GHLIBCPP_MUTEX diff --git a/cpp/common/test/includes/standard-library/optional b/cpp/common/test/includes/standard-library/optional new file mode 100644 index 0000000000..8b129a36cb --- /dev/null +++ b/cpp/common/test/includes/standard-library/optional @@ -0,0 +1,165 @@ +#ifndef _GHLIBCPP_OPTIONAL +#define _GHLIBCPP_OPTIONAL + +#include "initializer_list" +#include "stddef.h" + +namespace std { + +// Forward declarations and helper types +struct in_place_t { + explicit in_place_t() = default; +}; +constexpr in_place_t in_place{}; + +// Type trait helper +template struct decay { + typedef T type; +}; + +// nullopt_t type and nullopt constant +struct nullopt_t { + explicit constexpr nullopt_t(int) {} +}; +constexpr nullopt_t nullopt{0}; + +// bad_optional_access exception +class bad_optional_access {}; + +// optional template class +template class optional { +public: + typedef T value_type; + + // Constructors + constexpr optional() noexcept; + constexpr optional(nullopt_t) noexcept; + constexpr optional(const optional &other); + constexpr optional(optional &&other) noexcept; + template constexpr explicit optional(const optional &other); + template constexpr explicit optional(optional &&other); + template + constexpr explicit optional(in_place_t, Args &&...args); + template + constexpr explicit optional(in_place_t, initializer_list ilist, + Args &&...args); + template constexpr explicit optional(U &&value); + + // Destructor + ~optional(); + + // Assignment operators + optional &operator=(nullopt_t) noexcept; + constexpr optional &operator=(const optional &other); + constexpr optional &operator=(optional &&other) noexcept; + template optional &operator=(U &&value); + template optional &operator=(const optional &other); + template optional &operator=(optional &&other); + + // Observers + constexpr const T *operator->() const; + constexpr T *operator->(); + constexpr const T &operator*() const &; + constexpr T &operator*() &; + constexpr const T &&operator*() const &&; + constexpr T &&operator*() &&; + constexpr explicit operator bool() const noexcept; + constexpr bool has_value() const noexcept; + constexpr const T &value() const &; + constexpr T &value() &; + constexpr const T &&value() const &&; + constexpr T &&value() &&; + template constexpr T value_or(U &&default_value) const &; + template constexpr T value_or(U &&default_value) &&; + + // Modifiers + void swap(optional &other) noexcept; + void reset() noexcept; + template T &emplace(Args &&...args); + template + T &emplace(initializer_list ilist, Args &&...args); +}; + +// Deduction guides +template optional(T) -> optional; + +// Comparison operators +template +constexpr bool operator==(const optional &lhs, const optional &rhs); +template +constexpr bool operator!=(const optional &lhs, const optional &rhs); +template +constexpr bool operator<(const optional &lhs, const optional &rhs); +template +constexpr bool operator<=(const optional &lhs, const optional &rhs); +template +constexpr bool operator>(const optional &lhs, const optional &rhs); +template +constexpr bool operator>=(const optional &lhs, const optional &rhs); + +// Comparison with nullopt +template +constexpr bool operator==(const optional &opt, nullopt_t) noexcept; +template +constexpr bool operator==(nullopt_t, const optional &opt) noexcept; +template +constexpr bool operator!=(const optional &opt, nullopt_t) noexcept; +template +constexpr bool operator!=(nullopt_t, const optional &opt) noexcept; +template +constexpr bool operator<(const optional &opt, nullopt_t) noexcept; +template +constexpr bool operator<(nullopt_t, const optional &opt) noexcept; +template +constexpr bool operator<=(const optional &opt, nullopt_t) noexcept; +template +constexpr bool operator<=(nullopt_t, const optional &opt) noexcept; +template +constexpr bool operator>(const optional &opt, nullopt_t) noexcept; +template +constexpr bool operator>(nullopt_t, const optional &opt) noexcept; +template +constexpr bool operator>=(const optional &opt, nullopt_t) noexcept; +template +constexpr bool operator>=(nullopt_t, const optional &opt) noexcept; + +// Comparison with T +template +constexpr bool operator==(const optional &opt, const U &value); +template +constexpr bool operator==(const T &value, const optional &opt); +template +constexpr bool operator!=(const optional &opt, const U &value); +template +constexpr bool operator!=(const T &value, const optional &opt); +template +constexpr bool operator<(const optional &opt, const U &value); +template +constexpr bool operator<(const T &value, const optional &opt); +template +constexpr bool operator<=(const optional &opt, const U &value); +template +constexpr bool operator<=(const T &value, const optional &opt); +template +constexpr bool operator>(const optional &opt, const U &value); +template +constexpr bool operator>(const T &value, const optional &opt); +template +constexpr bool operator>=(const optional &opt, const U &value); +template +constexpr bool operator>=(const T &value, const optional &opt); + +// Specialized algorithms +template void swap(optional &lhs, optional &rhs) noexcept; + +// Factory functions +template +constexpr optional::type> make_optional(T &&value); +template +constexpr optional make_optional(Args &&...args); +template +constexpr optional make_optional(initializer_list ilist, Args &&...args); + +} // namespace std + +#endif // _GHLIBCPP_OPTIONAL \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/ostream.h b/cpp/common/test/includes/standard-library/ostream.h index 9f2c6d9069..23117a93d2 100644 --- a/cpp/common/test/includes/standard-library/ostream.h +++ b/cpp/common/test/includes/standard-library/ostream.h @@ -10,6 +10,18 @@ class basic_ostream : virtual public basic_ios { typedef charT char_type; basic_ostream &operator<<(int n); + basic_ostream &operator<<(bool n); + basic_ostream &operator<<(short n); + basic_ostream &operator<<(unsigned short n); + basic_ostream &operator<<(unsigned int n); + basic_ostream &operator<<(long n); + basic_ostream &operator<<(unsigned long n); + basic_ostream &operator<<(long long n); + basic_ostream &operator<<(unsigned long long n); + basic_ostream &operator<<(float f); + basic_ostream &operator<<(double f); + basic_ostream &operator<<(long double f); + basic_ostream &operator<<(const void *p); basic_ostream &put(char_type c); basic_ostream &write(const char_type *s, streamsize n); @@ -25,6 +37,20 @@ template basic_ostream &operator<<( basic_ostream &, basic_ostream &(*func)(basic_ostream &)); + +template +basic_ostream & +operator<<(basic_ostream &, + std::ios_base &(*func)(std::ios_base &)); +template +basic_ostream &operator<<( + basic_ostream &, + std::basic_ios &(*func)(std::basic_ios &)); + +template +basic_ostream &operator<<(basic_ostream &os, + const void *p); + template basic_ostream &endl(basic_ostream &); diff --git a/cpp/common/test/includes/standard-library/random.h b/cpp/common/test/includes/standard-library/random.h index 1a2b341226..141b806b62 100644 --- a/cpp/common/test/includes/standard-library/random.h +++ b/cpp/common/test/includes/standard-library/random.h @@ -1,7 +1,7 @@ #ifndef _GHLIBCPP_RANDOM #define _GHLIBCPP_RANDOM -#include "cstdint.h" #include "stddef.h" +#include #include namespace std { diff --git a/cpp/common/test/includes/standard-library/setjmp.h b/cpp/common/test/includes/standard-library/setjmp.h index bb7e4fdc27..3d9ac27eb5 100644 --- a/cpp/common/test/includes/standard-library/setjmp.h +++ b/cpp/common/test/includes/standard-library/setjmp.h @@ -1,14 +1,12 @@ #ifndef _GHLIBCPP_SETJMP #define _GHLIBCPP_SETJMP - -struct __jmp_buf_tag - { - int x; - }; +struct __jmp_buf_tag { + int x; +}; typedef struct __jmp_buf_tag jmp_buf[1]; -void longjmp (struct __jmp_buf_tag __env[1], int __val); -#define setjmp(env) 0 +[[noreturn]] void longjmp(struct __jmp_buf_tag __env[1], int __val); +#define setjmp(env) 0 #endif diff --git a/cpp/common/test/includes/standard-library/stdarg.h b/cpp/common/test/includes/standard-library/stdarg.h index e69de29bb2..cab940168a 100644 --- a/cpp/common/test/includes/standard-library/stdarg.h +++ b/cpp/common/test/includes/standard-library/stdarg.h @@ -0,0 +1,6 @@ + +typedef __builtin_va_list va_list; +#define va_arg(v, p) __builtin_va_arg(v, p) +#define va_end(v) __builtin_va_end(v) +#define va_start(v, l) __builtin_va_start(v, l) +#define va_copy(d, s) __builtin_va_copy(d, s) \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/stddef.h b/cpp/common/test/includes/standard-library/stddef.h index 496de53167..96e9849973 100644 --- a/cpp/common/test/includes/standard-library/stddef.h +++ b/cpp/common/test/includes/standard-library/stddef.h @@ -17,5 +17,11 @@ using size_t = decltype(sizeof(char)); #define offsetof(t, d) __builtin_offsetof(t, d) /*implementation-defined*/ +#ifdef __cplusplus +#define NULL 0L +#else +#define NULL ((void*)0) +#endif + // namespace std #endif // _GHLIBCPP_STDDEF \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/stdint.h b/cpp/common/test/includes/standard-library/stdint.h index e69de29bb2..75827a8068 100644 --- a/cpp/common/test/includes/standard-library/stdint.h +++ b/cpp/common/test/includes/standard-library/stdint.h @@ -0,0 +1,23 @@ +#ifndef _GHLIBCPP_STDINT +#define _GHLIBCPP_STDINT + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed short int int16_t; +typedef unsigned short int uint16_t; +typedef signed int int32_t; +typedef unsigned int uint32_t; +typedef signed long int int64_t; +typedef unsigned long int uint64_t; +typedef int intmax_t; +typedef unsigned int uintmax_t; + +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +typedef long intptr_t; +typedef unsigned long uintptr_t; + +#endif // _GHLIBCPP_STDINT \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/stdlib.h b/cpp/common/test/includes/standard-library/stdlib.h index c8ff7a7592..eb73db0627 100644 --- a/cpp/common/test/includes/standard-library/stdlib.h +++ b/cpp/common/test/includes/standard-library/stdlib.h @@ -8,18 +8,32 @@ void free(void *ptr); void *malloc(size_t size); void *realloc(void *ptr, size_t size); -void abort(); +[[noreturn]] void _Exit(int status) noexcept; +[[noreturn]] void abort(void) noexcept; +[[noreturn]] void quick_exit(int status) noexcept; +extern "C++" int atexit(void (*f)(void)) noexcept; +extern "C++" int at_quick_exit(void (*f)(void)) noexcept; void exit(int code); int system(const char *command); char *getenv(const char *name); +int setenv(const char *, const char *, int); + int atoi(const char *str); long int atol(const char *str); long long int atoll(const char *str); double atof(const char *str); +long int strtol(const char *str, char **endptr, int base); +long long int strtoll(const char *str, char **endptr, int base); +unsigned long int strtoul(const char *str, char **endptr, int base); +unsigned long long int strtoull(const char *str, char **endptr, int base); +double strtod(const char *str, char **endptr); +float strtof(const char *str, char **endptr); +long double strtold(const char *str, char **endptr); + int rand(void); #endif // _GHLIBCPP_STDLIB \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/string b/cpp/common/test/includes/standard-library/string index a3f22f5e80..cb76a7742d 100644 --- a/cpp/common/test/includes/standard-library/string +++ b/cpp/common/test/includes/standard-library/string @@ -1,12 +1,92 @@ #ifndef _GHLIBCPP_STRING #define _GHLIBCPP_STRING +#include "cwchar" #include "initializer_list" +#include "ios.h" #include "iosfwd.h" #include "iterator.h" #include "stddef.h" namespace std { -template struct char_traits; +template struct char_traits { + typedef charT char_type; + typedef int int_type; + typedef streamoff off_type; + typedef streampos pos_type; + typedef mbstate_t state_type; + + static void assign(char_type &c1, const char_type &c2); + static bool eq(const char_type &c1, const char_type &c2); + static bool lt(const char_type &c1, const char_type &c2); + + static int compare(const char_type *s1, const char_type *s2, size_t n); + static size_t length(const char_type *s); + static const char_type *find(const char_type *s, size_t n, + const char_type &a); + static char_type *move(char_type *s1, const char_type *s2, size_t n); + static char_type *copy(char_type *s1, const char_type *s2, size_t n); + static char_type *assign(char_type *s, size_t n, char_type a); + + static int_type not_eof(const int_type &c); + static char_type to_char_type(const int_type &c); + static int_type to_int_type(const char_type &c); + static bool eq_int_type(const int_type &c1, const int_type &c2); + static int_type eof(); +}; + +// Specialization for char +template <> struct char_traits { + typedef char char_type; + typedef int int_type; + typedef streamoff off_type; + typedef streampos pos_type; + typedef mbstate_t state_type; + + static void assign(char_type &c1, const char_type &c2); + static bool eq(const char_type &c1, const char_type &c2); + static bool lt(const char_type &c1, const char_type &c2); + + static int compare(const char_type *s1, const char_type *s2, size_t n); + static size_t length(const char_type *s); + static const char_type *find(const char_type *s, size_t n, + const char_type &a); + static char_type *move(char_type *s1, const char_type *s2, size_t n); + static char_type *copy(char_type *s1, const char_type *s2, size_t n); + static char_type *assign(char_type *s, size_t n, char_type a); + + static int_type not_eof(const int_type &c); + static char_type to_char_type(const int_type &c); + static int_type to_int_type(const char_type &c); + static bool eq_int_type(const int_type &c1, const int_type &c2); + static int_type eof(); +}; + +// Specialization for wchar_t +template <> struct char_traits { + typedef wchar_t char_type; + typedef wint_t int_type; + typedef streamoff off_type; + typedef wstreampos pos_type; + typedef mbstate_t state_type; + + static void assign(char_type &c1, const char_type &c2); + static bool eq(const char_type &c1, const char_type &c2); + static bool lt(const char_type &c1, const char_type &c2); + + static int compare(const char_type *s1, const char_type *s2, size_t n); + static size_t length(const char_type *s); + static const char_type *find(const char_type *s, size_t n, + const char_type &a); + static char_type *move(char_type *s1, const char_type *s2, size_t n); + static char_type *copy(char_type *s1, const char_type *s2, size_t n); + static char_type *assign(char_type *s, size_t n, char_type a); + + static int_type not_eof(const int_type &c); + static char_type to_char_type(const int_type &c); + static int_type to_int_type(const char_type &c); + static bool eq_int_type(const int_type &c1, const int_type &c2); + static int_type eof(); +}; template class allocator { public: @@ -114,14 +194,15 @@ public: basic_string &replace(size_type pos, size_type n1, size_type n2, charT c); basic_string &replace(__const_iterator i1, __const_iterator i2, const basic_string &str); - basic_string &replace(__const_iterator i1, __const_iterator i2, const charT *s, - size_type n); - basic_string &replace(__const_iterator i1, __const_iterator i2, const charT *s); + basic_string &replace(__const_iterator i1, __const_iterator i2, + const charT *s, size_type n); + basic_string &replace(__const_iterator i1, __const_iterator i2, + const charT *s); basic_string &replace(__const_iterator i1, __const_iterator i2, size_type n, charT c); template - basic_string &replace(__const_iterator i1, __const_iterator i2, InputIterator j1, - InputIterator j2); + basic_string &replace(__const_iterator i1, __const_iterator i2, + InputIterator j1, InputIterator j2); basic_string &replace(__const_iterator, __const_iterator, initializer_list); diff --git a/cpp/common/test/includes/standard-library/string.h b/cpp/common/test/includes/standard-library/string.h index c4d06b6e7b..b4b4d9b121 100644 --- a/cpp/common/test/includes/standard-library/string.h +++ b/cpp/common/test/includes/standard-library/string.h @@ -35,12 +35,13 @@ const char *strstr(const char *str1, const char *str2); char *strstr(char *str1, const char *str2); char *strtok(char *str, const char *delimiters); +char *strerror(int errnum); + +char *strdup(const char *); void *memcpy(void *dest, const void *src, size_t count); void *memset(void *dest, int ch, size_t count); void *memmove(void *dest, const void *src, size_t count); int memcmp(const void *lhs, const void *rhs, size_t count); -size_t strlen(const char *str); - #endif // _GHLIBCPP_STRINGH \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/string_view b/cpp/common/test/includes/standard-library/string_view new file mode 100644 index 0000000000..7897d2cf78 --- /dev/null +++ b/cpp/common/test/includes/standard-library/string_view @@ -0,0 +1,79 @@ +#pragma once +#ifndef _GHLIBCPP_STRING_VIEW +#define _GHLIBCPP_STRING_VIEW + +#include "stddef.h" + +namespace std { + +template class basic_string_view { +public: + typedef CharT value_type; + typedef const CharT *pointer; + typedef const CharT *const_pointer; + typedef const CharT &reference; + typedef const CharT &const_reference; + typedef const CharT *const_iterator; + typedef const_iterator iterator; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + // Constructors + basic_string_view() noexcept; + basic_string_view(const basic_string_view &) noexcept = default; + basic_string_view(const CharT *s, size_type count); + basic_string_view(const CharT *s); + + // Assignment + basic_string_view &operator=(const basic_string_view &) noexcept = default; + + // Element access + const_reference operator[](size_type pos) const; + const_reference at(size_type pos) const; + const_reference front() const; + const_reference back() const; + const_pointer data() const noexcept; + + // Capacity + size_type size() const noexcept; + size_type length() const noexcept; + size_type max_size() const noexcept; + bool empty() const noexcept; + + // Modifiers + void remove_prefix(size_type n); + void remove_suffix(size_type n); + void swap(basic_string_view &v) noexcept; + + // String operations + size_type copy(CharT *dest, size_type count, size_type pos = 0) const; + basic_string_view substr(size_type pos = 0, size_type len = npos) const; + + // Comparison + int compare(basic_string_view v) const noexcept; + int compare(size_type pos1, size_type n1, basic_string_view v) const; + int compare(const CharT *s) const; + + // Search + size_type find(basic_string_view v, size_type pos = 0) const noexcept; + size_type find(CharT c, size_type pos = 0) const noexcept; + size_type find(const CharT *s, size_type pos, size_type n) const; + size_type find(const CharT *s, size_type pos = 0) const; + + // Constants + static const size_type npos = static_cast(-1); + +private: + const CharT *data_; + size_type size_; +}; + +// Type aliases +typedef basic_string_view string_view; +typedef basic_string_view wstring_view; +typedef basic_string_view u16string_view; +typedef basic_string_view u32string_view; + +} // namespace std + +#endif // _GHLIBCPP_STRING_VIEW diff --git a/cpp/common/test/includes/standard-library/time.h b/cpp/common/test/includes/standard-library/time.h index e69de29bb2..cc7ff1673a 100644 --- a/cpp/common/test/includes/standard-library/time.h +++ b/cpp/common/test/includes/standard-library/time.h @@ -0,0 +1,32 @@ +#ifndef _GHLIBCPP_TIME +#define _GHLIBCPP_TIME + +typedef unsigned long clock_t; +typedef unsigned long time_t; + +typedef unsigned long size_t; +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +clock_t clock(void); +double difftime(clock_t end, clock_t beginning); +time_t mktime(struct tm *timeptr); +time_t time(time_t *timer); +char *asctime(const struct tm *timeptr); + +char *ctime(const time_t *timer); +struct tm *gmtime(const time_t *timer); +struct tm *localtime(const time_t *timer); +size_t strftime(char *ptr, size_t maxsize, const char *format, + const struct tm *timeptr); + +#endif // _GHLIBCPP_TIME \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/wchar.h b/cpp/common/test/includes/standard-library/wchar.h index e69de29bb2..055520eb2e 100644 --- a/cpp/common/test/includes/standard-library/wchar.h +++ b/cpp/common/test/includes/standard-library/wchar.h @@ -0,0 +1,29 @@ +#ifndef _GHLIBCPP_WCHAR +#define _GHLIBCPP_WCHAR + +#include "stddef.h" +#include "wctype.h" + +// Wide character I/O functions +wint_t fgetwc(void *stream); +wint_t fputwc(wchar_t wc, void *stream); + +// Wide character string conversion functions +long wcstol(const wchar_t *str, wchar_t **endptr, int base); +long long wcstoll(const wchar_t *str, wchar_t **endptr, int base); +unsigned long wcstoul(const wchar_t *str, wchar_t **endptr, int base); +unsigned long long wcstoull(const wchar_t *str, wchar_t **endptr, int base); +double wcstod(const wchar_t *str, wchar_t **endptr); +float wcstof(const wchar_t *str, wchar_t **endptr); +long double wcstold(const wchar_t *str, wchar_t **endptr); + +// Character classification and conversion types +typedef struct { + int __count; + union { + unsigned int __wch; + char __wchb[4]; + } __value; +} mbstate_t; + +#endif // _GHLIBCPP_WCHAR \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/wctype.h b/cpp/common/test/includes/standard-library/wctype.h index e69de29bb2..1fdef4ea04 100644 --- a/cpp/common/test/includes/standard-library/wctype.h +++ b/cpp/common/test/includes/standard-library/wctype.h @@ -0,0 +1,37 @@ +#ifndef _GHLIBCPP_WCTYPE +#define _GHLIBCPP_WCTYPE + +typedef long wint_t; +typedef long wctype_t; +typedef long wctrans_t; + +// Wide character classification functions +extern int iswalnum(wint_t wc); +extern int iswalpha(wint_t wc); +extern int iswblank(wint_t wc); +extern int iswcntrl(wint_t wc); +extern int iswdigit(wint_t wc); +extern int iswgraph(wint_t wc); +extern int iswlower(wint_t wc); +extern int iswprint(wint_t wc); +extern int iswpunct(wint_t wc); +extern int iswspace(wint_t wc); +extern int iswupper(wint_t wc); +extern int iswxdigit(wint_t wc); + +// Wide character conversion functions +extern wint_t towlower(wint_t wc); +extern wint_t towupper(wint_t wc); + +// Generic wide character classification functions +extern int iswctype(wint_t wc, wctype_t desc); +extern wctype_t wctype(const char *property); + +// Generic wide character mapping functions +extern wint_t towctrans(wint_t wc, wctrans_t desc); +extern wctrans_t wctrans(const char *property); + +// Wide character constants +static const wint_t WEOF = static_cast(-1); + +#endif // _GHLIBCPP_WCTYPE \ No newline at end of file diff --git a/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.expected b/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.expected new file mode 100644 index 0000000000..c273346e3b --- /dev/null +++ b/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.expected @@ -0,0 +1,7 @@ +| deduplicatemacroresults.cpp:4:8:4:9 | definition of g1 | Findme var 'g1'. | deduplicatemacroresults.cpp:4:8:4:9 | definition of g1 | | +| deduplicatemacroresults.cpp:10:1:10:34 | SOMETIMES_HAS_RESULTS1(type,name) | Invocation of macro $@ has findme var 'g3'. | deduplicatemacroresults.cpp:6:1:6:52 | #define SOMETIMES_HAS_RESULTS1(type,name) type name | SOMETIMES_HAS_RESULTS1 | +| deduplicatemacroresults.cpp:13:1:13:34 | SOMETIMES_HAS_RESULTS2(type,name) | Invocation of macro $@ has findme var 'g5'. | deduplicatemacroresults.cpp:7:1:7:53 | #define SOMETIMES_HAS_RESULTS2(type,name) type name; | SOMETIMES_HAS_RESULTS2 | +| deduplicatemacroresults.cpp:15:1:15:50 | #define ALWAYS_HAS_SAME_RESULT() extern findme g6; | Macro ALWAYS_HAS_SAME_RESULT always has findme var named g6 | deduplicatemacroresults.cpp:15:1:15:50 | #define ALWAYS_HAS_SAME_RESULT() extern findme g6; | (ignored) | +| deduplicatemacroresults.cpp:21:1:21:70 | #define ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(name) extern findme name; | Macro ALWAYS_HAS_RESULT_VARIED_DESCRIPTION always has findme var, for example '$@'. | deduplicatemacroresults.cpp:23:38:23:39 | declaration of g7 | g7 | +| deduplicatemacroresults.cpp:30:1:31:50 | #define OUTER_ALWAYS_HAS_SAME_RESULT() extern INNER_SOMETIMES_HAS_RESULTS(findme, g10); | Macro OUTER_ALWAYS_HAS_SAME_RESULT always has findme var named g10 | deduplicatemacroresults.cpp:30:1:31:50 | #define OUTER_ALWAYS_HAS_SAME_RESULT() extern INNER_SOMETIMES_HAS_RESULTS(findme, g10); | (ignored) | +| deduplicatemacroresults.cpp:37:1:38:52 | #define OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(name) INNER_SOMETIMES_HAS_RESULTS(findme, name ## suffix); | Macro OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION always has findme var, for example '$@'. | deduplicatemacroresults.cpp:40:44:40:47 | definition of g11suffix | g11suffix | diff --git a/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.ql b/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.ql new file mode 100644 index 0000000000..68cfc9a78f --- /dev/null +++ b/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.ql @@ -0,0 +1,36 @@ +import cpp +import codingstandards.cpp.alertreporting.DeduplicateMacroResults + +class FindMe extends VariableDeclarationEntry { + FindMe() { getType().toString() = "findme" } +} + +module FindMeDedupeConfig implements DeduplicateMacroConfigSig { + string describe(FindMe def) { result = def.getName() } +} + +module FindMeReportConfig implements MacroReportConfigSig { + bindingset[description] + string getMessageSameResultInAllExpansions(Macro m, string description) { + result = "Macro " + m.getName() + " always has findme var named " + description + } + + string getMessageVariedResultInAllExpansions(Macro m) { + result = "Macro " + m.getName() + " always has findme var, for example '$@'." + } + + string getMessageResultInIsolatedExpansion(FindMe f) { + result = "Invocation of macro $@ has findme var '" + f.getName() + "'." + } + + string getMessageNotInMacro(FindMe f, Locatable extra, string extraString) { + result = "Findme var '" + f.getName() + "'." and extra = f and extraString = "" + } +} + +import DeduplicateMacroResults +import DeduplicateMacroResults::Report + +from ReportResult report +select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocatable(), + report.getOptionalPlaceholderMessage() diff --git a/cpp/common/test/library/codingstandards/cpp/alertreporting/deduplicatemacroresults.cpp b/cpp/common/test/library/codingstandards/cpp/alertreporting/deduplicatemacroresults.cpp new file mode 100644 index 0000000000..d9b3659bf6 --- /dev/null +++ b/cpp/common/test/library/codingstandards/cpp/alertreporting/deduplicatemacroresults.cpp @@ -0,0 +1,53 @@ +typedef struct { +} findme; + +findme g1; // baseline report, not in a macro + +#define SOMETIMES_HAS_RESULTS1(type, name) type name // ignore +#define SOMETIMES_HAS_RESULTS2(type, name) type name; // ignore + +SOMETIMES_HAS_RESULTS1(int, g2); // ignore +SOMETIMES_HAS_RESULTS1(findme, g3); // RESULT + +SOMETIMES_HAS_RESULTS2(int, g4) // ignore +SOMETIMES_HAS_RESULTS2(findme, g5) // RESULT + +#define ALWAYS_HAS_SAME_RESULT() extern findme g6; // RESULT + +ALWAYS_HAS_SAME_RESULT() // ignore +ALWAYS_HAS_SAME_RESULT() // ignore +ALWAYS_HAS_SAME_RESULT() // ignore + +#define ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(name) extern findme name; // RESULT + +ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(g7) // ignore +ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(g8) // ignore +ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(g9) // ignore +ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(g9) // ignore +ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(g9) // ignore + +#define INNER_SOMETIMES_HAS_RESULTS(type, name) type name; // ignore +#define OUTER_ALWAYS_HAS_SAME_RESULT() \ + extern INNER_SOMETIMES_HAS_RESULTS(findme, g10); // RESULT + +OUTER_ALWAYS_HAS_SAME_RESULT() // ignore +OUTER_ALWAYS_HAS_SAME_RESULT() // ignore + +// 'name ## suffix' required to work around extractor bug. +#define OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(name) \ + INNER_SOMETIMES_HAS_RESULTS(findme, name##suffix); // RESULT + +OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(g11) // ignore +OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(g12) // ignore + +#define OUTER_OUTER_ALWAYS_HAS_SAME_RESULT() \ + OUTER_ALWAYS_HAS_SAME_RESULT(); // ignore +OUTER_OUTER_ALWAYS_HAS_SAME_RESULT() // ignore +OUTER_OUTER_ALWAYS_HAS_SAME_RESULT() // ignore + +// 'name ## suffix' required to work around extractor bug. +#define OUTER_OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(name) \ + OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(name##suffix); // ignore + +OUTER_OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(g13) // ignore +OUTER_OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(g14) // ignore \ No newline at end of file diff --git a/cpp/common/test/library/codingstandards/cpp/mainlikefunctions/typedefint/MainLikeFunction.expected b/cpp/common/test/library/codingstandards/cpp/mainlikefunctions/typedefint/MainLikeFunction.expected new file mode 100644 index 0000000000..fa98ca7648 --- /dev/null +++ b/cpp/common/test/library/codingstandards/cpp/mainlikefunctions/typedefint/MainLikeFunction.expected @@ -0,0 +1 @@ +| test.cpp:5:9:5:12 | main | diff --git a/cpp/common/test/library/codingstandards/cpp/mainlikefunctions/typedefint/MainLikeFunction.ql b/cpp/common/test/library/codingstandards/cpp/mainlikefunctions/typedefint/MainLikeFunction.ql new file mode 100644 index 0000000000..ed1757631e --- /dev/null +++ b/cpp/common/test/library/codingstandards/cpp/mainlikefunctions/typedefint/MainLikeFunction.ql @@ -0,0 +1,5 @@ +import cpp +import codingstandards.cpp.EncapsulatingFunctions + +from MainFunction m +select m diff --git a/cpp/common/test/library/codingstandards/cpp/mainlikefunctions/typedefint/test.cpp b/cpp/common/test/library/codingstandards/cpp/mainlikefunctions/typedefint/test.cpp new file mode 100644 index 0000000000..7b514505f1 --- /dev/null +++ b/cpp/common/test/library/codingstandards/cpp/mainlikefunctions/typedefint/test.cpp @@ -0,0 +1,8 @@ +typedef signed int int32_t; + +// @brief main +// @return exit code +int32_t main(void) { + int32_t ret{0}; + return ret; +} diff --git a/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected b/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected new file mode 100644 index 0000000000..90aa3b30c8 --- /dev/null +++ b/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected @@ -0,0 +1,91 @@ +| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | operator= | +| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | operator= | +| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:8:7:8:7 | operator= | +| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:8:7:8:7 | operator= | +| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:27:28:27:28 | (unnamed constructor) | +| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:27:28:27:28 | (unnamed constructor) | +| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:27:28:27:28 | operator= | +| file://:0:0:0:0 | __va_list_tag | file://:0:0:0:0 | (global namespace) | +| file://:0:0:0:0 | fp_offset | file://:0:0:0:0 | __va_list_tag | +| file://:0:0:0:0 | gp_offset | file://:0:0:0:0 | __va_list_tag | +| file://:0:0:0:0 | operator= | file://:0:0:0:0 | __va_list_tag | +| file://:0:0:0:0 | operator= | file://:0:0:0:0 | __va_list_tag | +| file://:0:0:0:0 | overflow_arg_area | file://:0:0:0:0 | __va_list_tag | +| file://:0:0:0:0 | reg_save_area | file://:0:0:0:0 | __va_list_tag | +| test.cpp:1:5:1:7 | id1 | file://:0:0:0:0 | (global namespace) | +| test.cpp:3:11:3:13 | ns1 | file://:0:0:0:0 | (global namespace) | +| test.cpp:4:5:4:7 | id1 | test.cpp:3:11:3:13 | ns1 | +| test.cpp:6:11:6:13 | ns1::ns2 | test.cpp:3:11:3:13 | ns1 | +| test.cpp:7:5:7:7 | id1 | test.cpp:6:11:6:13 | ns1::ns2 | +| test.cpp:8:7:8:7 | C1 | test.cpp:8:7:8:8 | C1 | +| test.cpp:8:7:8:7 | operator= | test.cpp:8:7:8:8 | C1 | +| test.cpp:8:7:8:7 | operator= | test.cpp:8:7:8:8 | C1 | +| test.cpp:8:7:8:8 | C1 | test.cpp:6:11:6:13 | ns1::ns2 | +| test.cpp:9:7:9:9 | id1 | test.cpp:8:7:8:8 | C1 | +| test.cpp:10:8:10:17 | test_scope | test.cpp:8:7:8:8 | C1 | +| test.cpp:10:23:10:25 | id1 | test.cpp:10:8:10:17 | test_scope | +| test.cpp:10:28:34:3 | { ... } | test.cpp:10:8:10:17 | test_scope | +| test.cpp:11:5:33:5 | for(...;...;...) ... | test.cpp:10:28:34:3 | { ... } | +| test.cpp:11:10:11:17 | declaration | test.cpp:11:5:33:5 | for(...;...;...) ... | +| test.cpp:11:14:11:16 | id1 | test.cpp:11:5:33:5 | for(...;...;...) ... | +| test.cpp:11:19:11:21 | id1 | test.cpp:10:28:34:3 | { ... } | +| test.cpp:11:19:11:25 | ... < ... | test.cpp:11:5:33:5 | for(...;...;...) ... | +| test.cpp:11:25:11:25 | 1 | test.cpp:10:28:34:3 | { ... } | +| test.cpp:11:28:11:30 | id1 | test.cpp:10:28:34:3 | { ... } | +| test.cpp:11:28:11:32 | ... ++ | test.cpp:11:5:33:5 | for(...;...;...) ... | +| test.cpp:11:35:33:5 | { ... } | test.cpp:11:5:33:5 | for(...;...;...) ... | +| test.cpp:12:7:32:7 | for(...;...;...) ... | test.cpp:11:35:33:5 | { ... } | +| test.cpp:12:12:12:19 | declaration | test.cpp:12:7:32:7 | for(...;...;...) ... | +| test.cpp:12:16:12:18 | id1 | test.cpp:12:7:32:7 | for(...;...;...) ... | +| test.cpp:12:21:12:23 | id1 | test.cpp:11:35:33:5 | { ... } | +| test.cpp:12:21:12:27 | ... < ... | test.cpp:12:7:32:7 | for(...;...;...) ... | +| test.cpp:12:27:12:27 | 1 | test.cpp:11:35:33:5 | { ... } | +| test.cpp:12:30:12:32 | id1 | test.cpp:11:35:33:5 | { ... } | +| test.cpp:12:30:12:34 | ... ++ | test.cpp:12:7:32:7 | for(...;...;...) ... | +| test.cpp:12:37:32:7 | { ... } | test.cpp:12:7:32:7 | for(...;...;...) ... | +| test.cpp:13:9:31:9 | { ... } | test.cpp:12:37:32:7 | { ... } | +| test.cpp:14:11:14:18 | declaration | test.cpp:13:9:31:9 | { ... } | +| test.cpp:14:15:14:17 | id1 | test.cpp:13:9:31:9 | { ... } | +| test.cpp:16:11:20:11 | if (...) ... | test.cpp:13:9:31:9 | { ... } | +| test.cpp:16:15:16:17 | id1 | test.cpp:13:9:31:9 | { ... } | +| test.cpp:16:15:16:22 | ... == ... | test.cpp:13:9:31:9 | { ... } | +| test.cpp:16:22:16:22 | 0 | test.cpp:13:9:31:9 | { ... } | +| test.cpp:16:25:18:11 | { ... } | test.cpp:16:11:20:11 | if (...) ... | +| test.cpp:17:13:17:20 | declaration | test.cpp:16:25:18:11 | { ... } | +| test.cpp:17:17:17:19 | id1 | test.cpp:16:25:18:11 | { ... } | +| test.cpp:18:18:20:11 | { ... } | test.cpp:16:11:20:11 | if (...) ... | +| test.cpp:19:13:19:20 | declaration | test.cpp:18:18:20:11 | { ... } | +| test.cpp:19:17:19:19 | id1 | test.cpp:18:18:20:11 | { ... } | +| test.cpp:21:11:25:11 | switch (...) ... | test.cpp:13:9:31:9 | { ... } | +| test.cpp:21:19:21:21 | id1 | test.cpp:13:9:31:9 | { ... } | +| test.cpp:21:24:25:11 | { ... } | test.cpp:21:11:25:11 | switch (...) ... | +| test.cpp:22:11:22:17 | case ...: | test.cpp:21:24:25:11 | { ... } | +| test.cpp:22:16:22:16 | 0 | test.cpp:21:24:25:11 | { ... } | +| test.cpp:23:13:23:20 | declaration | test.cpp:21:24:25:11 | { ... } | +| test.cpp:23:17:23:19 | id1 | test.cpp:21:24:25:11 | { ... } | +| test.cpp:24:13:24:18 | break; | test.cpp:21:24:25:11 | { ... } | +| test.cpp:25:11:25:11 | label ...: | test.cpp:13:9:31:9 | { ... } | +| test.cpp:26:11:28:11 | try { ... } | test.cpp:13:9:31:9 | { ... } | +| test.cpp:26:15:28:11 | { ... } | test.cpp:13:9:31:9 | { ... } | +| test.cpp:27:13:27:53 | declaration | test.cpp:26:15:28:11 | { ... } | +| test.cpp:27:18:27:24 | lambda1 | test.cpp:26:15:28:11 | { ... } | +| test.cpp:27:27:27:52 | [...](...){...} | test.cpp:26:15:28:11 | { ... } | +| test.cpp:27:27:27:52 | {...} | test.cpp:26:15:28:11 | { ... } | +| test.cpp:27:28:27:28 | (unnamed constructor) | file://:0:0:0:0 | decltype([...](...){...}) | +| test.cpp:27:28:27:28 | (unnamed constructor) | file://:0:0:0:0 | decltype([...](...){...}) | +| test.cpp:27:28:27:28 | (unnamed constructor) | file://:0:0:0:0 | decltype([...](...){...}) | +| test.cpp:27:28:27:28 | operator= | file://:0:0:0:0 | decltype([...](...){...}) | +| test.cpp:27:29:27:29 | id1 | file://:0:0:0:0 | decltype([...](...){...}) | +| test.cpp:27:29:27:31 | id1 | test.cpp:26:15:28:11 | { ... } | +| test.cpp:27:33:27:33 | operator() | test.cpp:27:13:27:53 | declaration | +| test.cpp:27:36:27:52 | { ... } | test.cpp:27:33:27:33 | operator() | +| test.cpp:27:38:27:50 | declaration | test.cpp:27:36:27:52 | { ... } | +| test.cpp:27:42:27:44 | id1 | test.cpp:27:36:27:52 | { ... } | +| test.cpp:27:47:27:49 | 10 | test.cpp:27:36:27:52 | { ... } | +| test.cpp:27:52:27:52 | return ... | test.cpp:27:36:27:52 | { ... } | +| test.cpp:28:24:28:26 | id1 | test.cpp:28:29:30:11 | | +| test.cpp:28:29:30:11 | | test.cpp:26:11:28:11 | try { ... } | +| test.cpp:28:29:30:11 | { ... } | test.cpp:13:9:31:9 | { ... } | +| test.cpp:29:13:29:20 | declaration | test.cpp:28:29:30:11 | { ... } | +| test.cpp:29:17:29:19 | id1 | test.cpp:28:29:30:11 | { ... } | +| test.cpp:34:3:34:3 | return ... | test.cpp:10:28:34:3 | { ... } | diff --git a/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.ql b/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.ql new file mode 100644 index 0000000000..47d27fb0f0 --- /dev/null +++ b/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.ql @@ -0,0 +1,5 @@ +import codingstandards.cpp.Scope + +from Element e, Element parent +where Internal::getParentScope(e) = parent +select e, parent diff --git a/cpp/common/test/library/codingstandards/cpp/scope/test.cpp b/cpp/common/test/library/codingstandards/cpp/scope/test.cpp new file mode 100644 index 0000000000..a0b617916d --- /dev/null +++ b/cpp/common/test/library/codingstandards/cpp/scope/test.cpp @@ -0,0 +1,37 @@ +int id1; + +namespace ns1 { +int id1; // COMPLIANT + +namespace ns2 { +int id1; // COMPLIANT +class C1 { + int id1; + void test_scope(int id1) { + for (int id1; id1 < 1; id1++) { + for (int id1; id1 < 1; id1++) { + { + int id1; + + if (id1 == 0) { + int id1; + } else { + int id1; + } + switch (id1) { + case 0: + int id1; + break; + } + try { + auto lambda1 = [id1]() { int id1 = 10; }; + } catch (int id1) { + int id1; + } + } + } + } + } +}; +} // namespace ns2 +} // namespace ns1 diff --git a/cpp/common/test/library/codingstandards/cpp/trivialtypes/LiteralType.ql b/cpp/common/test/library/codingstandards/cpp/trivialtypes/LiteralType.ql index 4d0f8567d0..e7a1d5ebd3 100644 --- a/cpp/common/test/library/codingstandards/cpp/trivialtypes/LiteralType.ql +++ b/cpp/common/test/library/codingstandards/cpp/trivialtypes/LiteralType.ql @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType from Type t where diff --git a/cpp/common/test/library/codingstandards/cpp/trivialtypes/TrivialType.ql b/cpp/common/test/library/codingstandards/cpp/trivialtypes/TrivialType.ql index a85fcf5676..edbfbe5303 100644 --- a/cpp/common/test/library/codingstandards/cpp/trivialtypes/TrivialType.ql +++ b/cpp/common/test/library/codingstandards/cpp/trivialtypes/TrivialType.ql @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType from Type t where diff --git a/cpp/common/test/library/codingstandards/cpp/trivialtypes/TriviallyCopyableType.ql b/cpp/common/test/library/codingstandards/cpp/trivialtypes/TriviallyCopyableType.ql index 3b3f498796..1667372f4b 100644 --- a/cpp/common/test/library/codingstandards/cpp/trivialtypes/TriviallyCopyableType.ql +++ b/cpp/common/test/library/codingstandards/cpp/trivialtypes/TriviallyCopyableType.ql @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType from TriviallyCopyableClass t select t diff --git a/cpp/common/test/options b/cpp/common/test/options new file mode 100644 index 0000000000..59fc70d386 --- /dev/null +++ b/cpp/common/test/options @@ -0,0 +1 @@ +semmle-extractor-options:--clang -std=c++17 -nostdinc++ -I../../../../common/test/includes/standard-library -I../../../../common/test/includes/custom-library \ No newline at end of file diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index a66a3fbf70..cdec8497fd 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.32.0-dev +version: 2.52.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/common/test/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.expected b/cpp/common/test/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.expected index a4e40cc6cb..7a43b3757e 100644 --- a/cpp/common/test/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.expected +++ b/cpp/common/test/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.expected @@ -2,8 +2,8 @@ problems | test.cpp:10:3:10:13 | call to expression | test.cpp:8:22:8:28 | 0 | test.cpp:10:9:10:10 | l2 | A null pointer-to-member value from $@ is passed as the second operand to a pointer-to-member expression. | test.cpp:8:22:8:28 | test.cpp:8:22:8:28 | initialization | | test.cpp:11:8:11:9 | l3 | test.cpp:9:17:9:23 | 0 | test.cpp:11:8:11:9 | l3 | A null pointer-to-member value from $@ is passed as the second operand to a pointer-to-member expression. | test.cpp:9:17:9:23 | test.cpp:9:17:9:23 | initialization | edges -| test.cpp:8:22:8:28 | 0 | test.cpp:10:9:10:10 | l2 | -| test.cpp:9:17:9:23 | 0 | test.cpp:11:8:11:9 | l3 | +| test.cpp:8:22:8:28 | 0 | test.cpp:10:9:10:10 | l2 | provenance | | +| test.cpp:9:17:9:23 | 0 | test.cpp:11:8:11:9 | l3 | provenance | | nodes | test.cpp:8:22:8:28 | 0 | semmle.label | 0 | | test.cpp:9:17:9:23 | 0 | semmle.label | 0 | diff --git a/cpp/autosar/test/rules/M5-3-3/UnaryOperatorOverloaded.expected b/cpp/common/test/rules/addressofoperatoroverloaded/AddressOfOperatorOverloaded.expected similarity index 100% rename from cpp/autosar/test/rules/M5-3-3/UnaryOperatorOverloaded.expected rename to cpp/common/test/rules/addressofoperatoroverloaded/AddressOfOperatorOverloaded.expected diff --git a/cpp/common/test/rules/addressofoperatoroverloaded/AddressOfOperatorOverloaded.ql b/cpp/common/test/rules/addressofoperatoroverloaded/AddressOfOperatorOverloaded.ql new file mode 100644 index 0000000000..ee8ba0d5d5 --- /dev/null +++ b/cpp/common/test/rules/addressofoperatoroverloaded/AddressOfOperatorOverloaded.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.addressofoperatoroverloaded.AddressOfOperatorOverloaded + +class TestFileQuery extends AddressOfOperatorOverloadedSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/M5-3-3/test.cpp b/cpp/common/test/rules/addressofoperatoroverloaded/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M5-3-3/test.cpp rename to cpp/common/test/rules/addressofoperatoroverloaded/test.cpp diff --git a/cpp/common/test/rules/amixedusemacroargumentsubjecttoexpansion/AMixedUseMacroArgumentSubjectToExpansion.expected b/cpp/common/test/rules/amixedusemacroargumentsubjecttoexpansion/AMixedUseMacroArgumentSubjectToExpansion.expected new file mode 100644 index 0000000000..71355bf4cc --- /dev/null +++ b/cpp/common/test/rules/amixedusemacroargumentsubjecttoexpansion/AMixedUseMacroArgumentSubjectToExpansion.expected @@ -0,0 +1,2 @@ +| test.cpp:5:1:5:41 | #define BAD_MACRO_WITH_ARG(x) (x) + wow ## x | Macro BAD_MACRO_WITH_ARG contains use of parameter x used in multiple contexts. | +| test.cpp:6:1:6:48 | #define BAD_MACRO_WITH_ARG_TWO(x,y) (x) + wow ## x | Macro BAD_MACRO_WITH_ARG_TWO contains use of parameter x used in multiple contexts. | diff --git a/cpp/common/test/rules/amixedusemacroargumentsubjecttoexpansion/AMixedUseMacroArgumentSubjectToExpansion.ql b/cpp/common/test/rules/amixedusemacroargumentsubjecttoexpansion/AMixedUseMacroArgumentSubjectToExpansion.ql new file mode 100644 index 0000000000..5aa514e86d --- /dev/null +++ b/cpp/common/test/rules/amixedusemacroargumentsubjecttoexpansion/AMixedUseMacroArgumentSubjectToExpansion.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.amixedusemacroargumentsubjecttoexpansion.AMixedUseMacroArgumentSubjectToExpansion + +class TestFileQuery extends AMixedUseMacroArgumentSubjectToExpansionSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/amixedusemacroargumentsubjecttoexpansion/test.cpp b/cpp/common/test/rules/amixedusemacroargumentsubjecttoexpansion/test.cpp new file mode 100644 index 0000000000..e96e2f7414 --- /dev/null +++ b/cpp/common/test/rules/amixedusemacroargumentsubjecttoexpansion/test.cpp @@ -0,0 +1,26 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +#define GOOD_MACRO_WITH_ARG(X) ((X)*X##_scale) // COMPLIANT +#define MACRO 1 +#define BAD_MACRO_WITH_ARG(x) (x) + wow##x // NON_COMPLIANT +#define BAD_MACRO_WITH_ARG_TWO(x, y) (x) + wow##x // NON_COMPLIANT +#define MACROONE(x) #x // COMPLIANT +#define MACROTWO(x) x *x // COMPLIANT +#define MACROTHREE(x) "##\"\"'" + (x) // COMPLIANT +#define FOO(x) #x MACROONE(x) // COMPLIANT - no further arg expansion + +void f() { + + int x; + int x_scale; + int y; + int wowMACRO = 0; + + y = GOOD_MACRO_WITH_ARG(x); + wowMACRO = BAD_MACRO_WITH_ARG(MACRO); + wowMACRO = BAD_MACRO_WITH_ARG_TWO(MACRO, 1); + char s[] = MACROONE(MACRO); + y = MACROTWO(MACRO); + MACROTHREE(MACRO); + FOO(x); +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-2-12/IdentifierWithArrayTypePassedAsFunctionArgumentDecayToAPointer.expected b/cpp/common/test/rules/arraypassedasfunctionargumentdecaytoapointer/ArrayPassedAsFunctionArgumentDecayToAPointer.expected similarity index 100% rename from cpp/autosar/test/rules/M5-2-12/IdentifierWithArrayTypePassedAsFunctionArgumentDecayToAPointer.expected rename to cpp/common/test/rules/arraypassedasfunctionargumentdecaytoapointer/ArrayPassedAsFunctionArgumentDecayToAPointer.expected diff --git a/cpp/common/test/rules/arraypassedasfunctionargumentdecaytoapointer/ArrayPassedAsFunctionArgumentDecayToAPointer.ql b/cpp/common/test/rules/arraypassedasfunctionargumentdecaytoapointer/ArrayPassedAsFunctionArgumentDecayToAPointer.ql new file mode 100644 index 0000000000..929e5affdf --- /dev/null +++ b/cpp/common/test/rules/arraypassedasfunctionargumentdecaytoapointer/ArrayPassedAsFunctionArgumentDecayToAPointer.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.arraypassedasfunctionargumentdecaytoapointer.ArrayPassedAsFunctionArgumentDecayToAPointer + +class TestFileQuery extends ArrayPassedAsFunctionArgumentDecayToAPointerSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/M5-2-12/test.cpp b/cpp/common/test/rules/arraypassedasfunctionargumentdecaytoapointer/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M5-2-12/test.cpp rename to cpp/common/test/rules/arraypassedasfunctionargumentdecaytoapointer/test.cpp diff --git a/cpp/autosar/test/rules/A7-4-1/AsmDeclarationUsed.expected b/cpp/common/test/rules/asmdeclarationused/AsmDeclarationUsed.expected similarity index 100% rename from cpp/autosar/test/rules/A7-4-1/AsmDeclarationUsed.expected rename to cpp/common/test/rules/asmdeclarationused/AsmDeclarationUsed.expected diff --git a/cpp/common/test/rules/asmdeclarationused/AsmDeclarationUsed.ql b/cpp/common/test/rules/asmdeclarationused/AsmDeclarationUsed.ql new file mode 100644 index 0000000000..5e60570f5a --- /dev/null +++ b/cpp/common/test/rules/asmdeclarationused/AsmDeclarationUsed.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.asmdeclarationused.AsmDeclarationUsed + +class TestFileQuery extends AsmDeclarationUsedSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/A7-4-1/test.cpp b/cpp/common/test/rules/asmdeclarationused/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A7-4-1/test.cpp rename to cpp/common/test/rules/asmdeclarationused/test.cpp diff --git a/cpp/common/test/rules/atofatoiatolandatollused/AtofAtoiAtolAndAtollUsed.expected b/cpp/common/test/rules/atofatoiatolandatollused/AtofAtoiAtolAndAtollUsed.expected new file mode 100644 index 0000000000..9a849af3f4 --- /dev/null +++ b/cpp/common/test/rules/atofatoiatolandatollused/AtofAtoiAtolAndAtollUsed.expected @@ -0,0 +1,4 @@ +| test.cpp:8:14:8:17 | call to atof | Call to banned function atof. | +| test.cpp:9:12:9:15 | call to atoi | Call to banned function atoi. | +| test.cpp:10:13:10:16 | call to atol | Call to banned function atol. | +| test.cpp:11:18:11:22 | call to atoll | Call to banned function atoll. | diff --git a/cpp/common/test/rules/atofatoiatolandatollused/AtofAtoiAtolAndAtollUsed.ql b/cpp/common/test/rules/atofatoiatolandatollused/AtofAtoiAtolAndAtollUsed.ql new file mode 100644 index 0000000000..6da5fe6097 --- /dev/null +++ b/cpp/common/test/rules/atofatoiatolandatollused/AtofAtoiAtolAndAtollUsed.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.atofatoiatolandatollused.AtofAtoiAtolAndAtollUsed + +class TestFileQuery extends AtofAtoiAtolAndAtollUsedSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/atofatoiatolandatollused/test.cpp b/cpp/common/test/rules/atofatoiatolandatollused/test.cpp new file mode 100644 index 0000000000..c995df6aad --- /dev/null +++ b/cpp/common/test/rules/atofatoiatolandatollused/test.cpp @@ -0,0 +1,13 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +#include +#include +void f2(); +void f1() { + char l1[5] = "abcd"; + float l2 = atof(l1); // NON_COMLIANT + int l3 = atoi(l1); // NON_COMPLIANT + long l4 = atol(l1); // NON_COMPLIANT + long long l5 = atoll(l1); // NON_COMPLIANT + f2(); // COMPLIANT +} diff --git a/cpp/autosar/test/rules/A2-13-1/EscapeSequenceOutsideISO.expected b/cpp/common/test/rules/backslashcharactermisuse/BackslashCharacterMisuse.expected similarity index 100% rename from cpp/autosar/test/rules/A2-13-1/EscapeSequenceOutsideISO.expected rename to cpp/common/test/rules/backslashcharactermisuse/BackslashCharacterMisuse.expected diff --git a/cpp/common/test/rules/backslashcharactermisuse/BackslashCharacterMisuse.ql b/cpp/common/test/rules/backslashcharactermisuse/BackslashCharacterMisuse.ql new file mode 100644 index 0000000000..aa32fa3096 --- /dev/null +++ b/cpp/common/test/rules/backslashcharactermisuse/BackslashCharacterMisuse.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.backslashcharactermisuse.BackslashCharacterMisuse + +class TestFileQuery extends BackslashCharacterMisuseSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/A2-13-1/test.cpp b/cpp/common/test/rules/backslashcharactermisuse/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A2-13-1/test.cpp rename to cpp/common/test/rules/backslashcharactermisuse/test.cpp diff --git a/cpp/common/test/rules/bitfieldshallhaveanappropriatetype/BitFieldShallHaveAnAppropriateType.expected b/cpp/common/test/rules/bitfieldshallhaveanappropriatetype/BitFieldShallHaveAnAppropriateType.expected new file mode 100644 index 0000000000..346a557e32 --- /dev/null +++ b/cpp/common/test/rules/bitfieldshallhaveanappropriatetype/BitFieldShallHaveAnAppropriateType.expected @@ -0,0 +1,4 @@ +| test.cpp:9:7:9:8 | x1 | Bit-field 'x1' is declared on type 'int'. | +| test.cpp:13:15:13:16 | x5 | Bit-field 'x5' is declared on type 'signed long'. | +| test.cpp:15:15:15:16 | x6 | Bit-field 'x6' is declared on type 'signed char'. | +| test.cpp:17:14:17:15 | x7 | Bit-field 'x7' is declared on type 'Color'. | diff --git a/cpp/common/test/rules/bitfieldshallhaveanappropriatetype/BitFieldShallHaveAnAppropriateType.ql b/cpp/common/test/rules/bitfieldshallhaveanappropriatetype/BitFieldShallHaveAnAppropriateType.ql new file mode 100644 index 0000000000..a3e1ecc76c --- /dev/null +++ b/cpp/common/test/rules/bitfieldshallhaveanappropriatetype/BitFieldShallHaveAnAppropriateType.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.bitfieldshallhaveanappropriatetype.BitFieldShallHaveAnAppropriateType + +class TestFileQuery extends BitFieldShallHaveAnAppropriateTypeSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/bitfieldshallhaveanappropriatetype/test.cpp b/cpp/common/test/rules/bitfieldshallhaveanappropriatetype/test.cpp new file mode 100644 index 0000000000..96b28997c4 --- /dev/null +++ b/cpp/common/test/rules/bitfieldshallhaveanappropriatetype/test.cpp @@ -0,0 +1,18 @@ + +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +typedef unsigned int UINT16; + +enum Color { R, G, B }; + +struct SampleStruct { + int x1 : 2; // NON_COMPLIANT - not explicitly signed or unsigned + unsigned int x2 : 2; // COMPLIANT - explicitly unsigned + signed int x3 : 2; // COMPLIANT - explicitly signed + UINT16 x4 : 2; // COMPLIANT - type alias resolves to a compliant type + signed long x5 : 2; // NON_COMPLIANT - cannot declare bit field for long, even + // if it's signed + signed char x6 : 2; // NON_COMPLIANT - cannot declare bit field for char, even + // if it's signed + enum Color x7 : 3; // NON_COMPLIANT - cannot declare bit field for enum +} sample_struct; diff --git a/cpp/autosar/test/rules/M5-3-2/UnaryMinusOperatorAppliedToAnExpressionWhoseUnderlyingTypeIsUnsigned.expected b/cpp/common/test/rules/builtinunaryoperatorappliedtounsignedexpression/BuiltInUnaryOperatorAppliedToUnsignedExpression.expected similarity index 100% rename from cpp/autosar/test/rules/M5-3-2/UnaryMinusOperatorAppliedToAnExpressionWhoseUnderlyingTypeIsUnsigned.expected rename to cpp/common/test/rules/builtinunaryoperatorappliedtounsignedexpression/BuiltInUnaryOperatorAppliedToUnsignedExpression.expected diff --git a/cpp/common/test/rules/builtinunaryoperatorappliedtounsignedexpression/BuiltInUnaryOperatorAppliedToUnsignedExpression.ql b/cpp/common/test/rules/builtinunaryoperatorappliedtounsignedexpression/BuiltInUnaryOperatorAppliedToUnsignedExpression.ql new file mode 100644 index 0000000000..3f5110e299 --- /dev/null +++ b/cpp/common/test/rules/builtinunaryoperatorappliedtounsignedexpression/BuiltInUnaryOperatorAppliedToUnsignedExpression.ql @@ -0,0 +1,5 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.builtinunaryoperatorappliedtounsignedexpression.BuiltInUnaryOperatorAppliedToUnsignedExpression + +class TestFileQuery extends BuiltInUnaryOperatorAppliedToUnsignedExpressionSharedQuery, TestQuery { +} diff --git a/cpp/autosar/test/rules/M5-3-2/test.cpp b/cpp/common/test/rules/builtinunaryoperatorappliedtounsignedexpression/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M5-3-2/test.cpp rename to cpp/common/test/rules/builtinunaryoperatorappliedtounsignedexpression/test.cpp diff --git a/cpp/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected b/cpp/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected new file mode 100644 index 0000000000..886d03ddac --- /dev/null +++ b/cpp/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected @@ -0,0 +1,2 @@ +| test.cpp:11:9:11:9 | (int32_t)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.cpp:12:41:12:41 | (signed int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | diff --git a/cpp/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.ql b/cpp/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.ql new file mode 100644 index 0000000000..2a1e49774f --- /dev/null +++ b/cpp/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.castcharbeforeconvertingtolargersizes.CastCharBeforeConvertingToLargerSizes + +class TestFileQuery extends CastCharBeforeConvertingToLargerSizesSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/castcharbeforeconvertingtolargersizes/test.cpp b/cpp/common/test/rules/castcharbeforeconvertingtolargersizes/test.cpp new file mode 100644 index 0000000000..4e5d90e714 --- /dev/null +++ b/cpp/common/test/rules/castcharbeforeconvertingtolargersizes/test.cpp @@ -0,0 +1,17 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +#include + +template S get(T t) { + S s = t; // COMPLIANT + return s; +} + +void test(std::int32_t i32, std::int8_t i8, char c) { + i32 = c; // NON_COMPLIANT + i32 = get(c); // NON_COMPLIANT + i32 = get(c); // COMPLIANT + i32 = i8; // COMPLIANT + i32 = get(i8); // COMPLIANT + i32 = get(i8); // COMPLIANT +} diff --git a/cpp/common/test/rules/castsbetweenapointertofunctionandanyothertype/CastsBetweenAPointerToFunctionAndAnyOtherType.expected b/cpp/common/test/rules/castsbetweenapointertofunctionandanyothertype/CastsBetweenAPointerToFunctionAndAnyOtherType.expected new file mode 100644 index 0000000000..24493879f0 --- /dev/null +++ b/cpp/common/test/rules/castsbetweenapointertofunctionandanyothertype/CastsBetweenAPointerToFunctionAndAnyOtherType.expected @@ -0,0 +1,2 @@ +| test.cpp:3:3:3:34 | reinterpret_cast<..(*)(..)>... | Cast converting a pointer to function. | +| test.cpp:4:3:4:30 | reinterpret_cast... | Cast converting a pointer to function. | diff --git a/cpp/common/test/rules/castsbetweenapointertofunctionandanyothertype/CastsBetweenAPointerToFunctionAndAnyOtherType.ql b/cpp/common/test/rules/castsbetweenapointertofunctionandanyothertype/CastsBetweenAPointerToFunctionAndAnyOtherType.ql new file mode 100644 index 0000000000..fd716b8570 --- /dev/null +++ b/cpp/common/test/rules/castsbetweenapointertofunctionandanyothertype/CastsBetweenAPointerToFunctionAndAnyOtherType.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.castsbetweenapointertofunctionandanyothertype.CastsBetweenAPointerToFunctionAndAnyOtherType + +class TestFileQuery extends CastsBetweenAPointerToFunctionAndAnyOtherTypeSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/castsbetweenapointertofunctionandanyothertype/test.cpp b/cpp/common/test/rules/castsbetweenapointertofunctionandanyothertype/test.cpp new file mode 100644 index 0000000000..aad03a054e --- /dev/null +++ b/cpp/common/test/rules/castsbetweenapointertofunctionandanyothertype/test.cpp @@ -0,0 +1,5 @@ + +void f(int) { + reinterpret_cast(&f); // NON_COMPLIANT + reinterpret_cast(&f); // NON_COMPLIANT +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/M2-7-1/SlashStarUsedWithinACStyleComment.expected b/cpp/common/test/rules/charactersequenceusedwithinacstylecomment/CharacterSequenceUsedWithinACStyleComment.expected similarity index 100% rename from cpp/autosar/test/rules/M2-7-1/SlashStarUsedWithinACStyleComment.expected rename to cpp/common/test/rules/charactersequenceusedwithinacstylecomment/CharacterSequenceUsedWithinACStyleComment.expected diff --git a/cpp/common/test/rules/charactersequenceusedwithinacstylecomment/CharacterSequenceUsedWithinACStyleComment.ql b/cpp/common/test/rules/charactersequenceusedwithinacstylecomment/CharacterSequenceUsedWithinACStyleComment.ql new file mode 100644 index 0000000000..3fd1cf77ba --- /dev/null +++ b/cpp/common/test/rules/charactersequenceusedwithinacstylecomment/CharacterSequenceUsedWithinACStyleComment.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.charactersequenceusedwithinacstylecomment.CharacterSequenceUsedWithinACStyleComment + +class TestFileQuery extends CharacterSequenceUsedWithinACStyleCommentSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/M2-7-1/test.cpp b/cpp/common/test/rules/charactersequenceusedwithinacstylecomment/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M2-7-1/test.cpp rename to cpp/common/test/rules/charactersequenceusedwithinacstylecomment/test.cpp diff --git a/cpp/common/test/rules/constlikereturnvalue/ConstLikeReturnValue.expected b/cpp/common/test/rules/constlikereturnvalue/ConstLikeReturnValue.expected new file mode 100644 index 0000000000..2caa0d197c --- /dev/null +++ b/cpp/common/test/rules/constlikereturnvalue/ConstLikeReturnValue.expected @@ -0,0 +1,20 @@ +problems +| test.cpp:11:8:11:12 | c_str | test.cpp:18:16:18:21 | call to getenv | test.cpp:11:8:11:12 | c_str | The object returned by the function getenv should not be modified. | +| test.cpp:67:5:67:9 | conv4 | test.cpp:64:11:64:20 | call to localeconv | test.cpp:67:5:67:9 | conv4 | The object returned by the function localeconv should not be modified. | +| test.cpp:76:5:76:8 | conv | test.cpp:72:25:72:34 | call to localeconv | test.cpp:76:5:76:8 | conv | The object returned by the function localeconv should not be modified. | +edges +| test.cpp:8:18:8:22 | c_str | test.cpp:11:8:11:12 | c_str | provenance | | +| test.cpp:18:16:18:21 | call to getenv | test.cpp:24:9:24:12 | env1 | provenance | | +| test.cpp:24:9:24:12 | env1 | test.cpp:8:18:8:22 | c_str | provenance | | +| test.cpp:64:11:64:20 | call to localeconv | test.cpp:67:5:67:9 | conv4 | provenance | | +| test.cpp:72:25:72:34 | call to localeconv | test.cpp:76:5:76:8 | conv | provenance | | +nodes +| test.cpp:8:18:8:22 | c_str | semmle.label | c_str | +| test.cpp:11:8:11:12 | c_str | semmle.label | c_str | +| test.cpp:18:16:18:21 | call to getenv | semmle.label | call to getenv | +| test.cpp:24:9:24:12 | env1 | semmle.label | env1 | +| test.cpp:64:11:64:20 | call to localeconv | semmle.label | call to localeconv | +| test.cpp:67:5:67:9 | conv4 | semmle.label | conv4 | +| test.cpp:72:25:72:34 | call to localeconv | semmle.label | call to localeconv | +| test.cpp:76:5:76:8 | conv | semmle.label | conv | +subpaths diff --git a/cpp/common/test/rules/constlikereturnvalue/ConstLikeReturnValue.ql b/cpp/common/test/rules/constlikereturnvalue/ConstLikeReturnValue.ql new file mode 100644 index 0000000000..53c27eb3ce --- /dev/null +++ b/cpp/common/test/rules/constlikereturnvalue/ConstLikeReturnValue.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.constlikereturnvalue.ConstLikeReturnValue + +class TestFileQuery extends ConstLikeReturnValueSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/constlikereturnvalue/test.cpp b/cpp/common/test/rules/constlikereturnvalue/test.cpp new file mode 100644 index 0000000000..19db17faee --- /dev/null +++ b/cpp/common/test/rules/constlikereturnvalue/test.cpp @@ -0,0 +1,96 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +#include +#include +#include +#include + +void trstr(char *c_str, char orig, char rep) { + while (*c_str != '\0') { + if (*c_str == orig) { + *c_str = rep; // NON_COMPLIANT + } + ++c_str; + } +} + +void f1(void) { + char *env1 = getenv("TEST_ENV"); + char *copy_of_env; + copy_of_env = env1; // COMPLIANT + + if (env1 == NULL) { + } + trstr(env1, '"', '_'); +} + +void f2(void) { + const char *env2; + char *copy_of_env; + + env2 = getenv("TEST_ENV"); + if (env2 == NULL) { + } + + copy_of_env = (char *)malloc(strlen(env2) + 1); + if (copy_of_env == NULL) { + } + + strcpy(copy_of_env, env2); + trstr(copy_of_env, '"', '_'); // COMPLIANT +} + +void f3(void) { + const char *env3; + char *copy_of_env; + + env3 = getenv("TEST_ENV"); + if (env3 == NULL) { + } + + copy_of_env = strdup(env3); + if (copy_of_env == NULL) { + } + + trstr(copy_of_env, '"', '_'); // COMPLIANT + if (setenv("TEST_ENV", copy_of_env, 1) != 0) { + } +} + +void f4(void) { + struct lconv *conv4 = localeconv(); + + setlocale(LC_ALL, "C"); // COMPLIANT + conv4 = localeconv(); // COMPLIANT + + if ('\0' == conv4->decimal_point[0]) { + conv4->decimal_point = "."; // NON_COMPLIANT + } +} + +void f4alias(void) { + struct lconv *conv4 = localeconv(); + struct lconv *conv = conv4; + + if ('\0' == conv4->decimal_point[0]) { + conv->decimal_point = "."; // NON_COMPLIANT + } +} + +void f5(void) { + const struct lconv *conv5 = localeconv(); + if (conv5 == NULL) { + } + + struct lconv *copy_of_conv = (struct lconv *)malloc(sizeof(struct lconv)); + if (copy_of_conv == NULL) { + } + + memcpy(copy_of_conv, conv5, sizeof(struct lconv)); + + if ('\0' == copy_of_conv->decimal_point[0]) { + copy_of_conv->decimal_point = "."; // COMPLIANT + } + + free(copy_of_conv); +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/A12-8-5/CopyAssignmentAndAMoveHandleSelfAssignment.expected b/cpp/common/test/rules/copyandmoveassignmentsshallhandleselfassignment/CopyAndMoveAssignmentsShallHandleSelfAssignment.expected similarity index 100% rename from cpp/autosar/test/rules/A12-8-5/CopyAssignmentAndAMoveHandleSelfAssignment.expected rename to cpp/common/test/rules/copyandmoveassignmentsshallhandleselfassignment/CopyAndMoveAssignmentsShallHandleSelfAssignment.expected diff --git a/cpp/common/test/rules/copyandmoveassignmentsshallhandleselfassignment/CopyAndMoveAssignmentsShallHandleSelfAssignment.ql b/cpp/common/test/rules/copyandmoveassignmentsshallhandleselfassignment/CopyAndMoveAssignmentsShallHandleSelfAssignment.ql new file mode 100644 index 0000000000..9e84431f65 --- /dev/null +++ b/cpp/common/test/rules/copyandmoveassignmentsshallhandleselfassignment/CopyAndMoveAssignmentsShallHandleSelfAssignment.ql @@ -0,0 +1,5 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.copyandmoveassignmentsshallhandleselfassignment.CopyAndMoveAssignmentsShallHandleSelfAssignment + +class TestFileQuery extends CopyAndMoveAssignmentsShallHandleSelfAssignmentSharedQuery, TestQuery { +} diff --git a/cpp/autosar/test/rules/A12-8-5/test.cpp b/cpp/common/test/rules/copyandmoveassignmentsshallhandleselfassignment/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A12-8-5/test.cpp rename to cpp/common/test/rules/copyandmoveassignmentsshallhandleselfassignment/test.cpp diff --git a/cpp/autosar/test/rules/M18-7-1/CsignalFunctionsUsed.expected b/cpp/common/test/rules/csignalfunctionsused/CsignalFunctionsUsed.expected similarity index 100% rename from cpp/autosar/test/rules/M18-7-1/CsignalFunctionsUsed.expected rename to cpp/common/test/rules/csignalfunctionsused/CsignalFunctionsUsed.expected diff --git a/cpp/common/test/rules/csignalfunctionsused/CsignalFunctionsUsed.ql b/cpp/common/test/rules/csignalfunctionsused/CsignalFunctionsUsed.ql new file mode 100644 index 0000000000..1d39069ae7 --- /dev/null +++ b/cpp/common/test/rules/csignalfunctionsused/CsignalFunctionsUsed.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.csignalfunctionsused.CsignalFunctionsUsed + +class TestFileQuery extends CsignalFunctionsUsedSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/M18-7-1/test.cpp b/cpp/common/test/rules/csignalfunctionsused/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M18-7-1/test.cpp rename to cpp/common/test/rules/csignalfunctionsused/test.cpp diff --git a/cpp/autosar/test/rules/M18-7-1/CsignalTypesUsed.expected b/cpp/common/test/rules/csignaltypesused/CsignalTypesUsed.expected similarity index 100% rename from cpp/autosar/test/rules/M18-7-1/CsignalTypesUsed.expected rename to cpp/common/test/rules/csignaltypesused/CsignalTypesUsed.expected diff --git a/cpp/common/test/rules/csignaltypesused/CsignalTypesUsed.ql b/cpp/common/test/rules/csignaltypesused/CsignalTypesUsed.ql new file mode 100644 index 0000000000..76cc8aad04 --- /dev/null +++ b/cpp/common/test/rules/csignaltypesused/CsignalTypesUsed.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.csignaltypesused.CsignalTypesUsed + +class TestFileQuery extends CsignalTypesUsedSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/csignaltypesused/test.cpp b/cpp/common/test/rules/csignaltypesused/test.cpp new file mode 100644 index 0000000000..e621160b81 --- /dev/null +++ b/cpp/common/test/rules/csignaltypesused/test.cpp @@ -0,0 +1,13 @@ +#include + +void signal_handler(int signal) {} + +void test_signal_is_used() { + std::sig_atomic_t atom; // NON_COMPLIANT + std::signal(SIGINT, signal_handler); // NON_COMPLIANT + std::raise(SIGINT); // NON_COMPLIANT + + sig_atomic_t atom1; // NON_COMPLIANT + signal(SIGINT, signal_handler); // NON_COMPLIANT + raise(SIGINT); // NON_COMPLIANT +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/M27-0-1/CstdioFunctionsUsed.expected b/cpp/common/test/rules/cstdiofunctionsused/CstdioFunctionsUsed.expected similarity index 100% rename from cpp/autosar/test/rules/M27-0-1/CstdioFunctionsUsed.expected rename to cpp/common/test/rules/cstdiofunctionsused/CstdioFunctionsUsed.expected diff --git a/cpp/common/test/rules/cstdiofunctionsused/CstdioFunctionsUsed.ql b/cpp/common/test/rules/cstdiofunctionsused/CstdioFunctionsUsed.ql new file mode 100644 index 0000000000..16dbb974b6 --- /dev/null +++ b/cpp/common/test/rules/cstdiofunctionsused/CstdioFunctionsUsed.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.cstdiofunctionsused.CstdioFunctionsUsed + +class TestFileQuery extends CstdioFunctionsUsedSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/M27-0-1/test.cpp b/cpp/common/test/rules/cstdiofunctionsused/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M27-0-1/test.cpp rename to cpp/common/test/rules/cstdiofunctionsused/test.cpp diff --git a/cpp/autosar/test/rules/M27-0-1/CstdioMacrosUsed.expected b/cpp/common/test/rules/cstdiomacrosused/CstdioMacrosUsed.expected similarity index 100% rename from cpp/autosar/test/rules/M27-0-1/CstdioMacrosUsed.expected rename to cpp/common/test/rules/cstdiomacrosused/CstdioMacrosUsed.expected diff --git a/cpp/common/test/rules/cstdiomacrosused/CstdioMacrosUsed.ql b/cpp/common/test/rules/cstdiomacrosused/CstdioMacrosUsed.ql new file mode 100644 index 0000000000..79ab6086b1 --- /dev/null +++ b/cpp/common/test/rules/cstdiomacrosused/CstdioMacrosUsed.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.cstdiomacrosused.CstdioMacrosUsed + +class TestFileQuery extends CstdioMacrosUsedSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/cstdiomacrosused/test.cpp b/cpp/common/test/rules/cstdiomacrosused/test.cpp new file mode 100644 index 0000000000..27447ba06a --- /dev/null +++ b/cpp/common/test/rules/cstdiomacrosused/test.cpp @@ -0,0 +1,61 @@ +#include +#include +void *test_cstdio_is_used() { + std::FILE *f = std::fopen("foo.txt", "r"); // NON_COMPLIANT + + std::fpos_t init_position; // NON_COMPLIANT + std::fgetpos(f, &init_position); // NON_COMPLIANT + + while (!std::feof(f)) { // NON_COMPLIANT + char c = std::fgetc(f); // NON_COMPLIANT + if (c == EOF) // NON_COMPLIANT + std::rewind(f); // NON_COMPLIANT + } + if (std::ferror(f)) { // NON_COMPLIANT + std::clearerr(f); // NON_COMPLIANT + std::fclose(f); // NON_COMPLIANT + std::perror("fgetc"); // NON_COMPLIANT + } + + std::fseek(f, (size_t)0, SEEK_SET); // NON_COMPLIANT + std::fseek(f, (size_t)0, SEEK_END); // NON_COMPLIANT + char buf[BUFSIZ]; // NON_COMPLIANT + std::fread(buf, 1, sizeof(buf), f); // NON_COMPLIANT + + std::fsetpos(f, &init_position); // NON_COMPLIANT + std::fflush(f); // NON_COMPLIANT + std::fclose(f); // NON_COMPLIANT + + std::printf("DEBUG: TMP_MAX=%d FILENAME_MAX=%d FOPEN_MAX=%d\n", TMP_MAX, + FILENAME_MAX, FOPEN_MAX); // NON_COMPLIANT + std::puts("all done!"); // NON_COMPLIANT + + // global namespace + FILE *f1 = fopen("foo.txt", "r"); // NON_COMPLIANT + + fpos_t init_position1; + fgetpos(f1, &init_position1); // NON_COMPLIANT + + while (!feof(f1)) { // NON_COMPLIANT + char c = fgetc(f1); // NON_COMPLIANT + if (c == EOF) // NON_COMPLIANT + rewind(f1); // NON_COMPLIANT + } + if (ferror(f1)) { // NON_COMPLIANT + clearerr(f1); // NON_COMPLIANT + fclose(f1); // NON_COMPLIANT + perror("fgetc"); // NON_COMPLIANT + } + + fseek(f1, (size_t)0, SEEK_SET); // NON_COMPLIANT + fread(buf, 1, sizeof(buf), f1); // NON_COMPLIANT + + fsetpos(f1, &init_position1); // NON_COMPLIANT + fflush(f1); // NON_COMPLIANT + fclose(f1); // NON_COMPLIANT + + printf("foo"); // NON_COMPLIANT + puts("all done!"); // NON_COMPLIANT + + return NULL; // COMPLIANT - NULL is not uniquely defined by cstdio +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/M27-0-1/CstdioTypesUsed.expected b/cpp/common/test/rules/cstdiotypesused/CstdioTypesUsed.expected similarity index 100% rename from cpp/autosar/test/rules/M27-0-1/CstdioTypesUsed.expected rename to cpp/common/test/rules/cstdiotypesused/CstdioTypesUsed.expected diff --git a/cpp/common/test/rules/cstdiotypesused/CstdioTypesUsed.ql b/cpp/common/test/rules/cstdiotypesused/CstdioTypesUsed.ql new file mode 100644 index 0000000000..c5bac15c65 --- /dev/null +++ b/cpp/common/test/rules/cstdiotypesused/CstdioTypesUsed.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.cstdiotypesused.CstdioTypesUsed + +class TestFileQuery extends CstdioTypesUsedSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/cstdiotypesused/test.cpp b/cpp/common/test/rules/cstdiotypesused/test.cpp new file mode 100644 index 0000000000..27447ba06a --- /dev/null +++ b/cpp/common/test/rules/cstdiotypesused/test.cpp @@ -0,0 +1,61 @@ +#include +#include +void *test_cstdio_is_used() { + std::FILE *f = std::fopen("foo.txt", "r"); // NON_COMPLIANT + + std::fpos_t init_position; // NON_COMPLIANT + std::fgetpos(f, &init_position); // NON_COMPLIANT + + while (!std::feof(f)) { // NON_COMPLIANT + char c = std::fgetc(f); // NON_COMPLIANT + if (c == EOF) // NON_COMPLIANT + std::rewind(f); // NON_COMPLIANT + } + if (std::ferror(f)) { // NON_COMPLIANT + std::clearerr(f); // NON_COMPLIANT + std::fclose(f); // NON_COMPLIANT + std::perror("fgetc"); // NON_COMPLIANT + } + + std::fseek(f, (size_t)0, SEEK_SET); // NON_COMPLIANT + std::fseek(f, (size_t)0, SEEK_END); // NON_COMPLIANT + char buf[BUFSIZ]; // NON_COMPLIANT + std::fread(buf, 1, sizeof(buf), f); // NON_COMPLIANT + + std::fsetpos(f, &init_position); // NON_COMPLIANT + std::fflush(f); // NON_COMPLIANT + std::fclose(f); // NON_COMPLIANT + + std::printf("DEBUG: TMP_MAX=%d FILENAME_MAX=%d FOPEN_MAX=%d\n", TMP_MAX, + FILENAME_MAX, FOPEN_MAX); // NON_COMPLIANT + std::puts("all done!"); // NON_COMPLIANT + + // global namespace + FILE *f1 = fopen("foo.txt", "r"); // NON_COMPLIANT + + fpos_t init_position1; + fgetpos(f1, &init_position1); // NON_COMPLIANT + + while (!feof(f1)) { // NON_COMPLIANT + char c = fgetc(f1); // NON_COMPLIANT + if (c == EOF) // NON_COMPLIANT + rewind(f1); // NON_COMPLIANT + } + if (ferror(f1)) { // NON_COMPLIANT + clearerr(f1); // NON_COMPLIANT + fclose(f1); // NON_COMPLIANT + perror("fgetc"); // NON_COMPLIANT + } + + fseek(f1, (size_t)0, SEEK_SET); // NON_COMPLIANT + fread(buf, 1, sizeof(buf), f1); // NON_COMPLIANT + + fsetpos(f1, &init_position1); // NON_COMPLIANT + fflush(f1); // NON_COMPLIANT + fclose(f1); // NON_COMPLIANT + + printf("foo"); // NON_COMPLIANT + puts("all done!"); // NON_COMPLIANT + + return NULL; // COMPLIANT - NULL is not uniquely defined by cstdio +} \ No newline at end of file diff --git a/cpp/common/test/rules/deadcode/DeadCode.expected b/cpp/common/test/rules/deadcode/DeadCode.expected index 6c111d8a93..1756231343 100644 --- a/cpp/common/test/rules/deadcode/DeadCode.expected +++ b/cpp/common/test/rules/deadcode/DeadCode.expected @@ -12,3 +12,10 @@ | test.cpp:72:3:73:3 | try { ... } | This statement is dead code. | | test.cpp:73:17:74:3 | { ... } | This statement is dead code. | | test.cpp:79:17:80:3 | { ... } | This statement is dead code. | +| test.cpp:85:3:85:43 | declaration | This statement is dead code. | +| test.cpp:87:3:87:30 | declaration | This statement is dead code. | +| test.cpp:90:3:90:50 | declaration | This statement is dead code. | +| test.cpp:116:3:116:21 | ExprStmt | This statement is dead code. | +| test.cpp:117:3:117:27 | ExprStmt | This statement is dead code. | +| test.cpp:118:7:118:32 | ExprStmt | This statement is dead code. | +| test.cpp:139:3:139:35 | ExprStmt | This statement is dead code. | diff --git a/cpp/common/test/rules/deadcode/test.cpp b/cpp/common/test/rules/deadcode/test.cpp index ba5c59b07c..d40667539d 100644 --- a/cpp/common/test/rules/deadcode/test.cpp +++ b/cpp/common/test/rules/deadcode/test.cpp @@ -81,5 +81,61 @@ int test_dead_code(int x) { static_assert(1); // COMPLIANT - return live5 + live6; // COMPLIANT + constexpr int constexpr_array_size{6}; // COMPLIANT + int unused_array[constexpr_array_size]{}; // NON_COMPLIANT + + constexpr int unused_int{2}; // NON_COMPLIANT + + constexpr int constexpr_used_array[]{3, 4, 5}; // COMPLIANT + constexpr int constexpr_unused_array[]{0, 1, 2}; // NON_COMPLIANT + + return live5 + live6 + constexpr_used_array[1]; // COMPLIANT +} + +class Foo { +public: + void bar() { may_have_side_effects(); } +}; + +class Baz { +public: + void bar() {} // No side effects +}; + +#define FULL_STMT_NO_SIDE_EFFECTS no_side_effects(1); +#define PART_STMT_NO_SIDE_EFFECTS no_side_effects(1) +#define BLOCK_SOME_SIDE_EFFECTS \ + { \ + may_have_side_effects(); \ + no_side_effects(1); \ + } + +template void test_template() { + T t; + t.bar(); // COMPLIANT + no_side_effects(1); // NON_COMPLIANT + FULL_STMT_NO_SIDE_EFFECTS // NON_COMPLIANT + PART_STMT_NO_SIDE_EFFECTS; // NON_COMPLIANT + BLOCK_SOME_SIDE_EFFECTS; // COMPLIANT - cannot determine loc for + // no_side_effects(1) +} + +template void test_variant_side_effects() { + T t; + t.bar(); // COMPLIANT - not dead in at least one instance +} + +template void test_unused_template() { + T t; + t.bar(); // COMPLIANT + no_side_effects( + 1); // NON_COMPLIANT[FALSE_NEGATIVE] - unused templates are not extracted +} + +void test() { + test_template(); + test_template(); + test_variant_side_effects(); // COMPLIANT + test_variant_side_effects(); // NON_COMPLIANT - no effect in this + // instantiation } \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-3-1/DefinitionNotConsideredForUnqualifiedLookup.expected b/cpp/common/test/rules/definitionnotconsideredforunqualifiedlookup/DefinitionNotConsideredForUnqualifiedLookup.expected similarity index 100% rename from cpp/autosar/test/rules/A7-3-1/DefinitionNotConsideredForUnqualifiedLookup.expected rename to cpp/common/test/rules/definitionnotconsideredforunqualifiedlookup/DefinitionNotConsideredForUnqualifiedLookup.expected diff --git a/cpp/common/test/rules/definitionnotconsideredforunqualifiedlookup/DefinitionNotConsideredForUnqualifiedLookup.ql b/cpp/common/test/rules/definitionnotconsideredforunqualifiedlookup/DefinitionNotConsideredForUnqualifiedLookup.ql new file mode 100644 index 0000000000..05457c997c --- /dev/null +++ b/cpp/common/test/rules/definitionnotconsideredforunqualifiedlookup/DefinitionNotConsideredForUnqualifiedLookup.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.definitionnotconsideredforunqualifiedlookup.DefinitionNotConsideredForUnqualifiedLookup + +class TestFileQuery extends DefinitionNotConsideredForUnqualifiedLookupSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/A7-3-1/test.cpp b/cpp/common/test/rules/definitionnotconsideredforunqualifiedlookup/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A7-3-1/test.cpp rename to cpp/common/test/rules/definitionnotconsideredforunqualifiedlookup/test.cpp diff --git a/cpp/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.expected b/cpp/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.expected new file mode 100644 index 0000000000..f94246bc63 --- /dev/null +++ b/cpp/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.expected @@ -0,0 +1,2 @@ +| test.cpp:6:3:6:13 | call to memcpy | Call to 'memcpy' passes an $@ to a $@ (pointer value derived from a pair of address-of expressions ($@, $@). | test.cpp:6:22:6:26 | & ... | aliased pointer | test.cpp:6:15:6:19 | & ... | restrict-qualified parameter | test.cpp:6:15:6:19 | & ... | addressof1 | test.cpp:6:22:6:26 | & ... | addressof2 | +| test.cpp:8:3:8:13 | call to memcpy | Call to 'memcpy' passes an $@ to a $@ (pointer value derived from a pair of address-of expressions ($@, $@). | test.cpp:8:22:8:26 | & ... | aliased pointer | test.cpp:8:15:8:19 | & ... | restrict-qualified parameter | test.cpp:8:15:8:19 | & ... | addressof1 | test.cpp:8:22:8:26 | & ... | addressof2 | diff --git a/cpp/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.ql b/cpp/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.ql new file mode 100644 index 0000000000..dc3a521edf --- /dev/null +++ b/cpp/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.ql @@ -0,0 +1,6 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.donotpassaliasedpointertorestrictqualifiedparamshared.DoNotPassAliasedPointerToRestrictQualifiedParamShared + +class TestFileQuery extends DoNotPassAliasedPointerToRestrictQualifiedParamSharedSharedQuery, + TestQuery +{ } diff --git a/cpp/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/test.cpp b/cpp/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/test.cpp new file mode 100644 index 0000000000..42a35d0e92 --- /dev/null +++ b/cpp/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/test.cpp @@ -0,0 +1,10 @@ +#include + +int a[20]; + +void undefined_behaviour_fn_119(void) { + std::memcpy(&a[0], &a[1], 10u * sizeof(a[0])); // NON_COMPLIANT + std::memmove(&a[0], &a[1], 10u * sizeof(a[0])); // COMPLIANT + std::memcpy(&a[1], &a[0], 10u * sizeof(a[0])); // NON_COMPLIANT + std::memmove(&a[1], &a[0], 10u * sizeof(a[0])); // COMPLIANT +} \ No newline at end of file diff --git a/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected b/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected index 537228a000..2d293e6928 100644 --- a/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected +++ b/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected @@ -4,14 +4,14 @@ problems | test.cpp:13:10:13:11 | p4 | test.cpp:5:14:5:15 | l2 | test.cpp:13:10:13:11 | p4 | Subtraction between left operand pointing to array $@ and other operand pointing to array $@. | test.cpp:3:7:3:8 | l2 | l2 | test.cpp:2:7:2:8 | l1 | l1 | | test.cpp:13:15:13:16 | l1 | test.cpp:13:15:13:16 | l1 | test.cpp:13:15:13:16 | l1 | Subtraction between right operand pointing to array $@ and other operand pointing to array $@. | test.cpp:2:7:2:8 | l1 | l1 | test.cpp:3:7:3:8 | l2 | l2 | edges -| test.cpp:4:14:4:15 | l1 | test.cpp:4:14:4:18 | access to array | -| test.cpp:4:14:4:18 | access to array | test.cpp:10:10:10:11 | p1 | -| test.cpp:4:14:4:18 | access to array | test.cpp:12:10:12:11 | p1 | -| test.cpp:5:14:5:15 | l2 | test.cpp:5:14:5:19 | access to array | -| test.cpp:5:14:5:19 | access to array | test.cpp:11:10:11:11 | p2 | -| test.cpp:5:14:5:19 | access to array | test.cpp:12:15:12:16 | p2 | -| test.cpp:5:14:5:19 | access to array | test.cpp:13:10:13:11 | p4 | -| test.cpp:5:14:5:19 | access to array | test.cpp:14:10:14:11 | p4 | +| test.cpp:4:14:4:15 | l1 | test.cpp:4:14:4:18 | access to array | provenance | Config | +| test.cpp:4:14:4:18 | access to array | test.cpp:10:10:10:11 | p1 | provenance | | +| test.cpp:4:14:4:18 | access to array | test.cpp:12:10:12:11 | p1 | provenance | | +| test.cpp:5:14:5:15 | l2 | test.cpp:5:14:5:19 | access to array | provenance | Config | +| test.cpp:5:14:5:19 | access to array | test.cpp:11:10:11:11 | p2 | provenance | | +| test.cpp:5:14:5:19 | access to array | test.cpp:12:15:12:16 | p2 | provenance | | +| test.cpp:5:14:5:19 | access to array | test.cpp:13:10:13:11 | p4 | provenance | | +| test.cpp:5:14:5:19 | access to array | test.cpp:14:10:14:11 | p4 | provenance | | nodes | test.cpp:4:14:4:15 | l1 | semmle.label | l1 | | test.cpp:4:14:4:18 | access to array | semmle.label | access to array | diff --git a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected index fa181755e8..31ff47e55c 100644 --- a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected +++ b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected @@ -1,5 +1,8 @@ -| test.cpp:4:13:4:18 | ... + ... | Array pointer p2 points 1 element passed the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | -| test.cpp:5:13:5:18 | ... + ... | Array pointer p3 points 1 element passed the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | -| test.cpp:6:13:6:18 | & ... | Array pointer p4 points 1 element passed the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | -| test.cpp:11:8:11:11 | ... -- | Array pointer p7 points 1 element passed the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | -| test.cpp:12:8:12:9 | p3 | Array pointer p8 points 1 element passed the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | +| test.cpp:4:13:4:18 | ... + ... | Array pointer p2 points 1 element past the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | +| test.cpp:5:13:5:18 | ... + ... | Array pointer p3 points 1 element past the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | +| test.cpp:6:13:6:18 | & ... | Array pointer p4 points 1 element past the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | +| test.cpp:11:8:11:11 | ... -- | Array pointer p7 points 1 element past the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | +| test.cpp:12:8:12:9 | p3 | Array pointer p8 points 1 element past the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | +| test.cpp:25:15:25:21 | & ... | Array pointer p14 points 1 element past the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | +| test.cpp:30:15:30:21 | & ... | Array pointer p17 points 1 element past the end of $@. | test.cpp:28:24:28:42 | (unsigned char *)... | cast to byte pointer | +| test.cpp:35:15:35:21 | & ... | Array pointer p20 points 1 element past the end of $@. | test.cpp:33:24:33:43 | (unsigned char *)... | cast to byte pointer | diff --git a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp index c1032ee735..d9874bfb29 100644 --- a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp +++ b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp @@ -17,4 +17,37 @@ void f1() { 3 + p1; // COMPLIANT - points to an element on beyond the end of the array int *p11 = &l1[3]; // COMPLIANT - points to an element on beyond the end of the array + + // Casting to a pointer to a type of the same size doesn't invalidate the + // analysis + unsigned int *p12 = (unsigned int *)l1; + void *p13 = &p12[3]; // COMPLIANT + void *p14 = &p12[4]; // NON_COMPLIANT + + // Casting to a char* is effectively a new array of length sizeof(T) + unsigned char *p15 = (unsigned char *)l1; + void *p16 = &p15[4]; // COMPLIANT + void *p17 = &p15[5]; // NON_COMPLIANT + + long l2[3]; + unsigned char *p18 = (unsigned char *)&l2; + void *p19 = &p18[8]; // COMPLIANT + void *p20 = &p18[9]; // NON_COMPLIANT + + // Casting to a pointer to a differently sized type that isn't char + // invalidates analysis + long *p21 = (long *)&l1; + void *p22 = &p21[0]; // COMPLIANT + void *p23 = &p21[100]; // NON_COMPLIANT[FALSE_NEGATIVE] + + // Casting a byte pointer to a differently sized type that isn't char + // invalidates analysis + long *p24 = (long *)p15; + void *p25 = &p24[0]; // COMPLIANT + void *p26 = &p24[100]; // NON_COMPLIANT[FALSE_NEGATIVE] + + // Void pointers have size zero and can't be analyzed. + void *p27 = 0; + unsigned char *p28 = (unsigned char *)p27; + void *p29 = &p28[100]; // COMPLIANT } \ No newline at end of file diff --git a/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected b/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected index 22ddfd123a..cab80e0fe0 100644 --- a/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected +++ b/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected @@ -10,19 +10,19 @@ problems | test.cpp:25:7:25:14 | ... >= ... | test.cpp:7:14:7:15 | l1 | test.cpp:25:7:25:8 | p1 | Compare operation >= comparing left operand pointing to array $@ and other operand pointing to array $@. | test.cpp:2:7:2:8 | l1 | l1 | test.cpp:4:7:4:8 | l3 | l3 | | test.cpp:25:7:25:14 | ... >= ... | test.cpp:25:13:25:14 | l3 | test.cpp:25:13:25:14 | l3 | Compare operation >= comparing right operand pointing to array $@ and other operand pointing to array $@. | test.cpp:4:7:4:8 | l3 | l3 | test.cpp:2:7:2:8 | l1 | l1 | edges -| test.cpp:6:13:6:14 | l1 | test.cpp:13:12:13:13 | p0 | -| test.cpp:7:14:7:15 | l1 | test.cpp:7:14:7:18 | access to array | -| test.cpp:7:14:7:18 | access to array | test.cpp:11:7:11:8 | p1 | -| test.cpp:7:14:7:18 | access to array | test.cpp:13:7:13:8 | p1 | -| test.cpp:7:14:7:18 | access to array | test.cpp:15:13:15:14 | p1 | -| test.cpp:7:14:7:18 | access to array | test.cpp:17:7:17:8 | p1 | -| test.cpp:7:14:7:18 | access to array | test.cpp:23:13:23:14 | p1 | -| test.cpp:7:14:7:18 | access to array | test.cpp:25:7:25:8 | p1 | -| test.cpp:8:14:8:15 | l1 | test.cpp:8:14:8:18 | access to array | -| test.cpp:8:14:8:18 | access to array | test.cpp:11:12:11:13 | p2 | -| test.cpp:8:14:8:18 | access to array | test.cpp:21:7:21:8 | p2 | -| test.cpp:9:14:9:15 | l2 | test.cpp:9:14:9:18 | access to array | -| test.cpp:9:14:9:18 | access to array | test.cpp:21:12:21:13 | p3 | +| test.cpp:6:13:6:14 | l1 | test.cpp:13:12:13:13 | p0 | provenance | | +| test.cpp:7:14:7:15 | l1 | test.cpp:7:14:7:18 | access to array | provenance | Config | +| test.cpp:7:14:7:18 | access to array | test.cpp:11:7:11:8 | p1 | provenance | | +| test.cpp:7:14:7:18 | access to array | test.cpp:13:7:13:8 | p1 | provenance | | +| test.cpp:7:14:7:18 | access to array | test.cpp:15:13:15:14 | p1 | provenance | | +| test.cpp:7:14:7:18 | access to array | test.cpp:17:7:17:8 | p1 | provenance | | +| test.cpp:7:14:7:18 | access to array | test.cpp:23:13:23:14 | p1 | provenance | | +| test.cpp:7:14:7:18 | access to array | test.cpp:25:7:25:8 | p1 | provenance | | +| test.cpp:8:14:8:15 | l1 | test.cpp:8:14:8:18 | access to array | provenance | Config | +| test.cpp:8:14:8:18 | access to array | test.cpp:11:12:11:13 | p2 | provenance | | +| test.cpp:8:14:8:18 | access to array | test.cpp:21:7:21:8 | p2 | provenance | | +| test.cpp:9:14:9:15 | l2 | test.cpp:9:14:9:18 | access to array | provenance | Config | +| test.cpp:9:14:9:18 | access to array | test.cpp:21:12:21:13 | p3 | provenance | | nodes | test.cpp:6:13:6:14 | l1 | semmle.label | l1 | | test.cpp:7:14:7:15 | l1 | semmle.label | l1 | diff --git a/cpp/autosar/test/rules/M15-1-3/EmptyThrowOutsideCatch.expected b/cpp/common/test/rules/emptythrowonlywithinacatchhandler/EmptyThrowOnlyWithinACatchHandler.expected similarity index 100% rename from cpp/autosar/test/rules/M15-1-3/EmptyThrowOutsideCatch.expected rename to cpp/common/test/rules/emptythrowonlywithinacatchhandler/EmptyThrowOnlyWithinACatchHandler.expected diff --git a/cpp/common/test/rules/emptythrowonlywithinacatchhandler/EmptyThrowOnlyWithinACatchHandler.ql b/cpp/common/test/rules/emptythrowonlywithinacatchhandler/EmptyThrowOnlyWithinACatchHandler.ql new file mode 100644 index 0000000000..a07b861639 --- /dev/null +++ b/cpp/common/test/rules/emptythrowonlywithinacatchhandler/EmptyThrowOnlyWithinACatchHandler.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.emptythrowonlywithinacatchhandler.EmptyThrowOnlyWithinACatchHandler + +class TestFileQuery extends EmptyThrowOnlyWithinACatchHandlerSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/M15-1-3/test.cpp b/cpp/common/test/rules/emptythrowonlywithinacatchhandler/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M15-1-3/test.cpp rename to cpp/common/test/rules/emptythrowonlywithinacatchhandler/test.cpp diff --git a/cpp/autosar/test/rules/A7-2-2/EnumerationUnderlyingBaseTypeNotExplicitlyDefined.expected b/cpp/common/test/rules/enumerationnotdefinedwithanexplicitunderlyingtype/EnumerationNotDefinedWithAnExplicitUnderlyingType.expected similarity index 100% rename from cpp/autosar/test/rules/A7-2-2/EnumerationUnderlyingBaseTypeNotExplicitlyDefined.expected rename to cpp/common/test/rules/enumerationnotdefinedwithanexplicitunderlyingtype/EnumerationNotDefinedWithAnExplicitUnderlyingType.expected diff --git a/cpp/common/test/rules/enumerationnotdefinedwithanexplicitunderlyingtype/EnumerationNotDefinedWithAnExplicitUnderlyingType.ql b/cpp/common/test/rules/enumerationnotdefinedwithanexplicitunderlyingtype/EnumerationNotDefinedWithAnExplicitUnderlyingType.ql new file mode 100644 index 0000000000..999f505c5f --- /dev/null +++ b/cpp/common/test/rules/enumerationnotdefinedwithanexplicitunderlyingtype/EnumerationNotDefinedWithAnExplicitUnderlyingType.ql @@ -0,0 +1,5 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.enumerationnotdefinedwithanexplicitunderlyingtype.EnumerationNotDefinedWithAnExplicitUnderlyingType + +class TestFileQuery extends EnumerationNotDefinedWithAnExplicitUnderlyingTypeSharedQuery, TestQuery { +} diff --git a/cpp/autosar/test/rules/A7-2-2/test.cpp b/cpp/common/test/rules/enumerationnotdefinedwithanexplicitunderlyingtype/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A7-2-2/test.cpp rename to cpp/common/test/rules/enumerationnotdefinedwithanexplicitunderlyingtype/test.cpp diff --git a/cpp/autosar/test/rules/A15-1-2/PointerExceptionObject.expected b/cpp/common/test/rules/exceptionobjecthavepointertype/ExceptionObjectHavePointerType.expected similarity index 100% rename from cpp/autosar/test/rules/A15-1-2/PointerExceptionObject.expected rename to cpp/common/test/rules/exceptionobjecthavepointertype/ExceptionObjectHavePointerType.expected diff --git a/cpp/common/test/rules/exceptionobjecthavepointertype/ExceptionObjectHavePointerType.ql b/cpp/common/test/rules/exceptionobjecthavepointertype/ExceptionObjectHavePointerType.ql new file mode 100644 index 0000000000..d0727790d3 --- /dev/null +++ b/cpp/common/test/rules/exceptionobjecthavepointertype/ExceptionObjectHavePointerType.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.exceptionobjecthavepointertype.ExceptionObjectHavePointerType + +class TestFileQuery extends ExceptionObjectHavePointerTypeSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/A15-1-2/test.cpp b/cpp/common/test/rules/exceptionobjecthavepointertype/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A15-1-2/test.cpp rename to cpp/common/test/rules/exceptionobjecthavepointertype/test.cpp diff --git a/cpp/common/test/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.expected b/cpp/common/test/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.expected index 18689c333b..b8a8c17435 100644 --- a/cpp/common/test/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.expected +++ b/cpp/common/test/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.expected @@ -6,7 +6,7 @@ | test.cpp:103:5:103:9 | re-throw exception | The $@ is not released explicitly before throwing an exception. | test.cpp:99:12:99:21 | new | allocated resource | | test.cpp:125:5:125:37 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:124:9:124:18 | new | allocated resource | | test.cpp:134:5:134:37 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:133:23:133:32 | new | allocated resource | -| test.cpp:142:3:142:35 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:141:3:141:4 | fs | allocated resource | -| test.cpp:154:3:154:35 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:152:3:152:4 | fs | allocated resource | -| test.cpp:160:3:160:35 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:159:3:159:5 | mtx | allocated resource | -| test.cpp:172:3:172:35 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:170:3:170:5 | mtx | allocated resource | +| test.cpp:142:3:142:35 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:141:6:141:9 | call to open | allocated resource | +| test.cpp:154:3:154:35 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:152:6:152:9 | call to open | allocated resource | +| test.cpp:160:3:160:35 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:159:7:159:10 | call to lock | allocated resource | +| test.cpp:172:3:172:35 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:170:7:170:10 | call to lock | allocated resource | diff --git a/cpp/autosar/test/rules/A18-9-2/ForwardingValuesToOtherFunctions.expected b/cpp/common/test/rules/forwardingreferencesandforwardnotusedtogether/ForwardingReferencesAndForwardNotUsedTogether.expected similarity index 100% rename from cpp/autosar/test/rules/A18-9-2/ForwardingValuesToOtherFunctions.expected rename to cpp/common/test/rules/forwardingreferencesandforwardnotusedtogether/ForwardingReferencesAndForwardNotUsedTogether.expected diff --git a/cpp/common/test/rules/forwardingreferencesandforwardnotusedtogether/ForwardingReferencesAndForwardNotUsedTogether.ql b/cpp/common/test/rules/forwardingreferencesandforwardnotusedtogether/ForwardingReferencesAndForwardNotUsedTogether.ql new file mode 100644 index 0000000000..4f08530f35 --- /dev/null +++ b/cpp/common/test/rules/forwardingreferencesandforwardnotusedtogether/ForwardingReferencesAndForwardNotUsedTogether.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.forwardingreferencesandforwardnotusedtogether.ForwardingReferencesAndForwardNotUsedTogether + +class TestFileQuery extends ForwardingReferencesAndForwardNotUsedTogetherSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/A18-9-2/test.cpp b/cpp/common/test/rules/forwardingreferencesandforwardnotusedtogether/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A18-9-2/test.cpp rename to cpp/common/test/rules/forwardingreferencesandforwardnotusedtogether/test.cpp diff --git a/cpp/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected b/cpp/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected new file mode 100644 index 0000000000..2f681c9210 --- /dev/null +++ b/cpp/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected @@ -0,0 +1 @@ +| test.cpp:16:3:16:8 | call to remove | Return value from remove is not tested for errors. | diff --git a/cpp/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.ql b/cpp/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.ql new file mode 100644 index 0000000000..12c2196efd --- /dev/null +++ b/cpp/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.functionerroneousreturnvaluenottested.FunctionErroneousReturnValueNotTested + +class TestFileQuery extends FunctionErroneousReturnValueNotTestedSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/functionerroneousreturnvaluenottested/test.cpp b/cpp/common/test/rules/functionerroneousreturnvaluenottested/test.cpp new file mode 100644 index 0000000000..08e2f23dec --- /dev/null +++ b/cpp/common/test/rules/functionerroneousreturnvaluenottested/test.cpp @@ -0,0 +1,17 @@ +#include + +void test_compliant() { + // Return value is passed to an lvalue and then tested. + FILE *fh = fopen("/etc/foo", "r"); + if (!fh) { // COMPLIANT + return; + } + + // Return value is tested immediately as an rvalue. + if (fclose(fh)) // COMPLIANT + return; +} + +void test_noncompliant() { + remove("/bin/bash"); // NON_COMPLIANT +} \ No newline at end of file diff --git a/cpp/common/test/rules/functionlikemacrosdefined/FunctionLikeMacrosDefined.expected b/cpp/common/test/rules/functionlikemacrosdefined/FunctionLikeMacrosDefined.expected new file mode 100644 index 0000000000..62787cca0b --- /dev/null +++ b/cpp/common/test/rules/functionlikemacrosdefined/FunctionLikeMacrosDefined.expected @@ -0,0 +1,2 @@ +| test.cpp:8:1:8:25 | #define MACRO4(x) (x + 1) | Macro used instead of a function. | +| test.cpp:13:1:13:48 | #define MACRO9() printf_custom("output = %d", 7) | Macro used instead of a function. | diff --git a/cpp/common/test/rules/functionlikemacrosdefined/FunctionLikeMacrosDefined.ql b/cpp/common/test/rules/functionlikemacrosdefined/FunctionLikeMacrosDefined.ql new file mode 100644 index 0000000000..29088c4458 --- /dev/null +++ b/cpp/common/test/rules/functionlikemacrosdefined/FunctionLikeMacrosDefined.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.functionlikemacrosdefined.FunctionLikeMacrosDefined + +class TestFileQuery extends FunctionLikeMacrosDefinedSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/functionlikemacrosdefined/test.cpp b/cpp/common/test/rules/functionlikemacrosdefined/test.cpp new file mode 100644 index 0000000000..f39236ca3b --- /dev/null +++ b/cpp/common/test/rules/functionlikemacrosdefined/test.cpp @@ -0,0 +1,42 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +#include + +#define MACRO(OP, L, R) ((L)OP(R)) // COMPLIANT +#define MACRO2(L, R) (L + R) // COMPLIANT +#define MACRO3(L, R) (L " " R " " L) // COMPLIANT +#define MACRO4(x) (x + 1) // NON_COMPLIANT +#define MACRO5(L, LR) (LR + 1) // COMPLIANT +#define MACRO6(x) printf_custom("output = %d", test##x) // COMPLIANT +#define MACRO7(x) #x // COMPLIANT +#define MACRO8(x) "NOP" // COMPLIANT +#define MACRO9() printf_custom("output = %d", 7) // NON_COMPLIANT +#define MACRO10(x) // COMPLIANT +#define MY_ASSERT(X) assert(X) // NON_COMPLIANT[FALSE_NEGATIVE] + +char a1[MACRO2(1, 1) + 6]; +extern int printf_custom(char *, int); +int test1; + +void f() { + int i = MACRO(+, 1, 1); + int i2 = MACRO2(7, 10); + + static int i3 = MACRO2(1, 1); + + char *i4 = MACRO3("prefix", "suffix"); + + int i5 = MACRO4(1); + + int i6 = MACRO4(MACRO2(1, 1)); + + int i7 = MACRO5(1, 1); + + MACRO6(1); + + char *i10 = MACRO7("prefix"); + + asm(MACRO8(1)); + + MY_ASSERT(1); +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-5-2/RecursiveFunctions.expected b/cpp/common/test/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.expected similarity index 100% rename from cpp/autosar/test/rules/A7-5-2/RecursiveFunctions.expected rename to cpp/common/test/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.expected diff --git a/cpp/common/test/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.ql b/cpp/common/test/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.ql new file mode 100644 index 0000000000..e95ba9b7f7 --- /dev/null +++ b/cpp/common/test/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.ql @@ -0,0 +1,5 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.functionscallthemselveseitherdirectlyorindirectly.FunctionsCallThemselvesEitherDirectlyOrIndirectly + +class TestFileQuery extends FunctionsCallThemselvesEitherDirectlyOrIndirectlySharedQuery, TestQuery { +} diff --git a/cpp/autosar/test/rules/A7-5-2/test.cpp b/cpp/common/test/rules/functionscallthemselveseitherdirectlyorindirectly/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A7-5-2/test.cpp rename to cpp/common/test/rules/functionscallthemselveseitherdirectlyorindirectly/test.cpp diff --git a/cpp/autosar/test/rules/A14-8-2/ExplicitSpecializationsOfFunctionTemplatesUsed.expected b/cpp/common/test/rules/functiontemplatesexplicitlyspecialized/FunctionTemplatesExplicitlySpecialized.expected similarity index 100% rename from cpp/autosar/test/rules/A14-8-2/ExplicitSpecializationsOfFunctionTemplatesUsed.expected rename to cpp/common/test/rules/functiontemplatesexplicitlyspecialized/FunctionTemplatesExplicitlySpecialized.expected diff --git a/cpp/common/test/rules/functiontemplatesexplicitlyspecialized/FunctionTemplatesExplicitlySpecialized.ql b/cpp/common/test/rules/functiontemplatesexplicitlyspecialized/FunctionTemplatesExplicitlySpecialized.ql new file mode 100644 index 0000000000..a64a9786b6 --- /dev/null +++ b/cpp/common/test/rules/functiontemplatesexplicitlyspecialized/FunctionTemplatesExplicitlySpecialized.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.functiontemplatesexplicitlyspecialized.FunctionTemplatesExplicitlySpecialized + +class TestFileQuery extends FunctionTemplatesExplicitlySpecializedSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/A14-8-2/test.cpp b/cpp/common/test/rules/functiontemplatesexplicitlyspecialized/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A14-8-2/test.cpp rename to cpp/common/test/rules/functiontemplatesexplicitlyspecialized/test.cpp diff --git a/cpp/autosar/test/rules/M7-3-1/GlobalNamespaceMembershipViolation.expected b/cpp/common/test/rules/globalnamespacedeclarations/GlobalNamespaceDeclarations.expected similarity index 100% rename from cpp/autosar/test/rules/M7-3-1/GlobalNamespaceMembershipViolation.expected rename to cpp/common/test/rules/globalnamespacedeclarations/GlobalNamespaceDeclarations.expected diff --git a/cpp/common/test/rules/globalnamespacedeclarations/GlobalNamespaceDeclarations.ql b/cpp/common/test/rules/globalnamespacedeclarations/GlobalNamespaceDeclarations.ql new file mode 100644 index 0000000000..19482c5b09 --- /dev/null +++ b/cpp/common/test/rules/globalnamespacedeclarations/GlobalNamespaceDeclarations.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.globalnamespacedeclarations.GlobalNamespaceDeclarations + +class TestFileQuery extends GlobalNamespaceDeclarationsSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/M7-3-1/test.cpp b/cpp/common/test/rules/globalnamespacedeclarations/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M7-3-1/test.cpp rename to cpp/common/test/rules/globalnamespacedeclarations/test.cpp diff --git a/cpp/autosar/test/rules/A18-5-4/GlobalSizedOperatorDeleteNotDefined.expected b/cpp/common/test/rules/globalsizedoperatordeletenotdefined/GlobalSizedOperatorDeleteNotDefined.expected similarity index 100% rename from cpp/autosar/test/rules/A18-5-4/GlobalSizedOperatorDeleteNotDefined.expected rename to cpp/common/test/rules/globalsizedoperatordeletenotdefined/GlobalSizedOperatorDeleteNotDefined.expected diff --git a/cpp/common/test/rules/globalsizedoperatordeletenotdefined/GlobalSizedOperatorDeleteNotDefined.ql b/cpp/common/test/rules/globalsizedoperatordeletenotdefined/GlobalSizedOperatorDeleteNotDefined.ql new file mode 100644 index 0000000000..61d492f0c6 --- /dev/null +++ b/cpp/common/test/rules/globalsizedoperatordeletenotdefined/GlobalSizedOperatorDeleteNotDefined.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.globalsizedoperatordeletenotdefined.GlobalSizedOperatorDeleteNotDefined + +class TestFileQuery extends GlobalSizedOperatorDeleteNotDefinedSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/A18-5-4/test.cpp b/cpp/common/test/rules/globalsizedoperatordeletenotdefined/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A18-5-4/test.cpp rename to cpp/common/test/rules/globalsizedoperatordeletenotdefined/test.cpp diff --git a/cpp/common/test/rules/globalunsizedoperatordeletenotdefined/GlobalUnsizedOperatorDeleteNotDefined.expected b/cpp/common/test/rules/globalunsizedoperatordeletenotdefined/GlobalUnsizedOperatorDeleteNotDefined.expected new file mode 100644 index 0000000000..e69de29bb2 diff --git a/cpp/common/test/rules/globalunsizedoperatordeletenotdefined/GlobalUnsizedOperatorDeleteNotDefined.ql b/cpp/common/test/rules/globalunsizedoperatordeletenotdefined/GlobalUnsizedOperatorDeleteNotDefined.ql new file mode 100644 index 0000000000..c415cbcd70 --- /dev/null +++ b/cpp/common/test/rules/globalunsizedoperatordeletenotdefined/GlobalUnsizedOperatorDeleteNotDefined.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.globalunsizedoperatordeletenotdefined.GlobalUnsizedOperatorDeleteNotDefined + +class TestFileQuery extends GlobalUnsizedOperatorDeleteNotDefinedSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/globalunsizedoperatordeletenotdefined/test.cpp b/cpp/common/test/rules/globalunsizedoperatordeletenotdefined/test.cpp new file mode 100644 index 0000000000..8f77a41637 --- /dev/null +++ b/cpp/common/test/rules/globalunsizedoperatordeletenotdefined/test.cpp @@ -0,0 +1,3 @@ + +void operator delete(void *ptr) {} // NON_COMPLIANT +// void operator delete(void *ptr, std::size_t sz) {} diff --git a/cpp/common/test/rules/gotoreferencealabelinsurroundingblock/GotoReferenceALabelInSurroundingBlock.expected b/cpp/common/test/rules/gotoreferencealabelinsurroundingblock/GotoReferenceALabelInSurroundingBlock.expected new file mode 100644 index 0000000000..416f949eaa --- /dev/null +++ b/cpp/common/test/rules/gotoreferencealabelinsurroundingblock/GotoReferenceALabelInSurroundingBlock.expected @@ -0,0 +1,2 @@ +| test.cpp:42:3:42:10 | goto ... | The goto statement and its $@ are not declared or enclosed in the same block. | test.cpp:46:3:46:5 | label ...: | label | +| test.cpp:57:5:57:12 | goto ... | The goto statement and its $@ are not declared or enclosed in the same block. | test.cpp:60:3:60:5 | label ...: | label | diff --git a/cpp/common/test/rules/gotoreferencealabelinsurroundingblock/GotoReferenceALabelInSurroundingBlock.ql b/cpp/common/test/rules/gotoreferencealabelinsurroundingblock/GotoReferenceALabelInSurroundingBlock.ql new file mode 100644 index 0000000000..f553135683 --- /dev/null +++ b/cpp/common/test/rules/gotoreferencealabelinsurroundingblock/GotoReferenceALabelInSurroundingBlock.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.gotoreferencealabelinsurroundingblock.GotoReferenceALabelInSurroundingBlock + +class TestFileQuery extends GotoReferenceALabelInSurroundingBlockSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/gotoreferencealabelinsurroundingblock/test.cpp b/cpp/common/test/rules/gotoreferencealabelinsurroundingblock/test.cpp new file mode 100644 index 0000000000..07ebb4b13a --- /dev/null +++ b/cpp/common/test/rules/gotoreferencealabelinsurroundingblock/test.cpp @@ -0,0 +1,87 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +/*void f1() { + int i = 0; goto L1; + for (;i < 100; i++) { + L1: // NON_COMPLIANT - this is compiler checked + break; + } +}*/ + +void f2() { + int i = 0; + if (i >= 0) { + for (int j = 0; j < 10; j++) { + goto L2; + } + } +L2: // COMPLIANT + return; +} + +void f3() { + int i = 0; + if (i >= 0) { + for (int j = 0; j < 10; j++) { + goto L3; + L3: // COMPLIANT + break; + } + } +} + +void f4() { + int i = 0; +L4: // COMPLIANT + if (i >= 0) { + goto L4; + } +} + +void f5(int p) { + goto L1; + + switch (p) { + case 0: + L1:; // NON_COMPLIANT + break; + default: + break; + } +} + +void f6(int p) { + + switch (p) { + case 0: + goto L1; + break; + default: + L1: // NON_COMPLIANT + break; + } +} + +void f7(int p) { +L1: // COMPLIANT + switch (p) { + case 0: + goto L1; + break; + default: + break; + } +} + +void f8(int p) { + + switch (p) { + case 0: + goto L1; + ; + L1:; // COMPLIANT + break; + default: + break; + } +} diff --git a/cpp/common/test/rules/gotostatementcondition/GotoStatementCondition.expected b/cpp/common/test/rules/gotostatementcondition/GotoStatementCondition.expected index c1b2f35eda..9e9d81e62c 100644 --- a/cpp/common/test/rules/gotostatementcondition/GotoStatementCondition.expected +++ b/cpp/common/test/rules/gotostatementcondition/GotoStatementCondition.expected @@ -1,4 +1,4 @@ -| test.cpp:7:3:7:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:7:3:7:10 | goto ... | l1 | test.cpp:3:1:3:3 | label ...: | label ...: | -| test.cpp:19:3:19:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:19:3:19:10 | goto ... | l2 | test.cpp:15:1:15:3 | label ...: | label ...: | -| test.cpp:21:3:21:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:21:3:21:10 | goto ... | l1 | test.cpp:14:1:14:3 | label ...: | label ...: | -| test.cpp:26:3:26:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:26:3:26:10 | goto ... | l1 | test.cpp:25:1:25:3 | label ...: | label ...: | +| test.cpp:9:3:9:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:9:3:9:10 | goto ... | l1 | test.cpp:5:1:5:3 | label ...: | label ...: | +| test.cpp:21:3:21:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:21:3:21:10 | goto ... | l2 | test.cpp:17:1:17:3 | label ...: | label ...: | +| test.cpp:23:3:23:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:23:3:23:10 | goto ... | l1 | test.cpp:16:1:16:3 | label ...: | label ...: | +| test.cpp:28:3:28:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:28:3:28:10 | goto ... | l1 | test.cpp:27:1:27:3 | label ...: | label ...: | diff --git a/cpp/common/test/rules/gotostatementcondition/test.cpp b/cpp/common/test/rules/gotostatementcondition/test.cpp index 225c1b32f6..5854b21983 100644 --- a/cpp/common/test/rules/gotostatementcondition/test.cpp +++ b/cpp/common/test/rules/gotostatementcondition/test.cpp @@ -1,3 +1,5 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. void f1(int p1) { l1: diff --git a/cpp/common/test/rules/gotostatementshouldnotbeused/GotoStatementShouldNotBeUsed.expected b/cpp/common/test/rules/gotostatementshouldnotbeused/GotoStatementShouldNotBeUsed.expected new file mode 100644 index 0000000000..48547e3cca --- /dev/null +++ b/cpp/common/test/rules/gotostatementshouldnotbeused/GotoStatementShouldNotBeUsed.expected @@ -0,0 +1 @@ +| test.cpp:6:3:6:14 | goto ... | Use of goto. | diff --git a/cpp/common/test/rules/gotostatementshouldnotbeused/GotoStatementShouldNotBeUsed.ql b/cpp/common/test/rules/gotostatementshouldnotbeused/GotoStatementShouldNotBeUsed.ql new file mode 100644 index 0000000000..1a117d5ddd --- /dev/null +++ b/cpp/common/test/rules/gotostatementshouldnotbeused/GotoStatementShouldNotBeUsed.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.gotostatementshouldnotbeused.GotoStatementShouldNotBeUsed + +class TestFileQuery extends GotoStatementShouldNotBeUsedSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/gotostatementshouldnotbeused/test.cpp b/cpp/common/test/rules/gotostatementshouldnotbeused/test.cpp new file mode 100644 index 0000000000..0763208625 --- /dev/null +++ b/cpp/common/test/rules/gotostatementshouldnotbeused/test.cpp @@ -0,0 +1,11 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +void test_goto() { + int x = 1; + + goto label1; // NON_COMPLIANT + +label1: + + x = 2; +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-3-1/HiddenInheritedNonOverridableMemberFunction.expected b/cpp/common/test/rules/hiddeninheritednonoverridablememberfunction/HiddenInheritedNonOverridableMemberFunction.expected similarity index 100% rename from cpp/autosar/test/rules/A7-3-1/HiddenInheritedNonOverridableMemberFunction.expected rename to cpp/common/test/rules/hiddeninheritednonoverridablememberfunction/HiddenInheritedNonOverridableMemberFunction.expected diff --git a/cpp/common/test/rules/hiddeninheritednonoverridablememberfunction/HiddenInheritedNonOverridableMemberFunction.ql b/cpp/common/test/rules/hiddeninheritednonoverridablememberfunction/HiddenInheritedNonOverridableMemberFunction.ql new file mode 100644 index 0000000000..30953eacf3 --- /dev/null +++ b/cpp/common/test/rules/hiddeninheritednonoverridablememberfunction/HiddenInheritedNonOverridableMemberFunction.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.hiddeninheritednonoverridablememberfunction.HiddenInheritedNonOverridableMemberFunction + +class TestFileQuery extends HiddenInheritedNonOverridableMemberFunctionSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/hiddeninheritednonoverridablememberfunction/test.cpp b/cpp/common/test/rules/hiddeninheritednonoverridablememberfunction/test.cpp new file mode 100644 index 0000000000..c0904238c3 --- /dev/null +++ b/cpp/common/test/rules/hiddeninheritednonoverridablememberfunction/test.cpp @@ -0,0 +1,94 @@ +struct S1 { + int i; +}; + +class C1 { +public: + void f1(int); + + virtual void f2(int); + virtual void f2(double); + virtual void f2(S1); + +private: + void f3(int); + void f4(int); +}; + +class C2 : public C1 { +public: + void f1(double); // NON_COMPLIANT + + void f2(double) override; // NON_COMPLIANT +}; + +class C3 : public C1 { +public: + void f2(char *); // NON_COMPLIANT +}; + +class C4 : public C1 { +public: + using C1::f1; + void f1(double); // COMPLIANT + + using C1::f2; + void f2(double) override; // COMPLIANT +}; + +namespace ns1 { +void f1(int); +} + +using ns1::f1; + +namespace ns1 { +void f1(double); // NON_COMPLIANT +} + +void f1() { + C2 l1; + l1.f1(0); // calls C2::f1(double) instead of C1::f1(int) + l1.f2(0); // calls C2::f2(double) instead of C1::f2(int) + // S1 s1; + // l1.f2(s1); Won't compile because there is no suitable conversion from S1 to + // double. + C1 &l2{l1}; + l2.f1(0); // calls C1::f1(int) + + C4 l3; + l3.f1(0); // calls C1::f1(int) + l3.f1(0.0); // calls C3::f1(double) + l3.f2(0); // calls C1::f2(int) + l3.f2(0.0); // calls C3::f2(double) + S1 l4; + l3.f2(l4); // calls C1:f2(S1) +} + +class C5 : public C1 { +public: + void f1(double); // COMPLIANT + using C1::f1; // order of using and f1 declaration is not relevant + + void f2(double) override; // COMPLIANT + using C1::f2; // order of using and f2 declaration is not relevant +}; + +void f2() { + C5 c5; + c5.f1(0); // calls C1::f1(int) + c5.f1(0.0); // calls C5::f1(double) + c5.f2(0); // calls C1::f2(int) + c5.f2(0.0); // calls C5::f2(double) +} + +class C6 : public C1 { +public: + C6 &operator=(const C6 &); // COMPLIANT +}; + +class C7 : public C1 { + void f3(int); // COMPLIANT + + void f4(int); // COMPLIANT +}; \ No newline at end of file diff --git a/cpp/autosar/test/rules/A7-3-1/HiddenInheritedOverridableMemberFunction.expected b/cpp/common/test/rules/hiddeninheritedoverridablememberfunction/HiddenInheritedOverridableMemberFunction.expected similarity index 100% rename from cpp/autosar/test/rules/A7-3-1/HiddenInheritedOverridableMemberFunction.expected rename to cpp/common/test/rules/hiddeninheritedoverridablememberfunction/HiddenInheritedOverridableMemberFunction.expected diff --git a/cpp/common/test/rules/hiddeninheritedoverridablememberfunction/HiddenInheritedOverridableMemberFunction.ql b/cpp/common/test/rules/hiddeninheritedoverridablememberfunction/HiddenInheritedOverridableMemberFunction.ql new file mode 100644 index 0000000000..072f672efb --- /dev/null +++ b/cpp/common/test/rules/hiddeninheritedoverridablememberfunction/HiddenInheritedOverridableMemberFunction.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.hiddeninheritedoverridablememberfunction.HiddenInheritedOverridableMemberFunction + +class TestFileQuery extends HiddenInheritedOverridableMemberFunctionSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/hiddeninheritedoverridablememberfunction/test.cpp b/cpp/common/test/rules/hiddeninheritedoverridablememberfunction/test.cpp new file mode 100644 index 0000000000..c0904238c3 --- /dev/null +++ b/cpp/common/test/rules/hiddeninheritedoverridablememberfunction/test.cpp @@ -0,0 +1,94 @@ +struct S1 { + int i; +}; + +class C1 { +public: + void f1(int); + + virtual void f2(int); + virtual void f2(double); + virtual void f2(S1); + +private: + void f3(int); + void f4(int); +}; + +class C2 : public C1 { +public: + void f1(double); // NON_COMPLIANT + + void f2(double) override; // NON_COMPLIANT +}; + +class C3 : public C1 { +public: + void f2(char *); // NON_COMPLIANT +}; + +class C4 : public C1 { +public: + using C1::f1; + void f1(double); // COMPLIANT + + using C1::f2; + void f2(double) override; // COMPLIANT +}; + +namespace ns1 { +void f1(int); +} + +using ns1::f1; + +namespace ns1 { +void f1(double); // NON_COMPLIANT +} + +void f1() { + C2 l1; + l1.f1(0); // calls C2::f1(double) instead of C1::f1(int) + l1.f2(0); // calls C2::f2(double) instead of C1::f2(int) + // S1 s1; + // l1.f2(s1); Won't compile because there is no suitable conversion from S1 to + // double. + C1 &l2{l1}; + l2.f1(0); // calls C1::f1(int) + + C4 l3; + l3.f1(0); // calls C1::f1(int) + l3.f1(0.0); // calls C3::f1(double) + l3.f2(0); // calls C1::f2(int) + l3.f2(0.0); // calls C3::f2(double) + S1 l4; + l3.f2(l4); // calls C1:f2(S1) +} + +class C5 : public C1 { +public: + void f1(double); // COMPLIANT + using C1::f1; // order of using and f1 declaration is not relevant + + void f2(double) override; // COMPLIANT + using C1::f2; // order of using and f2 declaration is not relevant +}; + +void f2() { + C5 c5; + c5.f1(0); // calls C1::f1(int) + c5.f1(0.0); // calls C5::f1(double) + c5.f2(0); // calls C1::f2(int) + c5.f2(0.0); // calls C5::f2(double) +} + +class C6 : public C1 { +public: + C6 &operator=(const C6 &); // COMPLIANT +}; + +class C7 : public C1 { + void f3(int); // COMPLIANT + + void f4(int); // COMPLIANT +}; \ No newline at end of file diff --git a/cpp/autosar/test/rules/A12-1-1/ExplicitConstructorBaseClassInitialization.expected b/cpp/common/test/rules/initializeallvirtualbaseclasses/InitializeAllVirtualBaseClasses.expected similarity index 100% rename from cpp/autosar/test/rules/A12-1-1/ExplicitConstructorBaseClassInitialization.expected rename to cpp/common/test/rules/initializeallvirtualbaseclasses/InitializeAllVirtualBaseClasses.expected diff --git a/cpp/common/test/rules/initializeallvirtualbaseclasses/InitializeAllVirtualBaseClasses.ql b/cpp/common/test/rules/initializeallvirtualbaseclasses/InitializeAllVirtualBaseClasses.ql new file mode 100644 index 0000000000..89f720b125 --- /dev/null +++ b/cpp/common/test/rules/initializeallvirtualbaseclasses/InitializeAllVirtualBaseClasses.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.initializeallvirtualbaseclasses.InitializeAllVirtualBaseClasses + +class TestFileQuery extends InitializeAllVirtualBaseClassesSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/initializeallvirtualbaseclasses/test.cpp b/cpp/common/test/rules/initializeallvirtualbaseclasses/test.cpp new file mode 100644 index 0000000000..8e6b318b19 --- /dev/null +++ b/cpp/common/test/rules/initializeallvirtualbaseclasses/test.cpp @@ -0,0 +1,73 @@ +class Base {}; +class Derived : public Base { +public: + Derived() {} // NON_COMPLIANT - does not call Base() + Derived(int i) : Base() {} // COMPLIANT + Derived(int i, int j); // IGNORED - not defined, so we don't know +}; + +class Derived1 : public Base { +public: + Derived1() = default; // COMPLIANT - `default` does not have explicit + // initializers +}; + +class VirtualBase {}; + +class Derived2 : virtual public VirtualBase {}; + +class Derived3 : virtual public VirtualBase {}; + +class Derived4 : public Derived2, public Derived3 { +public: + Derived4() {} // NON_COMPLIANT - does not call Derived2(), Derived3() or + // VirtualBase() + Derived4(int i) // NON_COMPLIANT - does not call VirtualBase() + : Derived2(), Derived3() {} + Derived4(int i, int j) // COMPLIANT - calls VirtualBase() + : Derived2(), Derived3(), VirtualBase() {} +}; + +class NonTrivialBase { +public: + NonTrivialBase() = default; + NonTrivialBase(int i){}; + NonTrivialBase(int i, int j){}; +}; + +class Derived5 : public NonTrivialBase { +public: + Derived5() {} // NON_COMPLIANT - does not call NonTrivialBase() + Derived5(int i) : NonTrivialBase(i) {} // COMPLIANT + Derived5(int i, int j) : NonTrivialBase(i, j) {} // COMPLIANT +}; + +class MultipleInheritenceBase {}; + +class Child1 : public MultipleInheritenceBase {}; + +class Child2 : public MultipleInheritenceBase {}; + +class GrandChild : public Child1, public Child2 { + // no need to initialize MultipleInheritenceBase + GrandChild() : Child1(), Child2() {} // COMPLIANT +}; + +class Base2 {}; + +class Derived6 : public Base2 { +public: + Derived6() : b() {} // NON_COMPLIANT + +private: + Base2 b; +}; + +class Base3 {}; + +class Derived7 final : public Base3 { +public: + Derived7() = delete; // COMPLIANT + Derived7(const Derived7 &) = delete; // COMPLIANT + Derived7(Derived7 &&) = delete; // COMPLIANT +}; \ No newline at end of file diff --git a/cpp/autosar/test/rules/A8-5-4/ConfusingUseOfInitializerListConstructors.expected b/cpp/common/test/rules/initializerlistconstructoristheonlyconstructor/InitializerListConstructorIsTheOnlyConstructor.expected similarity index 100% rename from cpp/autosar/test/rules/A8-5-4/ConfusingUseOfInitializerListConstructors.expected rename to cpp/common/test/rules/initializerlistconstructoristheonlyconstructor/InitializerListConstructorIsTheOnlyConstructor.expected diff --git a/cpp/common/test/rules/initializerlistconstructoristheonlyconstructor/InitializerListConstructorIsTheOnlyConstructor.ql b/cpp/common/test/rules/initializerlistconstructoristheonlyconstructor/InitializerListConstructorIsTheOnlyConstructor.ql new file mode 100644 index 0000000000..a2b023a3dd --- /dev/null +++ b/cpp/common/test/rules/initializerlistconstructoristheonlyconstructor/InitializerListConstructorIsTheOnlyConstructor.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.initializerlistconstructoristheonlyconstructor.InitializerListConstructorIsTheOnlyConstructor + +class TestFileQuery extends InitializerListConstructorIsTheOnlyConstructorSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/A8-5-4/test.cpp b/cpp/common/test/rules/initializerlistconstructoristheonlyconstructor/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A8-5-4/test.cpp rename to cpp/common/test/rules/initializerlistconstructoristheonlyconstructor/test.cpp diff --git a/cpp/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected b/cpp/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected new file mode 100644 index 0000000000..b183ca7c42 --- /dev/null +++ b/cpp/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected @@ -0,0 +1,11 @@ +| test.cpp:21:14:21:19 | tmpvar | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:13:12:13:17 | call to getenv | call to getenv | test.cpp:17:13:17:18 | call to getenv | call to getenv | +| test.cpp:134:14:134:17 | temp | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:130:12:130:17 | call to getenv | call to getenv | test.cpp:131:11:131:16 | call to getenv | call to getenv | +| test.cpp:134:20:134:22 | tmp | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:131:11:131:16 | call to getenv | call to getenv | test.cpp:130:12:130:17 | call to getenv | call to getenv | +| test.cpp:165:14:165:26 | tmpvar_global | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:157:19:157:24 | call to getenv | call to getenv | test.cpp:161:20:161:25 | call to getenv | call to getenv | +| test.cpp:188:18:188:18 | r | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:185:7:185:15 | call to setlocale | call to setlocale | test.cpp:187:8:187:17 | call to localeconv | call to localeconv | +| test.cpp:208:10:208:15 | tmpvar | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:202:12:202:17 | call to getenv | call to getenv | test.cpp:206:3:206:8 | call to f11fun | call to f11fun | +| test.cpp:216:16:216:17 | r1 | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:214:14:214:18 | call to ctime | call to ctime | test.cpp:215:3:215:9 | call to asctime | call to asctime | +| test.cpp:226:16:226:17 | r1 | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:222:14:222:18 | call to ctime | call to ctime | test.cpp:225:14:225:20 | call to asctime | call to asctime | +| test.cpp:231:16:231:17 | r2 | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:225:14:225:20 | call to asctime | call to asctime | test.cpp:229:8:229:12 | call to ctime | call to ctime | +| test.cpp:240:16:240:17 | r1 | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:236:19:236:27 | call to localtime | call to localtime | test.cpp:239:19:239:24 | call to gmtime | call to gmtime | +| test.cpp:245:16:245:17 | r2 | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:239:19:239:24 | call to gmtime | call to gmtime | test.cpp:243:8:243:16 | call to localtime | call to localtime | diff --git a/cpp/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.ql b/cpp/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.ql new file mode 100644 index 0000000000..b82c43333a --- /dev/null +++ b/cpp/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.invalidatedenvstringpointers.InvalidatedEnvStringPointers + +class TestFileQuery extends InvalidatedEnvStringPointersSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/invalidatedenvstringpointers/test.cpp b/cpp/common/test/rules/invalidatedenvstringpointers/test.cpp new file mode 100644 index 0000000000..920d97c657 --- /dev/null +++ b/cpp/common/test/rules/invalidatedenvstringpointers/test.cpp @@ -0,0 +1,246 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +#include +#include +#include +#include +#include + +void f1(void) { + char *tmpvar; + char *tempvar; + + tmpvar = getenv("TMP"); + if (!tmpvar) { + /* Handle error */ + } + tempvar = getenv("TEMP"); + if (!tempvar) { + /* Handle error */ + } + if (strcmp(tmpvar, tempvar) == 0) { // NON_COMPLIANT + printf("TMP and TEMP are the same.\n"); + } else { + printf("TMP and TEMP are NOT the same.\n"); + } +} + +void f2(void) { + char *tmpvar; + char *tempvar; + + const char *temp = getenv("TMP"); + if (temp != NULL) { + tmpvar = (char *)malloc(strlen(temp) + 1); + if (tmpvar != NULL) { + strcpy(tmpvar, temp); + } else { + /* Handle error */ + } + } else { + /* Handle error */ + } + + temp = getenv("TEMP"); + if (temp != NULL) { + tempvar = (char *)malloc(strlen(temp) + 1); + if (tempvar != NULL) { + strcpy(tempvar, temp); + } else { + /* Handle error */ + } + } else { + /* Handle error */ + } + + if (strcmp(tmpvar, tempvar) == 0) { // COMPLIANT + printf("TMP and TEMP are the same.\n"); + } else { + printf("TMP and TEMP are NOT the same.\n"); + } + free(tmpvar); + free(tempvar); +} + +#define __STDC_WANT_LIB_EXT1__ 1 + +void f3(void) { + char *tmpvar; + char *tempvar; + + const char *temp = getenv("TMP"); + if (temp != NULL) { + tmpvar = strdup(temp); + if (tmpvar == NULL) { + /* Handle error */ + } + } else { + /* Handle error */ + } + + temp = getenv("TEMP"); + if (temp != NULL) { + tempvar = strdup(temp); + if (tempvar == NULL) { + /* Handle error */ + } + } else { + /* Handle error */ + } + + if (strcmp(tmpvar, tempvar) == 0) { // COMPLIANT + printf("TMP and TEMP are the same.\n"); + } else { + printf("TMP and TEMP are NOT the same.\n"); + } + free(tmpvar); + tmpvar = NULL; + free(tempvar); + tempvar = NULL; +} + +void f4(void) { + char *temp = getenv("VAR1"); + printf(temp); + temp = getenv("VAR2"); + printf(temp); // COMPLIANT +} + +void f5(void) { + const char *envVars[] = { + "v1", + "v2", + "v3", + }; + for (int i = 0; i < 3; i++) { + char *temp = getenv(envVars[i]); + printf(temp); // COMPLIANT + } +} + +void f5b(void) { + const char *envVars[] = { + "v1", + "v2", + "v3", + }; + char *temp; + char *tmp; + for (int i = 0; i < 3; i++) { + temp = getenv(envVars[i]); + tmp = getenv(envVars[i]); + } + + if (strcmp(temp, tmp) == 0) { // NON_COMPLIANT + printf("TMP and TEMP are the same.\n"); + } else { + printf("TMP and TEMP are NOT the same.\n"); + } +} + +void f6(void) { + const char *envVars[] = { + "v1", + "v2", + "v3", + }; + char *temp[3]; + for (int i = 0; i < 3; i++) { + temp[i] = getenv(envVars[i]); + } + printf(temp[0]); // NON_COMPLIANT[FALSE_NEGATIVE] +} + +char *tmpvar_global; +char *tempvar_global; +void f7(void) { + tmpvar_global = getenv("TMP"); + if (!tmpvar_global) { + /* Handle error */ + } + tempvar_global = getenv("TEMP"); + if (!tempvar_global) { + /* Handle error */ + } + if (strcmp(tmpvar_global, tempvar_global) == 0) { // NON_COMPLIANT + printf("TMP and TEMP are the same.\n"); + } else { + printf("TMP and TEMP are NOT the same.\n"); + } +} + +extern void f8fun(); +void f8(void) { + char *temp = getenv("VAR1"); + printf(temp); + f8fun(); // this function might call getenv() + temp = getenv("VAR2"); + printf(temp); // NON_COMPLIANT[FALSE_NEGATIVE] +} + +void f9(void) { + const char *r; + struct lconv *lc; + char c[128]; + r = setlocale(LC_ALL, "ja_JP.UTF-8"); + strcpy(c, r); + lc = localeconv(); + printf("%s\n", r); // NON_COMPLIANT + printf("%s\n", c); // COMPLIANT + printf("%s\n", lc->currency_symbol); // COMPLIANT +} + +void f10(void) { + struct tm tm = *localtime(&(time_t){time(NULL)}); + printf("%s", asctime(&tm)); // COMPLIANT +} + +void f11fun(void) { char *tempvar = getenv("TEMP"); } +void f11(void) { + char *tmpvar; + + tmpvar = getenv("TMP"); + if (!tmpvar) { + /* Handle error */ + } + f11fun(); + + printf(tmpvar); // NON_COMPLIANT +} + +void f12(void) { + time_t rawtime; + time(&rawtime); + char *r1 = ctime(&rawtime); + asctime(localtime(&rawtime)); + printf("%s", r1); // NON_COMPLIANT +} + +void f13(void) { + time_t rawtime; + time(&rawtime); + char *r1 = ctime(&rawtime); + printf("%s", r1); // COMPLIANT + + char *r2 = asctime(localtime(&rawtime)); + printf("%s", r1); // NON_COMPLIANT + printf("%s", r2); // COMPLIANT + + r1 = ctime(&rawtime); + printf("%s", r1); // COMPLIANT + printf("%s", r2); // NON_COMPLIANT +} + +void f14(void) { + time_t rawtime; + struct tm *r1 = localtime(&rawtime); + printf("%d", r1->tm_year); // COMPLIANT + + struct tm *r2 = gmtime(&rawtime); + printf("%s", r1->tm_year); // NON_COMPLIANT + printf("%s", r2->tm_year); // COMPLIANT + + r1 = localtime(&rawtime); + printf("%s", r1->tm_year); // COMPLIANT + printf("%s", r2->tm_year); // NON_COMPLIANT +} \ No newline at end of file diff --git a/cpp/common/test/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.expected b/cpp/common/test/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.expected new file mode 100644 index 0000000000..9061fcfbc4 --- /dev/null +++ b/cpp/common/test/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.expected @@ -0,0 +1,2 @@ +| test.cpp:15:19:15:24 | call to getenv | The value of variable $@ might become invalid after a subsequent call to function `getenv`. | test.cpp:12:7:12:19 | tmpvar_global | tmpvar_global | +| test.cpp:18:20:18:25 | call to getenv | The value of variable $@ might become invalid after a subsequent call to function `getenv`. | test.cpp:9:9:9:20 | tmpvar_field | tmpvar_field | diff --git a/cpp/common/test/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.ql b/cpp/common/test/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.ql new file mode 100644 index 0000000000..7a56af210d --- /dev/null +++ b/cpp/common/test/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.invalidatedenvstringpointerswarn.InvalidatedEnvStringPointersWarn + +class TestFileQuery extends InvalidatedEnvStringPointersWarnSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/invalidatedenvstringpointerswarn/test.cpp b/cpp/common/test/rules/invalidatedenvstringpointerswarn/test.cpp new file mode 100644 index 0000000000..5001e538a1 --- /dev/null +++ b/cpp/common/test/rules/invalidatedenvstringpointerswarn/test.cpp @@ -0,0 +1,21 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +#include +#include +#include +#include + +struct test_struct { + char *tmpvar_field; +}; + +char *tmpvar_global; + +void f1(void) { + tmpvar_global = getenv("TMP"); // NON_COMPLIANT + + struct test_struct s; + s.tmpvar_field = getenv("TEMP"); // NON_COMPLIANT + + char *tmpvar_local = getenv("TEMP"); // COMPLIANT +} diff --git a/cpp/autosar/test/rules/A2-7-1/SingleLineCommentEndsWithSlash.expected b/cpp/common/test/rules/linesplicingusedincomments/LineSplicingUsedInComments.expected similarity index 100% rename from cpp/autosar/test/rules/A2-7-1/SingleLineCommentEndsWithSlash.expected rename to cpp/common/test/rules/linesplicingusedincomments/LineSplicingUsedInComments.expected diff --git a/cpp/common/test/rules/linesplicingusedincomments/LineSplicingUsedInComments.ql b/cpp/common/test/rules/linesplicingusedincomments/LineSplicingUsedInComments.ql new file mode 100644 index 0000000000..55803eab88 --- /dev/null +++ b/cpp/common/test/rules/linesplicingusedincomments/LineSplicingUsedInComments.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.linesplicingusedincomments.LineSplicingUsedInComments + +class TestFileQuery extends LineSplicingUsedInCommentsSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/A2-7-1/test.cpp b/cpp/common/test/rules/linesplicingusedincomments/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A2-7-1/test.cpp rename to cpp/common/test/rules/linesplicingusedincomments/test.cpp diff --git a/cpp/autosar/test/rules/M6-3-1/LoopCompoundCondition.expected b/cpp/common/test/rules/loopcompoundcondition/LoopCompoundCondition.expected similarity index 100% rename from cpp/autosar/test/rules/M6-3-1/LoopCompoundCondition.expected rename to cpp/common/test/rules/loopcompoundcondition/LoopCompoundCondition.expected diff --git a/cpp/common/test/rules/loopcompoundcondition/LoopCompoundCondition.ql b/cpp/common/test/rules/loopcompoundcondition/LoopCompoundCondition.ql new file mode 100644 index 0000000000..3961d76d15 --- /dev/null +++ b/cpp/common/test/rules/loopcompoundcondition/LoopCompoundCondition.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.loopcompoundcondition.LoopCompoundCondition + +class TestFileQuery extends LoopCompoundConditionSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/M6-3-1/test.cpp b/cpp/common/test/rules/loopcompoundcondition/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M6-3-1/test.cpp rename to cpp/common/test/rules/loopcompoundcondition/test.cpp diff --git a/cpp/common/test/rules/lowercaselstartsinliteralsuffix/LowercaseLStartsInLiteralSuffix.expected b/cpp/common/test/rules/lowercaselstartsinliteralsuffix/LowercaseLStartsInLiteralSuffix.expected new file mode 100644 index 0000000000..545b6d3441 --- /dev/null +++ b/cpp/common/test/rules/lowercaselstartsinliteralsuffix/LowercaseLStartsInLiteralSuffix.expected @@ -0,0 +1,16 @@ +| test.cpp:5:10:5:11 | 0 | Lowercase 'l' used as a literal suffix. | +| test.cpp:6:10:6:12 | 0 | Lowercase 'l' used as a literal suffix. | +| test.cpp:9:10:9:12 | 0 | Lowercase 'l' used as a literal suffix. | +| test.cpp:10:10:10:12 | 0 | Lowercase 'l' used as a literal suffix. | +| test.cpp:15:11:15:12 | 0 | Lowercase 'l' used as a literal suffix. | +| test.cpp:16:11:16:13 | 0 | Lowercase 'l' used as a literal suffix. | +| test.cpp:19:11:19:13 | 0 | Lowercase 'l' used as a literal suffix. | +| test.cpp:20:11:20:13 | 0 | Lowercase 'l' used as a literal suffix. | +| test.cpp:25:10:25:14 | 1 | Lowercase 'l' used as a literal suffix. | +| test.cpp:26:10:26:15 | 1 | Lowercase 'l' used as a literal suffix. | +| test.cpp:29:10:29:15 | 1 | Lowercase 'l' used as a literal suffix. | +| test.cpp:30:10:30:15 | 1 | Lowercase 'l' used as a literal suffix. | +| test.cpp:35:11:35:14 | 1 | Lowercase 'l' used as a literal suffix. | +| test.cpp:36:11:36:15 | 1 | Lowercase 'l' used as a literal suffix. | +| test.cpp:39:11:39:15 | 1 | Lowercase 'l' used as a literal suffix. | +| test.cpp:40:11:40:15 | 1 | Lowercase 'l' used as a literal suffix. | diff --git a/cpp/common/test/rules/lowercaselstartsinliteralsuffix/LowercaseLStartsInLiteralSuffix.ql b/cpp/common/test/rules/lowercaselstartsinliteralsuffix/LowercaseLStartsInLiteralSuffix.ql new file mode 100644 index 0000000000..ab353ca8a9 --- /dev/null +++ b/cpp/common/test/rules/lowercaselstartsinliteralsuffix/LowercaseLStartsInLiteralSuffix.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.lowercaselstartsinliteralsuffix.LowercaseLStartsInLiteralSuffix + +class TestFileQuery extends LowercaseLStartsInLiteralSuffixSharedQuery, TestQuery { } diff --git a/c/misra/test/rules/RULE-7-3/cpp/README.md b/cpp/common/test/rules/lowercaselstartsinliteralsuffix/README.md similarity index 100% rename from c/misra/test/rules/RULE-7-3/cpp/README.md rename to cpp/common/test/rules/lowercaselstartsinliteralsuffix/README.md diff --git a/cpp/common/test/rules/lowercaselstartsinliteralsuffix/test.cpp b/cpp/common/test/rules/lowercaselstartsinliteralsuffix/test.cpp new file mode 100644 index 0000000000..27be2a327d --- /dev/null +++ b/cpp/common/test/rules/lowercaselstartsinliteralsuffix/test.cpp @@ -0,0 +1,46 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +int x = false; // COMPLIANT - reported as FP in #319 +int a1 = 0L; // COMPLIANT +int a2 = 0l; // NON_COMPLIANT +int a3 = 0ll; // NON_COMPLIANT +int a4 = 0LL; // COMPLIANT +int a5 = 0uL; // COMPLIANT +int a6 = 0ul; // NON_COMPLIANT +int a7 = 0lu; // NON_COMPLIANT +int a8 = 0Lu; // COMPLIANT +int a9 = 0LU; // COMPLIANT + +long b1 = 0L; // COMPLIANT +long b2 = 0l; // NON_COMPLIANT +long b3 = 0ll; // NON_COMPLIANT +long b4 = 0LL; // COMPLIANT +long b5 = 0uL; // COMPLIANT +long b6 = 0ul; // NON_COMPLIANT +long b7 = 0lu; // NON_COMPLIANT +long b8 = 0Lu; // COMPLIANT +long b9 = 0LU; // COMPLIANT + +int c1 = 0x01L; // COMPLIANT +int c2 = 0x01l; // NON_COMPLIANT +int c3 = 0x01ll; // NON_COMPLIANT +int c4 = 0x01LL; // COMPLIANT +int c5 = 0x01uL; // COMPLIANT +int c6 = 0x01ul; // NON_COMPLIANT +int c7 = 0x01lu; // NON_COMPLIANT +int c8 = 0x01Lu; // COMPLIANT +int c9 = 0x01LU; // COMPLIANT + +long d1 = 001L; // COMPLIANT +long d2 = 001l; // NON_COMPLIANT +long d3 = 001ll; // NON_COMPLIANT +long d4 = 001LL; // COMPLIANT +long d5 = 001uL; // COMPLIANT +long d6 = 001ul; // NON_COMPLIANT +long d7 = 001lu; // NON_COMPLIANT +long d8 = 001Lu; // COMPLIANT +long d9 = 001LU; // COMPLIANT + +char *e1 = ""; +char *e2 = "ul"; +char *e3 = "UL"; \ No newline at end of file diff --git a/cpp/autosar/test/rules/M18-2-1/MacroOffsetofUsed.expected b/cpp/common/test/rules/macrooffsetofused/MacroOffsetofUsed.expected similarity index 100% rename from cpp/autosar/test/rules/M18-2-1/MacroOffsetofUsed.expected rename to cpp/common/test/rules/macrooffsetofused/MacroOffsetofUsed.expected diff --git a/cpp/common/test/rules/macrooffsetofused/MacroOffsetofUsed.expected.gcc b/cpp/common/test/rules/macrooffsetofused/MacroOffsetofUsed.expected.gcc new file mode 100644 index 0000000000..87bf6e1b01 --- /dev/null +++ b/cpp/common/test/rules/macrooffsetofused/MacroOffsetofUsed.expected.gcc @@ -0,0 +1 @@ +| test.cpp:9:32:9:51 | offsetof(TYPE,MEMBER) | Use of banned macro offsetof. | diff --git a/cpp/autosar/test/rules/M18-2-1/MacroOffsetofUsed.expected.qcc b/cpp/common/test/rules/macrooffsetofused/MacroOffsetofUsed.expected.qcc similarity index 100% rename from cpp/autosar/test/rules/M18-2-1/MacroOffsetofUsed.expected.qcc rename to cpp/common/test/rules/macrooffsetofused/MacroOffsetofUsed.expected.qcc diff --git a/cpp/common/test/rules/macrooffsetofused/MacroOffsetofUsed.ql b/cpp/common/test/rules/macrooffsetofused/MacroOffsetofUsed.ql new file mode 100644 index 0000000000..44e30b1a2f --- /dev/null +++ b/cpp/common/test/rules/macrooffsetofused/MacroOffsetofUsed.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.macrooffsetofused.MacroOffsetofUsed + +class TestFileQuery extends MacroOffsetofUsedSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/M18-2-1/test.cpp b/cpp/common/test/rules/macrooffsetofused/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M18-2-1/test.cpp rename to cpp/common/test/rules/macrooffsetofused/test.cpp diff --git a/cpp/common/test/rules/macroparameterfollowinghash/MacroParameterFollowingHash.expected b/cpp/common/test/rules/macroparameterfollowinghash/MacroParameterFollowingHash.expected new file mode 100644 index 0000000000..6a3d5c5da7 --- /dev/null +++ b/cpp/common/test/rules/macroparameterfollowinghash/MacroParameterFollowingHash.expected @@ -0,0 +1 @@ +| test.cpp:27:1:27:29 | #define MACROTHIRTEEN(X) #X ## X | Macro definition uses an # operator followed by a ## operator. | diff --git a/cpp/common/test/rules/macroparameterfollowinghash/MacroParameterFollowingHash.ql b/cpp/common/test/rules/macroparameterfollowinghash/MacroParameterFollowingHash.ql new file mode 100644 index 0000000000..f753b75463 --- /dev/null +++ b/cpp/common/test/rules/macroparameterfollowinghash/MacroParameterFollowingHash.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.macroparameterfollowinghash.MacroParameterFollowingHash + +class TestFileQuery extends MacroParameterFollowingHashSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/macroparameterfollowinghash/test.cpp b/cpp/common/test/rules/macroparameterfollowinghash/test.cpp new file mode 100644 index 0000000000..5e6f187445 --- /dev/null +++ b/cpp/common/test/rules/macroparameterfollowinghash/test.cpp @@ -0,0 +1,29 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +#define MACROONE 1 // COMPLIANT + +#define MACROTWO '#\'-#' + '#' // COMPLIANT + +#define MACROTHREE "##" // COMPLIANT + +#define MACROFOUR "##" + "#" // COMPLIANT + +#define MACROFIVE(X) #X // COMPLIANT + +#define MACROSIX(X, Y) X##Y // COMPLIANT + +#define MACROSEVEN "##'" #"#" // COMPLIANT + +#define MACROEIGHT '##' #"#" // COMPLIANT + +#define MACRONINE "##\"\"" + "#" // COMPLIANT + +#define MACROTEN "##\"\"'" + "#" // COMPLIANT + +#define MACROELEVEN(X) X #X #X // COMPLIANT + +#define MACROTWELVE(X) X##X##X // COMPLIANT + +#define MACROTHIRTEEN(X) #X##X // NON_COMPLIANT + +#define MACROFOURTEEN '#\'-#' + 1 #1 #1 + '#' // COMPLIANT \ No newline at end of file diff --git a/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected new file mode 100644 index 0000000000..45bc2466b6 --- /dev/null +++ b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected @@ -0,0 +1,113 @@ +problems +| test.cpp:12:8:12:9 | l2 | test.cpp:8:14:8:20 | ... / ... | test.cpp:12:8:12:9 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:13:8:13:9 | l3 | test.cpp:8:14:8:20 | ... / ... | test.cpp:13:8:13:9 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:18:20:18:21 | l2 | test.cpp:8:14:8:20 | ... / ... | test.cpp:18:3:18:22 | l2 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:19:20:19:21 | l3 | test.cpp:8:14:8:20 | ... / ... | test.cpp:19:3:19:22 | l3 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:29:19:29:20 | l2 | test.cpp:8:14:8:20 | ... / ... | test.cpp:29:19:29:20 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:30:19:30:20 | l3 | test.cpp:8:14:8:20 | ... / ... | test.cpp:30:19:30:20 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:40:20:40:21 | l7 | test.cpp:33:14:34:15 | ... / ... | test.cpp:40:3:40:22 | l7 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:33:14:34:15 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:64:9:64:15 | ... / ... | test.cpp:63:5:64:16 | ... / ... | test.cpp:63:5:64:16 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:64:9:64:15 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:70:9:70:17 | ... / ... | test.cpp:69:5:70:18 | ... / ... | test.cpp:69:5:70:18 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:70:9:70:17 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:76:31:76:39 | ... / ... | test.cpp:76:14:76:40 | ... / ... | test.cpp:76:14:76:40 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:76:31:76:39 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:79:35:79:43 | ... / ... | test.cpp:79:18:79:44 | ... / ... | test.cpp:79:18:79:44 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:79:35:79:43 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:83:22:83:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:83:5:83:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:91:22:91:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:91:5:91:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:95:22:95:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:95:5:95:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:97:22:97:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:97:5:97:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:103:22:103:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:103:5:103:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:109:22:109:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:109:5:109:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:115:22:115:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:115:5:115:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:118:38:118:40 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:118:21:118:41 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:127:26:127:28 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:127:9:127:29 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:133:26:133:28 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:133:9:133:29 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:188:7:189:17 | ... / ... | test.cpp:187:3:189:18 | ... / ... | test.cpp:187:3:189:18 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:188:7:189:17 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:202:44:202:44 | p | test.cpp:216:51:216:59 | ... / ... | test.cpp:202:27:202:45 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:216:51:216:59 | ... / ... | from division by zero | test.cpp:216:6:216:24 | addInfThenCastToInt | addInfThenCastToInt | +| test.cpp:202:44:202:44 | p | test.cpp:220:13:221:15 | ... / ... | test.cpp:202:27:202:45 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:220:13:221:15 | ... / ... | from division by zero | test.cpp:219:6:219:7 | f2 | f2 | +| test.cpp:202:44:202:44 | p | test.cpp:231:19:231:27 | ... / ... | test.cpp:202:27:202:45 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:231:19:231:27 | ... / ... | from division by zero | test.cpp:219:6:219:7 | f2 | f2 | +| test.cpp:212:30:212:30 | p | test.cpp:227:25:227:33 | ... / ... | test.cpp:212:13:212:31 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:227:25:227:33 | ... / ... | from division by zero | test.cpp:219:6:219:7 | f2 | f2 | +edges +| test.cpp:8:14:8:20 | ... / ... | test.cpp:8:14:8:20 | ... / ... | provenance | | +| test.cpp:8:14:8:20 | ... / ... | test.cpp:9:14:9:16 | - ... | provenance | Config | +| test.cpp:8:14:8:20 | ... / ... | test.cpp:12:8:12:9 | l2 | provenance | | +| test.cpp:8:14:8:20 | ... / ... | test.cpp:18:3:18:22 | l2 | provenance | | +| test.cpp:8:14:8:20 | ... / ... | test.cpp:29:19:29:20 | l2 | provenance | | +| test.cpp:9:14:9:16 | - ... | test.cpp:9:14:9:16 | - ... | provenance | | +| test.cpp:9:14:9:16 | - ... | test.cpp:13:8:13:9 | l3 | provenance | | +| test.cpp:9:14:9:16 | - ... | test.cpp:19:3:19:22 | l3 | provenance | | +| test.cpp:9:14:9:16 | - ... | test.cpp:30:19:30:20 | l3 | provenance | | +| test.cpp:33:14:34:15 | ... / ... | test.cpp:33:14:34:15 | ... / ... | provenance | | +| test.cpp:33:14:34:15 | ... / ... | test.cpp:40:3:40:22 | l7 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:81:15:81:21 | ... / ... | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:83:5:83:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:91:5:91:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:95:5:95:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:97:5:97:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:103:5:103:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:109:5:109:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:115:5:115:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:118:21:118:41 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:127:9:127:29 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:133:9:133:29 | l12 | provenance | | +| test.cpp:202:22:202:22 | p | test.cpp:202:27:202:45 | p | provenance | | +| test.cpp:210:34:210:34 | p | test.cpp:212:13:212:31 | p | provenance | | +| test.cpp:216:32:216:32 | p | test.cpp:216:47:216:59 | ... + ... | provenance | Config | +| test.cpp:216:47:216:59 | ... + ... | test.cpp:202:22:202:22 | p | provenance | | +| test.cpp:216:47:216:59 | ... + ... | test.cpp:202:22:202:22 | p | provenance | | +| test.cpp:216:51:216:59 | ... / ... | test.cpp:216:47:216:59 | ... + ... | provenance | Config | +| test.cpp:220:13:221:15 | ... / ... | test.cpp:202:22:202:22 | p | provenance | | +| test.cpp:227:25:227:33 | ... / ... | test.cpp:210:34:210:34 | p | provenance | | +| test.cpp:231:19:231:27 | ... / ... | test.cpp:231:19:231:27 | ... / ... | provenance | | +| test.cpp:231:19:231:27 | ... / ... | test.cpp:233:21:233:31 | ... + ... | provenance | Config | +| test.cpp:233:21:233:31 | ... + ... | test.cpp:233:21:233:31 | ... + ... | provenance | | +| test.cpp:233:21:233:31 | ... + ... | test.cpp:235:13:235:21 | middleInf | provenance | | +| test.cpp:233:21:233:31 | ... + ... | test.cpp:237:23:237:31 | middleInf | provenance | | +| test.cpp:235:13:235:21 | middleInf | test.cpp:202:22:202:22 | p | provenance | | +| test.cpp:237:23:237:31 | middleInf | test.cpp:216:32:216:32 | p | provenance | | +nodes +| test.cpp:8:14:8:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:8:14:8:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:9:14:9:16 | - ... | semmle.label | - ... | +| test.cpp:9:14:9:16 | - ... | semmle.label | - ... | +| test.cpp:12:8:12:9 | l2 | semmle.label | l2 | +| test.cpp:13:8:13:9 | l3 | semmle.label | l3 | +| test.cpp:18:3:18:22 | l2 | semmle.label | l2 | +| test.cpp:19:3:19:22 | l3 | semmle.label | l3 | +| test.cpp:29:19:29:20 | l2 | semmle.label | l2 | +| test.cpp:30:19:30:20 | l3 | semmle.label | l3 | +| test.cpp:33:14:34:15 | ... / ... | semmle.label | ... / ... | +| test.cpp:33:14:34:15 | ... / ... | semmle.label | ... / ... | +| test.cpp:40:3:40:22 | l7 | semmle.label | l7 | +| test.cpp:63:5:64:16 | ... / ... | semmle.label | ... / ... | +| test.cpp:69:5:70:18 | ... / ... | semmle.label | ... / ... | +| test.cpp:76:14:76:40 | ... / ... | semmle.label | ... / ... | +| test.cpp:79:18:79:44 | ... / ... | semmle.label | ... / ... | +| test.cpp:81:15:81:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:81:15:81:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:83:5:83:25 | l12 | semmle.label | l12 | +| test.cpp:91:5:91:25 | l12 | semmle.label | l12 | +| test.cpp:95:5:95:25 | l12 | semmle.label | l12 | +| test.cpp:97:5:97:25 | l12 | semmle.label | l12 | +| test.cpp:103:5:103:25 | l12 | semmle.label | l12 | +| test.cpp:109:5:109:25 | l12 | semmle.label | l12 | +| test.cpp:115:5:115:25 | l12 | semmle.label | l12 | +| test.cpp:118:21:118:41 | l12 | semmle.label | l12 | +| test.cpp:127:9:127:29 | l12 | semmle.label | l12 | +| test.cpp:133:9:133:29 | l12 | semmle.label | l12 | +| test.cpp:187:3:189:18 | ... / ... | semmle.label | ... / ... | +| test.cpp:202:22:202:22 | p | semmle.label | p | +| test.cpp:202:27:202:45 | p | semmle.label | p | +| test.cpp:210:34:210:34 | p | semmle.label | p | +| test.cpp:212:13:212:31 | p | semmle.label | p | +| test.cpp:216:32:216:32 | p | semmle.label | p | +| test.cpp:216:47:216:59 | ... + ... | semmle.label | ... + ... | +| test.cpp:216:47:216:59 | ... + ... | semmle.label | ... + ... | +| test.cpp:216:51:216:59 | ... / ... | semmle.label | ... / ... | +| test.cpp:220:13:221:15 | ... / ... | semmle.label | ... / ... | +| test.cpp:227:25:227:33 | ... / ... | semmle.label | ... / ... | +| test.cpp:231:19:231:27 | ... / ... | semmle.label | ... / ... | +| test.cpp:231:19:231:27 | ... / ... | semmle.label | ... / ... | +| test.cpp:233:21:233:31 | ... + ... | semmle.label | ... + ... | +| test.cpp:233:21:233:31 | ... + ... | semmle.label | ... + ... | +| test.cpp:235:13:235:21 | middleInf | semmle.label | middleInf | +| test.cpp:237:23:237:31 | middleInf | semmle.label | middleInf | +subpaths diff --git a/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql new file mode 100644 index 0000000000..f0d160a650 --- /dev/null +++ b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.misuseofinfinitefloatingpointvalue.MisuseOfInfiniteFloatingPointValue + +class TestFileQuery extends MisuseOfInfiniteFloatingPointValueSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/test.cpp b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/test.cpp new file mode 100644 index 0000000000..a0624ccbf3 --- /dev/null +++ b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/test.cpp @@ -0,0 +1,239 @@ +#include + +float getFloat() { return 1.0; } + +// Parameter could be infinity +void f1(float p1) { + float l1 = 1; + float l2 = 1.0 / 0; + float l3 = -l2; + + 10 / l1; // COMPLIANT + 10 / l2; // NON_COMPLIANT: Underflows to zero + 10 / l3; // NON_COMPLIANT: Underflow to negative zero + 10 / p1; // COMPLIANT: Reduce false positives by assuming not infinity + 10 / getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + static_cast(l1); // COMPLIANT + static_cast(l2); // NON_COMPLIANT + static_cast(l3); // NON_COMPLIANT + static_cast( + p1); // COMPLIANT: Reduce false positives by assuming not infinity + static_cast( + getFloat()); // COMPLIANT: Reduce false positives by assuming not infinity + + // Not NaN: + float l4 = l1 / l1; // COMPLIANT + + // NaN because of infinity divided by itself: + float l5 = l2 / l2; // NON_COMPLIANT: Division by infinity not allowed. + float l6 = l3 / l3; // NON_COMPLIANT: Division by infinity not allowed. + + // NaN because of zero divided by itself: + float l7 = getFloat() / + p1; // COMPLIANT: Reduce false positives by assuming not infinity + float l8 = 0.0 / 0.0; + + static_cast(l4); // COMPLIANT + static_cast(l5); // COMPLIANT: Casting NaN to int + static_cast(l6); // COMPLIANT: Casting NaN to int + static_cast(l7); // NON_COMPLIANT: Casting Infinity to int + static_cast(l8); // COMPLIANT: Casting NaN to int + + l4 == 0; // COMPLIANT + l4 != 0; // COMPLIANT + l4 <= 0; // COMPLIANT + l4 < 0; // COMPLIANT + l4 >= 0; // COMPLIANT + l5 == 0; // NON_COMPLIANT: Comparison with NaN always false + l5 != 0; // NON_COMPLIANT: Comparison with NaN always false + l5 < 0; // NON_COMPLIANT: Comparison with NaN always false + l5 <= 0; // NON_COMPLIANT: Comparison with NaN always false + l5 > 0; // NON_COMPLIANT: Comparison with NaN always false + l5 >= 0; // NON_COMPLIANT: Comparison with NaN always false + l6 == 0; // NON_COMPLIANT: Comparison with NaN always false + l7 == 0; // NON_COMPLIANT: Comparison with NaN always false + l8 == 0; // NON_COMPLIANT: Comparison with NaN always false + + // Guards + float l9 = 0; + if (l9 != 0) { + static_cast(l9 / l9); // COMPLIANT: l9 is not zero + } else { + static_cast( + l9 / l9); // NON_COMPLIANT[False positive]: Guarded to not be NaN + } + + float l10 = 0; + if (l10 == 0) { + static_cast( + l10 / l10); // NON_COMPLIANT[False positive]: Casting NaN to integer + } else { + static_cast(l10 / l10); // COMPLIANT: Guarded to not be NaN + } + + float l11 = 0; + l11 == 0 ? static_cast(l11 / l11) : 0; // NON_COMPLIANT[False positive] + l11 == 0 ? 0 : static_cast(l11 / l11); // COMPLIANT + l11 != 0 ? static_cast(l11 / l11) : 0; // COMPLIANT + l11 != 0 ? 0 : static_cast(l11 / l11); // NON_COMPLIANT[False positive] + + float l12 = 1.0 / 0; + if (std::isinf(l12)) { + static_cast(l12); // NON_COMPLIANT: Casting Infinity to integer + } else { + static_cast(l12); // COMPLIANT: Guarded not to be Infinity + } + + if (!std::isinf(l12)) { + static_cast(l12); // COMPLIANT: Guarded not to be Infinity + } else { + static_cast(l12); // NON_COMPLIANT: Casting Infinity to integer + } + + if (std::isinf(l12) == 1) { + static_cast(l12); // NON_COMPLIANT: Must be +Infinity + } else { + static_cast(l12); // NON_COMPLIANT: May be -Infinity + } + + if (std::isfinite(l12)) { + static_cast(l12); // COMPLIANT: Guarded not to be Infinity + } else { + static_cast(l12); // NON_COMPLIANT: Casting Infinity to integer + } + + if (std::isnormal(l12)) { + static_cast(l12); // COMPLIANT: Guarded not to be Infinity + } else { + static_cast(l12); // NON_COMPLIANT: Casting Infinity to integer + } + + if (std::isnan(l12)) { + static_cast(l12); // COMPLIANT: Guarded not to be Infinity + } else { + static_cast(l12); // NON_COMPLIANT: Casting Infinity to integer + } + + std::isinf(l12) ? static_cast(l12) + : 0; // NON_COMPLIANT: Check on wrong branch + std::isinf(l12) + ? 0 + : static_cast(l12); // COMPLIANT: Checked not infinite before use + std::isfinite(l12) ? static_cast(l12) + : 0; // COMPLIANT: Checked finite before use + std::isfinite(l12) + ? 0 + : static_cast(l12); // NON_COMPLIANT: Checked on wrong branch + std::isnan(l12) + ? static_cast(l12) + : 0; // COMPLIANT: Checked NaN, therefore not infinite, before use + std::isnan(l12) + ? 0 + : static_cast(l12); // NON_COMPLIANT: Check on wrong branch + + float l13 = 0.0 / 0; + if (std::isinf(l13)) { + static_cast(l13); // COMPLIANT: Guarded not to be NaN + } else { + static_cast(l13); // COMPLIANT: Casting NaN to integer + } + + if (std::isinf(l13) == 1) { + static_cast( + l13); // COMPLIANT: Guarded not to be NaN (must be +Infinity) + } else { + static_cast(l13); // COMPLIANT: Casting NaN to integer + } + + if (std::isfinite(l13)) { + static_cast(l13); // COMPLIANT: Guarded not to be NaN + } else { + static_cast(l13); // COMPLIANT: Casting NaN to integer + } + + if (std::isnormal(l13)) { + static_cast(l13); // COMPLIANT: Guarded not to be NaN + } else { + static_cast(l13); // COMPLIANT: Casting NaN to integer + } + + if (std::isnan(l13)) { + static_cast(l13); // COMPLIANT: Casting NaN to integer + } else { + static_cast(l13); // COMPLIANT: Guarded not to be NaN + } + + std::isinf(l13) + ? static_cast(l13) + : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use + std::isinf(l13) ? 0 + : static_cast(l13); // COMPLIANT: Check on wrong branch + std::isfinite(l13) ? static_cast(l13) + : 0; // COMPLIANT: Checked finite before use + std::isfinite(l13) + ? 0 + : static_cast(l13); // COMPLIANT: Checked on wrong branch + std::isnan(l13) ? static_cast(l13) + : 0; // COMPLIANT: Check on wrong branch + std::isnan(l13) + ? 0 + : static_cast(l13); // COMPLIANT: Checked not NaN before use + + static_cast( + std::pow(2, p1)); // NON_COMPLIANT[False negative]: likely to be Infinity + static_cast( + std::pow(2, std::sin(p1))); // COMPLIANT: not likely to be Infinity + static_cast( + 1 / std::sin( + p1)); // NON_COMPLIANT: possible infinity from zero in denominator + static_cast(1 / + std::log(p1)); // COMPLIANT: not possibly zero in denominator + static_cast(std::pow(p1, p1)); // COMPLIANT: NaN if p1 is zero + if (p1 != 0) { + static_cast(std::pow(p1, p1)); // COMPLIANT: p1 is not zero + } + + static_cast(std::acos(p1)); // COMPLIANT: NaN if p1 is not within -1..1 + static_cast( + std::acos(std::cos(p1))); // COMPLIANT: cos(p1) is within -1..1 +} + +void castToInt(float p) { static_cast(p); } + +void checkBeforeCastToInt(float p) { + if (std::isfinite(p)) { + castToInt(p); + } +} + +void castToIntToFloatToInt(float p) { + // This should be reported as a violation, but not downstream from here. + castToInt(static_cast(p)); +} + +void addOneThenCastToInt(float p) { castToInt(p + 1); } +void addInfThenCastToInt(float p) { castToInt(p + 1.0 / 0.0); } +void addNaNThenCastToInt(float p) { castToInt(p + 0.0 / 0.0); } + +void f2() { + castToInt(1.0 / + 0.0); // NON_COMPLIANT: Infinity flows to denominator in division + castToInt(0.0 / 0.0); // COMPLIANT + checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT + checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT + addOneThenCastToInt(1.0 / 0.0); // NON_COMPLIANT[False negative] + addOneThenCastToInt(0.0 / 0.0); // NON_COMPLIANT + castToIntToFloatToInt(1.0 / 0.0); // NON_COMPLIANT + castToIntToFloatToInt(0.0 / 0.0); // COMPLIANT + + // Check that during flow analysis, we only report the true root cause: + float rootInf = 1.0 / 0.0; + float rootNaN = 0.0 / 0.0; + float middleInf = rootInf + 1; + float middleNaN = rootNaN + 1; + castToInt(middleInf); // NON_COMPLIANT + castToInt(middleNaN); // COMPLIANT + addInfThenCastToInt(middleInf); // NON_COMPLIANT + addNaNThenCastToInt(middleNaN); // COMPLIANT +} \ No newline at end of file diff --git a/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected b/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected new file mode 100644 index 0000000000..5e4d3cacd7 --- /dev/null +++ b/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected @@ -0,0 +1,136 @@ +problems +| test.cpp:36:8:36:9 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:36:3:36:9 | l5 | Possible NaN value $@ flows to a cast to integer. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:37:8:37:9 | l6 | test.cpp:28:14:28:20 | ... / ... | test.cpp:37:3:37:9 | l6 | Possible NaN value $@ flows to a cast to integer. | test.cpp:28:14:28:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:38:8:38:9 | l7 | test.cpp:31:14:32:15 | ... / ... | test.cpp:38:3:38:9 | l7 | Possible NaN value $@ flows to a cast to integer. | test.cpp:31:14:32:15 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:39:8:39:9 | l8 | test.cpp:33:14:33:22 | ... / ... | test.cpp:39:3:39:9 | l8 | Possible NaN value $@ flows to a cast to integer. | test.cpp:33:14:33:22 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:46:3:46:4 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:46:3:46:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:47:3:47:4 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:47:3:47:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:48:3:48:4 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:48:3:48:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:49:3:49:4 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:49:3:49:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:50:3:50:4 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:50:3:50:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:51:3:51:4 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:51:3:51:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:52:3:52:4 | l6 | test.cpp:28:14:28:20 | ... / ... | test.cpp:52:3:52:4 | l6 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:28:14:28:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:53:3:53:4 | l7 | test.cpp:31:14:32:15 | ... / ... | test.cpp:53:3:53:4 | l7 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:31:14:32:15 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:54:3:54:4 | l8 | test.cpp:33:14:33:22 | ... / ... | test.cpp:54:3:54:4 | l8 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:33:14:33:22 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:61:11:61:17 | ... / ... | test.cpp:61:5:61:18 | ... / ... | test.cpp:61:5:61:18 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.cpp:61:11:61:17 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:66:11:66:19 | ... / ... | test.cpp:66:5:66:20 | ... / ... | test.cpp:66:5:66:20 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.cpp:66:11:66:19 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:72:20:72:28 | ... / ... | test.cpp:72:14:72:29 | ... / ... | test.cpp:72:14:72:29 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.cpp:72:20:72:28 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:75:24:75:32 | ... / ... | test.cpp:75:18:75:33 | ... / ... | test.cpp:75:18:75:33 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.cpp:75:24:75:32 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:127:10:127:12 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:127:5:127:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:133:10:133:12 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:133:5:133:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:139:10:139:12 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:139:5:139:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:145:10:145:12 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:145:5:145:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:149:10:149:12 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:149:5:149:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:157:30:157:32 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:157:25:157:32 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:159:33:159:35 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:159:28:159:35 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:160:26:160:28 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:160:21:160:28 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:168:8:168:15 | call to pow | test.cpp:168:3:168:23 | call to pow | test.cpp:168:3:168:23 | call to pow | Possible NaN value $@ flows to a cast to integer. | test.cpp:168:8:168:15 | call to pow | both arguments are equal to zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:173:8:173:16 | call to acos | test.cpp:173:3:173:20 | call to acos | test.cpp:173:3:173:20 | call to acos | Possible NaN value $@ flows to a cast to integer. | test.cpp:173:8:173:16 | call to acos | the argument has a range -1000000000000000...1000000000000000 which is outside the domain of this function (-1.0...1.0) | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:177:32:177:32 | p | test.cpp:192:51:192:59 | ... / ... | test.cpp:177:27:177:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:192:51:192:59 | ... / ... | from division of zero by zero | test.cpp:192:6:192:24 | addNaNThenCastToInt | addNaNThenCastToInt | +| test.cpp:177:32:177:32 | p | test.cpp:196:13:196:21 | ... / ... | test.cpp:177:27:177:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:196:13:196:21 | ... / ... | from division of zero by zero | test.cpp:194:6:194:7 | f2 | f2 | +| test.cpp:177:32:177:32 | p | test.cpp:200:23:200:31 | ... / ... | test.cpp:177:27:177:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:200:23:200:31 | ... / ... | from division of zero by zero | test.cpp:194:6:194:7 | f2 | f2 | +| test.cpp:177:32:177:32 | p | test.cpp:206:19:206:27 | ... / ... | test.cpp:177:27:177:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:206:19:206:27 | ... / ... | from division of zero by zero | test.cpp:194:6:194:7 | f2 | f2 | +| test.cpp:187:18:187:18 | p | test.cpp:202:25:202:33 | ... / ... | test.cpp:187:13:187:18 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:202:25:202:33 | ... / ... | from division of zero by zero | test.cpp:194:6:194:7 | f2 | f2 | +edges +| test.cpp:27:14:27:20 | ... / ... | test.cpp:27:14:27:20 | ... / ... | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:36:3:36:9 | l5 | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:46:3:46:4 | l5 | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:47:3:47:4 | l5 | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:48:3:48:4 | l5 | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:49:3:49:4 | l5 | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:50:3:50:4 | l5 | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:51:3:51:4 | l5 | provenance | | +| test.cpp:28:14:28:20 | ... / ... | test.cpp:28:14:28:20 | ... / ... | provenance | | +| test.cpp:28:14:28:20 | ... / ... | test.cpp:37:3:37:9 | l6 | provenance | | +| test.cpp:28:14:28:20 | ... / ... | test.cpp:52:3:52:4 | l6 | provenance | | +| test.cpp:31:14:32:15 | ... / ... | test.cpp:31:14:32:15 | ... / ... | provenance | | +| test.cpp:31:14:32:15 | ... / ... | test.cpp:38:3:38:9 | l7 | provenance | | +| test.cpp:31:14:32:15 | ... / ... | test.cpp:53:3:53:4 | l7 | provenance | | +| test.cpp:33:14:33:22 | ... / ... | test.cpp:33:14:33:22 | ... / ... | provenance | | +| test.cpp:33:14:33:22 | ... / ... | test.cpp:39:3:39:9 | l8 | provenance | | +| test.cpp:33:14:33:22 | ... / ... | test.cpp:54:3:54:4 | l8 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:123:15:123:21 | ... / ... | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:127:5:127:12 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:133:5:133:12 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:139:5:139:12 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:145:5:145:12 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:149:5:149:12 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:157:25:157:32 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:159:28:159:35 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:160:21:160:28 | l13 | provenance | | +| test.cpp:177:22:177:22 | p | test.cpp:177:27:177:32 | p | provenance | | +| test.cpp:185:34:185:34 | p | test.cpp:187:13:187:18 | p | provenance | | +| test.cpp:190:32:190:32 | p | test.cpp:190:47:190:51 | ... + ... | provenance | Config | +| test.cpp:190:47:190:51 | ... + ... | test.cpp:177:22:177:22 | p | provenance | | +| test.cpp:192:32:192:32 | p | test.cpp:192:47:192:59 | ... + ... | provenance | Config | +| test.cpp:192:47:192:59 | ... + ... | test.cpp:177:22:177:22 | p | provenance | | +| test.cpp:192:47:192:59 | ... + ... | test.cpp:177:22:177:22 | p | provenance | | +| test.cpp:192:51:192:59 | ... / ... | test.cpp:192:47:192:59 | ... + ... | provenance | Config | +| test.cpp:196:13:196:21 | ... / ... | test.cpp:177:22:177:22 | p | provenance | | +| test.cpp:200:23:200:31 | ... / ... | test.cpp:190:32:190:32 | p | provenance | | +| test.cpp:202:25:202:33 | ... / ... | test.cpp:185:34:185:34 | p | provenance | | +| test.cpp:206:19:206:27 | ... / ... | test.cpp:206:19:206:27 | ... / ... | provenance | | +| test.cpp:206:19:206:27 | ... / ... | test.cpp:208:21:208:31 | ... + ... | provenance | Config | +| test.cpp:208:21:208:31 | ... + ... | test.cpp:208:21:208:31 | ... + ... | provenance | | +| test.cpp:208:21:208:31 | ... + ... | test.cpp:210:13:210:21 | middleNaN | provenance | | +| test.cpp:208:21:208:31 | ... + ... | test.cpp:212:23:212:31 | middleNaN | provenance | | +| test.cpp:210:13:210:21 | middleNaN | test.cpp:177:22:177:22 | p | provenance | | +| test.cpp:212:23:212:31 | middleNaN | test.cpp:192:32:192:32 | p | provenance | | +nodes +| test.cpp:27:14:27:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:27:14:27:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:28:14:28:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:28:14:28:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:31:14:32:15 | ... / ... | semmle.label | ... / ... | +| test.cpp:31:14:32:15 | ... / ... | semmle.label | ... / ... | +| test.cpp:33:14:33:22 | ... / ... | semmle.label | ... / ... | +| test.cpp:33:14:33:22 | ... / ... | semmle.label | ... / ... | +| test.cpp:36:3:36:9 | l5 | semmle.label | l5 | +| test.cpp:37:3:37:9 | l6 | semmle.label | l6 | +| test.cpp:38:3:38:9 | l7 | semmle.label | l7 | +| test.cpp:39:3:39:9 | l8 | semmle.label | l8 | +| test.cpp:46:3:46:4 | l5 | semmle.label | l5 | +| test.cpp:47:3:47:4 | l5 | semmle.label | l5 | +| test.cpp:48:3:48:4 | l5 | semmle.label | l5 | +| test.cpp:49:3:49:4 | l5 | semmle.label | l5 | +| test.cpp:50:3:50:4 | l5 | semmle.label | l5 | +| test.cpp:51:3:51:4 | l5 | semmle.label | l5 | +| test.cpp:52:3:52:4 | l6 | semmle.label | l6 | +| test.cpp:53:3:53:4 | l7 | semmle.label | l7 | +| test.cpp:54:3:54:4 | l8 | semmle.label | l8 | +| test.cpp:61:5:61:18 | ... / ... | semmle.label | ... / ... | +| test.cpp:66:5:66:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:72:14:72:29 | ... / ... | semmle.label | ... / ... | +| test.cpp:75:18:75:33 | ... / ... | semmle.label | ... / ... | +| test.cpp:123:15:123:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:123:15:123:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:127:5:127:12 | l13 | semmle.label | l13 | +| test.cpp:133:5:133:12 | l13 | semmle.label | l13 | +| test.cpp:139:5:139:12 | l13 | semmle.label | l13 | +| test.cpp:145:5:145:12 | l13 | semmle.label | l13 | +| test.cpp:149:5:149:12 | l13 | semmle.label | l13 | +| test.cpp:157:25:157:32 | l13 | semmle.label | l13 | +| test.cpp:159:28:159:35 | l13 | semmle.label | l13 | +| test.cpp:160:21:160:28 | l13 | semmle.label | l13 | +| test.cpp:168:3:168:23 | call to pow | semmle.label | call to pow | +| test.cpp:173:3:173:20 | call to acos | semmle.label | call to acos | +| test.cpp:177:22:177:22 | p | semmle.label | p | +| test.cpp:177:27:177:32 | p | semmle.label | p | +| test.cpp:185:34:185:34 | p | semmle.label | p | +| test.cpp:187:13:187:18 | p | semmle.label | p | +| test.cpp:190:32:190:32 | p | semmle.label | p | +| test.cpp:190:47:190:51 | ... + ... | semmle.label | ... + ... | +| test.cpp:192:32:192:32 | p | semmle.label | p | +| test.cpp:192:47:192:59 | ... + ... | semmle.label | ... + ... | +| test.cpp:192:47:192:59 | ... + ... | semmle.label | ... + ... | +| test.cpp:192:51:192:59 | ... / ... | semmle.label | ... / ... | +| test.cpp:196:13:196:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:200:23:200:31 | ... / ... | semmle.label | ... / ... | +| test.cpp:202:25:202:33 | ... / ... | semmle.label | ... / ... | +| test.cpp:206:19:206:27 | ... / ... | semmle.label | ... / ... | +| test.cpp:206:19:206:27 | ... / ... | semmle.label | ... / ... | +| test.cpp:208:21:208:31 | ... + ... | semmle.label | ... + ... | +| test.cpp:208:21:208:31 | ... + ... | semmle.label | ... + ... | +| test.cpp:210:13:210:21 | middleNaN | semmle.label | middleNaN | +| test.cpp:212:23:212:31 | middleNaN | semmle.label | middleNaN | +subpaths diff --git a/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql b/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql new file mode 100644 index 0000000000..a1f729ed02 --- /dev/null +++ b/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.misuseofnanfloatingpointvalue.MisuseOfNaNFloatingPointValue + +class TestFileQuery extends MisuseOfNaNFloatingPointValueSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/misuseofnanfloatingpointvalue/test.cpp b/cpp/common/test/rules/misuseofnanfloatingpointvalue/test.cpp new file mode 100644 index 0000000000..a68a47daf7 --- /dev/null +++ b/cpp/common/test/rules/misuseofnanfloatingpointvalue/test.cpp @@ -0,0 +1,213 @@ +#include + +float getFloat() { return 1.0; } + +// Parameter could be infinity +void f1(float p1) { + float l1 = 1; + float l2 = 1.0 / 0; + float l3 = -l2; + + 10 / l1; // COMPLIANT + 10 / l2; // COMPLIANT: Underflows to zero + 10 / l3; // COMPLIANT: Underflow to negative zero + 10 / p1; // COMPLIANT: Reduce false positives by assuming not infinity + 10 / getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + (int)l1; // COMPLIANT + (int)l2; // COMPLIANT + (int)l3; // COMPLIANT + (int)p1; // COMPLIANT: Reduce false positives by assuming not infinity + (int)getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + // Not NaN: + float l4 = l1 / l1; // COMPLIANT + + // NaN because of infinity divided by itself: + float l5 = l2 / l2; // COMPLIANT: Division by infinity not allowed. + float l6 = l3 / l3; // COMPLIANT: Division by infinity not allowed. + + // NaN because of zero divided by itself: + float l7 = getFloat() / + p1; // COMPLIANT: Reduce false positives by assuming not infinity + float l8 = 0.0 / 0.0; + + (int)l4; // COMPLIANT + (int)l5; // NON_COMPLIANT: Casting NaN to int + (int)l6; // NON_COMPLIANT: Casting NaN to int + (int)l7; // NON_COMPLIANT: Casting NaN to int + (int)l8; // NON_COMPLIANT: Casting NaN to int + + l4 == 0; // COMPLIANT + l4 != 0; // COMPLIANT + l4 <= 0; // COMPLIANT + l4 < 0; // COMPLIANT + l4 >= 0; // COMPLIANT + l5 == 0; // NON_COMPLIANT: Comparison with NaN always false + l5 != 0; // NON_COMPLIANT: Comparison with NaN always false + l5 < 0; // NON_COMPLIANT: Comparison with NaN always false + l5 <= 0; // NON_COMPLIANT: Comparison with NaN always false + l5 > 0; // NON_COMPLIANT: Comparison with NaN always false + l5 >= 0; // NON_COMPLIANT: Comparison with NaN always false + l6 == 0; // NON_COMPLIANT: Comparison with NaN always false + l7 == 0; // NON_COMPLIANT: Comparison with NaN always false + l8 == 0; // NON_COMPLIANT: Comparison with NaN always false + + // Guards + float l9 = 0; + if (l9 != 0) { + (int)(l9 / l9); // COMPLIANT: l9 is not zero + } else { + (int)(l9 / l9); // NON_COMPLIANT: Casting NaN to integer + } + + float l10 = 0; + if (l10 == 0) { + (int)(l10 / l10); // NON_COMPLIANT: Casting NaN to integer + } else { + (int)(l10 / l10); // COMPLIANT: Guarded to not be NaN + } + + float l11 = 0; + l11 == 0 ? (int)(l11 / l11) : 0; // NON_COMPLIANT + l11 == 0 ? 0 : (int)(l11 / l11); // COMPLIANT + l11 != 0 ? (int)(l11 / l11) : 0; // COMPLIANT + l11 != 0 ? 0 : (int)(l11 / l11); // NON_COMPLIANT + + float l12 = 1.0 / 0; + if (std::isinf(l12)) { + (int)l12; // COMPLIANT: Casting Infinity to integer + } else { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } + + if (!std::isinf(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + if (std::isinf(l12) == 1) { + (int)l12; // COMPLIANT: Must be +Infinity + } else { + (int)l12; // COMPLIANT: May be -Infinity + } + + if (std::isfinite(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + if (std::isnormal(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + if (std::isnan(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + std::isinf(l12) ? (int)l12 : 0; // COMPLIANT: Check on wrong branch + std::isinf(l12) ? 0 : (int)l12; // COMPLIANT: Checked not infinite before use + std::isfinite(l12) ? (int)l12 : 0; // COMPLIANT: Checked finite before use + std::isfinite(l12) ? 0 : (int)l12; // COMPLIANT: Checked on wrong branch + std::isnan(l12) + ? (int)l12 + : 0; // COMPLIANT: Checked NaN, therefore not infinite, before use + std::isnan(l12) ? 0 : (int)l12; // COMPLIANT: Check on wrong branch + + float l13 = 0.0 / 0; + if (std::isinf(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (std::isinf(l13) == 1) { + (int)l13; // COMPLIANT: Guarded not to be NaN (must be +Infinity) + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (std::isfinite(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (std::isnormal(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (std::isnan(l13)) { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } else { + (int)l13; // COMPLIANT: Guarded not to be NaN + } + + std::isinf(l13) + ? (int)l13 + : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use + std::isinf(l13) ? 0 : (int)l13; // NON_COMPLIANT: Check on wrong branch + std::isfinite(l13) ? (int)l13 : 0; // COMPLIANT: Checked finite before use + std::isfinite(l13) ? 0 : (int)l13; // NON_COMPLIANT: Checked on wrong branch + std::isnan(l13) ? (int)l13 : 0; // NON_COMPLIANT: Check on wrong branch + std::isnan(l13) ? 0 : (int)l13; // COMPLIANT: Checked not NaN before use + + (int)std::pow(2, p1); // COMPLIANT: likely to be Infinity + (int)std::pow(2, std::sin(p1)); // COMPLIANT: not likely to be Infinity + (int)(1 / + std::sin(p1)); // COMPLIANT: possible infinity from zero in denominator + (int)(1 / std::log(p1)); // COMPLIANT: not possibly zero in denominator + (int)std::pow(p1, p1); // NON_COMPLIANT: NaN if p1 is zero + if (p1 != 0) { + (int)std::pow(p1, p1); // COMPLIANT: p1 is not zero + } + + (int)std::acos(p1); // NON_COMPLIANT: NaN if p1 is not within -1..1 + (int)std::acos(std::cos(p1)); // COMPLIANT: cos(p1) is within -1..1 +} + +void castToInt(float p) { (int)p; } + +void checkBeforeCastToInt(float p) { + if (std::isfinite(p)) { + castToInt(p); + } +} + +void castToIntToFloatToInt(float p) { + // This should be reported as a violation, but not downstream from here. + castToInt((int)p); +} + +void addOneThenCastToInt(float p) { castToInt(p + 1); } +void addInfThenCastToInt(float p) { castToInt(p + 1.0 / 0.0); } +void addNaNThenCastToInt(float p) { castToInt(p + 0.0 / 0.0); } + +void f2() { + castToInt(1.0 / 0.0); // COMPLIANT: Infinity flows to denominator in division + castToInt(0.0 / 0.0); // COMPLIANT: NaN flows to denominator in division + checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT + checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT + addOneThenCastToInt(1.0 / 0.0); // COMPLIANT + addOneThenCastToInt(0.0 / 0.0); // NON_COMPLIANT + castToIntToFloatToInt(1.0 / 0.0); // COMPLIANT + castToIntToFloatToInt(0.0 / 0.0); // NON_COMPLIANT + + // Check that during flow analysis, we only report the true root cause: + float rootInf = 1.0 / 0.0; + float rootNaN = 0.0 / 0.0; + float middleInf = rootInf + 1; + float middleNaN = rootNaN + 1; + castToInt(middleInf); // COMPLIANT + castToInt(middleNaN); // NON_COMPLIANT + addInfThenCastToInt(middleInf); // COMPLIANT + addNaNThenCastToInt(middleNaN); // NON_COMPLIANT +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/M8-0-1/MultipleGlobalOrMemberDeclarators.expected b/cpp/common/test/rules/multipleglobalormemberdeclarators/MultipleGlobalOrMemberDeclarators.expected similarity index 100% rename from cpp/autosar/test/rules/M8-0-1/MultipleGlobalOrMemberDeclarators.expected rename to cpp/common/test/rules/multipleglobalormemberdeclarators/MultipleGlobalOrMemberDeclarators.expected diff --git a/cpp/common/test/rules/multipleglobalormemberdeclarators/MultipleGlobalOrMemberDeclarators.ql b/cpp/common/test/rules/multipleglobalormemberdeclarators/MultipleGlobalOrMemberDeclarators.ql new file mode 100644 index 0000000000..2f4d3cbdea --- /dev/null +++ b/cpp/common/test/rules/multipleglobalormemberdeclarators/MultipleGlobalOrMemberDeclarators.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.multipleglobalormemberdeclarators.MultipleGlobalOrMemberDeclarators + +class TestFileQuery extends MultipleGlobalOrMemberDeclaratorsSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/M8-0-1/test.cpp b/cpp/common/test/rules/multipleglobalormemberdeclarators/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M8-0-1/test.cpp rename to cpp/common/test/rules/multipleglobalormemberdeclarators/test.cpp diff --git a/cpp/autosar/test/rules/M8-0-1/MultipleLocalDeclarators.expected b/cpp/common/test/rules/multiplelocaldeclarators/MultipleLocalDeclarators.expected similarity index 100% rename from cpp/autosar/test/rules/M8-0-1/MultipleLocalDeclarators.expected rename to cpp/common/test/rules/multiplelocaldeclarators/MultipleLocalDeclarators.expected diff --git a/cpp/common/test/rules/multiplelocaldeclarators/MultipleLocalDeclarators.ql b/cpp/common/test/rules/multiplelocaldeclarators/MultipleLocalDeclarators.ql new file mode 100644 index 0000000000..7e2fe57b24 --- /dev/null +++ b/cpp/common/test/rules/multiplelocaldeclarators/MultipleLocalDeclarators.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.multiplelocaldeclarators.MultipleLocalDeclarators + +class TestFileQuery extends MultipleLocalDeclaratorsSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/multiplelocaldeclarators/test.cpp b/cpp/common/test/rules/multiplelocaldeclarators/test.cpp new file mode 100644 index 0000000000..cf664e4b34 --- /dev/null +++ b/cpp/common/test/rules/multiplelocaldeclarators/test.cpp @@ -0,0 +1,24 @@ +int g1, g2; // NON_COMPLIANT +int g3; // COMPLIANT + +namespace n1 { +int n_v1, n_v2; // NON_COMPLIANT +int n_v3; // COMPLIANT +} // namespace n1 + +void f() { + int l1, l2; // NON_COMPLIANT + int l3; // COMPLIANT +} + +class ClassA { + int m1, m2; // NON_COMPLIANT + int m3; // COMPLIANT +}; + +#include +void test_loop(std::vector v) { + for (const auto b : v) { // COMPLIANT - DeclStmt is compiler generated + b; + } +} \ No newline at end of file diff --git a/cpp/common/test/rules/namedbitfieldswithsignedintegertype/NamedBitFieldsWithSignedIntegerType.expected b/cpp/common/test/rules/namedbitfieldswithsignedintegertype/NamedBitFieldsWithSignedIntegerType.expected new file mode 100644 index 0000000000..8ddc10e90c --- /dev/null +++ b/cpp/common/test/rules/namedbitfieldswithsignedintegertype/NamedBitFieldsWithSignedIntegerType.expected @@ -0,0 +1,5 @@ +| test.cpp:6:7:6:8 | x1 | A named bit-field with signed integral type should have at least 2 bits of storage. | +| test.cpp:9:14:9:15 | x2 | A named bit-field with signed integral type should have at least 2 bits of storage. | +| test.cpp:11:7:11:8 | x3 | A named bit-field with signed integral type should have at least 2 bits of storage. | +| test.cpp:13:7:13:8 | x4 | A named bit-field with signed integral type should have at least 2 bits of storage. | +| test.cpp:22:14:22:14 | x | A named bit-field with signed integral type should have at least 2 bits of storage. | diff --git a/cpp/common/test/rules/namedbitfieldswithsignedintegertype/NamedBitFieldsWithSignedIntegerType.ql b/cpp/common/test/rules/namedbitfieldswithsignedintegertype/NamedBitFieldsWithSignedIntegerType.ql new file mode 100644 index 0000000000..a82fa7905a --- /dev/null +++ b/cpp/common/test/rules/namedbitfieldswithsignedintegertype/NamedBitFieldsWithSignedIntegerType.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.namedbitfieldswithsignedintegertype.NamedBitFieldsWithSignedIntegerType + +class TestFileQuery extends NamedBitFieldsWithSignedIntegerTypeSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/namedbitfieldswithsignedintegertype/test.cpp b/cpp/common/test/rules/namedbitfieldswithsignedintegertype/test.cpp new file mode 100644 index 0000000000..0d6e838f83 --- /dev/null +++ b/cpp/common/test/rules/namedbitfieldswithsignedintegertype/test.cpp @@ -0,0 +1,28 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +#include + +struct SampleStruct { + int x1 : 1; // NON_COMPLIANT: very likely be signed, but if it's not, the + // query will automatically handle it since we use signed(), not + // isExplicitlySigned(). + signed int x2 : 1; // NON_COMPLIANT: single-bit named field with a signed type + signed char + x3 : 1; // NON_COMPLIANT: single-bit named field with a signed type + signed short + x4 : 1; // NON_COMPLIANT: single-bit named field with a signed type + unsigned int + x5 : 1; // COMPLIANT: single-bit named field but with an unsigned type + signed int x6 : 2; // COMPLIANT: named field with a signed type but declared + // to carry more than 1 bit + signed char : 1; // COMPLIANT: single-bit bit-field but unnamed +} sample_struct; + +struct S { + signed int x : 1; // NON-COMPLIANT + signed int y : 5; // COMPLIANT + signed int z : 7; // COMPLIANT + signed int : 0; // COMPLIANT + signed int : 1; // COMPLIANT + signed int : 2; // COMPLIANT +}; \ No newline at end of file diff --git a/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.expected b/cpp/common/test/rules/namenotreferredusingaqualifiedidorthis/NameNotReferredUsingAQualifiedIdOrThis.expected similarity index 100% rename from cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThis.expected rename to cpp/common/test/rules/namenotreferredusingaqualifiedidorthis/NameNotReferredUsingAQualifiedIdOrThis.expected diff --git a/cpp/common/test/rules/namenotreferredusingaqualifiedidorthis/NameNotReferredUsingAQualifiedIdOrThis.ql b/cpp/common/test/rules/namenotreferredusingaqualifiedidorthis/NameNotReferredUsingAQualifiedIdOrThis.ql new file mode 100644 index 0000000000..731d7b1f84 --- /dev/null +++ b/cpp/common/test/rules/namenotreferredusingaqualifiedidorthis/NameNotReferredUsingAQualifiedIdOrThis.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.namenotreferredusingaqualifiedidorthis.NameNotReferredUsingAQualifiedIdOrThis + +class TestFileQuery extends NameNotReferredUsingAQualifiedIdOrThisSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/M14-6-1/test.cpp b/cpp/common/test/rules/namenotreferredusingaqualifiedidorthis/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M14-6-1/test.cpp rename to cpp/common/test/rules/namenotreferredusingaqualifiedidorthis/test.cpp diff --git a/cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.expected b/cpp/common/test/rules/namenotreferredusingaqualifiedidorthisaudit/NameNotReferredUsingAQualifiedIdOrThisAudit.expected similarity index 100% rename from cpp/autosar/test/rules/M14-6-1/NameNotReferredUsingAQualifiedIdOrThisAudit.expected rename to cpp/common/test/rules/namenotreferredusingaqualifiedidorthisaudit/NameNotReferredUsingAQualifiedIdOrThisAudit.expected diff --git a/cpp/common/test/rules/namenotreferredusingaqualifiedidorthisaudit/NameNotReferredUsingAQualifiedIdOrThisAudit.ql b/cpp/common/test/rules/namenotreferredusingaqualifiedidorthisaudit/NameNotReferredUsingAQualifiedIdOrThisAudit.ql new file mode 100644 index 0000000000..46ffea0b3d --- /dev/null +++ b/cpp/common/test/rules/namenotreferredusingaqualifiedidorthisaudit/NameNotReferredUsingAQualifiedIdOrThisAudit.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.namenotreferredusingaqualifiedidorthisaudit.NameNotReferredUsingAQualifiedIdOrThisAudit + +class TestFileQuery extends NameNotReferredUsingAQualifiedIdOrThisAuditSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/namenotreferredusingaqualifiedidorthisaudit/test.cpp b/cpp/common/test/rules/namenotreferredusingaqualifiedidorthisaudit/test.cpp new file mode 100644 index 0000000000..b16e6b40dc --- /dev/null +++ b/cpp/common/test/rules/namenotreferredusingaqualifiedidorthisaudit/test.cpp @@ -0,0 +1,87 @@ +typedef int TYPE; +void g(); +void g1(); +int m; + +template class B { +public: + typedef T TYPE; + void g(); + int m; +}; + +template class A : B { +public: + void m1() { + m = 0; // NON_COMPLIANT + g(); // NON_COMPLIANT + TYPE t = 0; // NON_COMPLIANT[FALSE_NEGATIVE] + void (*p)() = &g; // NON_COMPLIANT + } + void m2() { + ::m = 0; // COMPLIANT + ::g(); // COMPLIANT + ::TYPE t1 = 0; // COMPLIANT + B::m = 0; // COMPLIANT + this->m = 0; // COMPLIANT + this->g(); // COMPLIANT + void (B::*p)() = &B::g; // COMPLIANT + typename B::TYPE t2 = 0; // COMPLIANT + g1(); // COMPLIANT, identifier not found in B + } + void m3(int m) { + m = 0; // COMPLIANT, hides member + } + void m4() { + int m = 0; + m = 0; // COMPLIANT, hides member + } +}; + +void f() { + A a; + a.m1(); + a.m2(); + a.m3(1); + a.m4(); +} + +class D { +public: + typedef int TYPE; + void g(); + void g(int x); + static void sg(); + static void sg(int x); + int m; +}; + +class C : D { +public: + void m1() { + m = 0; // COMPLIANT - does not apply to non-class templates + g(); // COMPLIANT - does not apply to non-class templates + sg(); // COMPLIANT - does not apply to non-class templates + TYPE t1 = 0; // COMPLIANT - does not apply to non-class templates + // void (*p)() = &g; // NON_COMPILABLE - not valid to take address of member + // function without qualifier + } +}; + +template class E : D { +public: + void m1() { + m = 0; // COMPLIANT - does not apply to non dependent base types + g(); // COMPLIANT - does not apply to non dependent base types + TYPE t1 = 0; // COMPLIANT - does not apply to non dependent base types + // void (*p)() = &g; // NON_COMPILABLE - not valid to take address of member + // function without qualifier + } +}; + +void f2() { + C c; + c.m1(); + E e; + e.m1(); +} \ No newline at end of file diff --git a/cpp/common/test/rules/noexceptfunctionshouldnotpropagatetothecaller/NoexceptFunctionShouldNotPropagateToTheCaller.expected b/cpp/common/test/rules/noexceptfunctionshouldnotpropagatetothecaller/NoexceptFunctionShouldNotPropagateToTheCaller.expected new file mode 100644 index 0000000000..db392fd8f6 --- /dev/null +++ b/cpp/common/test/rules/noexceptfunctionshouldnotpropagatetothecaller/NoexceptFunctionShouldNotPropagateToTheCaller.expected @@ -0,0 +1,19 @@ +problems +| test.cpp:4:6:4:15 | test_throw | test.cpp:5:3:5:20 | throw ... [ExceptionA] | test.cpp:4:6:4:15 | test_throw [ExceptionA] | Function test_throw is declared noexcept(true) but can throw exceptions of type ExceptionA. | +| test.cpp:10:6:10:27 | noexceptIndirectThrowA | test.cpp:8:17:8:34 | throw ... [ExceptionA] | test.cpp:10:6:10:27 | noexceptIndirectThrowA [ExceptionA] | Function noexceptIndirectThrowA is declared noexcept(true) but can throw exceptions of type ExceptionA. | +| test.cpp:12:6:12:24 | test_indirect_throw | test.cpp:8:17:8:34 | throw ... [ExceptionA] | test.cpp:12:6:12:24 | test_indirect_throw [ExceptionA] | Function test_indirect_throw is declared noexcept(true) but can throw exceptions of type ExceptionA. | +| test.cpp:16:6:16:26 | test_indirect_throw_2 | test.cpp:8:17:8:34 | throw ... [ExceptionA] | test.cpp:16:6:16:26 | test_indirect_throw_2 [ExceptionA] | Function test_indirect_throw_2 is declared noexcept(true) but can throw exceptions of type ExceptionA. | +| test.cpp:33:6:33:26 | test_indirect_throw_6 | test.cpp:8:17:8:34 | throw ... [ExceptionA] | test.cpp:33:6:33:26 | test_indirect_throw_6 [ExceptionA] | Function test_indirect_throw_6 is declared noexcept(true) but can throw exceptions of type ExceptionA. | +edges +| test.cpp:5:3:5:20 | throw ... [ExceptionA] | test.cpp:4:6:4:15 | test_throw [ExceptionA] | +| test.cpp:8:6:8:11 | throwA [ExceptionA] | test.cpp:9:25:9:30 | call to throwA [ExceptionA] | +| test.cpp:8:6:8:11 | throwA [ExceptionA] | test.cpp:10:42:10:47 | call to throwA [ExceptionA] | +| test.cpp:8:6:8:11 | throwA [ExceptionA] | test.cpp:13:3:13:8 | call to throwA [ExceptionA] | +| test.cpp:8:6:8:11 | throwA [ExceptionA] | test.cpp:17:3:17:8 | call to throwA [ExceptionA] | +| test.cpp:8:17:8:34 | throw ... [ExceptionA] | test.cpp:8:6:8:11 | throwA [ExceptionA] | +| test.cpp:9:6:9:19 | indirectThrowA [ExceptionA] | test.cpp:34:3:34:16 | call to indirectThrowA [ExceptionA] | +| test.cpp:9:25:9:30 | call to throwA [ExceptionA] | test.cpp:9:6:9:19 | indirectThrowA [ExceptionA] | +| test.cpp:10:42:10:47 | call to throwA [ExceptionA] | test.cpp:10:6:10:27 | noexceptIndirectThrowA [ExceptionA] | +| test.cpp:13:3:13:8 | call to throwA [ExceptionA] | test.cpp:12:6:12:24 | test_indirect_throw [ExceptionA] | +| test.cpp:17:3:17:8 | call to throwA [ExceptionA] | test.cpp:16:6:16:26 | test_indirect_throw_2 [ExceptionA] | +| test.cpp:34:3:34:16 | call to indirectThrowA [ExceptionA] | test.cpp:33:6:33:26 | test_indirect_throw_6 [ExceptionA] | diff --git a/cpp/common/test/rules/noexceptfunctionshouldnotpropagatetothecaller/NoexceptFunctionShouldNotPropagateToTheCaller.ql b/cpp/common/test/rules/noexceptfunctionshouldnotpropagatetothecaller/NoexceptFunctionShouldNotPropagateToTheCaller.ql new file mode 100644 index 0000000000..e8906287da --- /dev/null +++ b/cpp/common/test/rules/noexceptfunctionshouldnotpropagatetothecaller/NoexceptFunctionShouldNotPropagateToTheCaller.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.noexceptfunctionshouldnotpropagatetothecaller.NoexceptFunctionShouldNotPropagateToTheCaller + +class TestFileQuery extends NoexceptFunctionShouldNotPropagateToTheCallerSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/A15-4-2/test.cpp b/cpp/common/test/rules/noexceptfunctionshouldnotpropagatetothecaller/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A15-4-2/test.cpp rename to cpp/common/test/rules/noexceptfunctionshouldnotpropagatetothecaller/test.cpp diff --git a/cpp/autosar/test/rules/M7-3-2/IdentifierMainUsedForAFunctionOtherThanTheGlobalFunctionMain.expected b/cpp/common/test/rules/nonglobalfunctionmain/NonGlobalFunctionMain.expected similarity index 100% rename from cpp/autosar/test/rules/M7-3-2/IdentifierMainUsedForAFunctionOtherThanTheGlobalFunctionMain.expected rename to cpp/common/test/rules/nonglobalfunctionmain/NonGlobalFunctionMain.expected diff --git a/cpp/common/test/rules/nonglobalfunctionmain/NonGlobalFunctionMain.ql b/cpp/common/test/rules/nonglobalfunctionmain/NonGlobalFunctionMain.ql new file mode 100644 index 0000000000..02edcf3732 --- /dev/null +++ b/cpp/common/test/rules/nonglobalfunctionmain/NonGlobalFunctionMain.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.nonglobalfunctionmain.NonGlobalFunctionMain + +class TestFileQuery extends NonGlobalFunctionMainSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/M7-3-2/test.cpp b/cpp/common/test/rules/nonglobalfunctionmain/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M7-3-2/test.cpp rename to cpp/common/test/rules/nonglobalfunctionmain/test.cpp diff --git a/cpp/common/test/rules/nonterminatedescapesequences/NonTerminatedEscapeSequences.expected b/cpp/common/test/rules/nonterminatedescapesequences/NonTerminatedEscapeSequences.expected new file mode 100644 index 0000000000..3051e32537 --- /dev/null +++ b/cpp/common/test/rules/nonterminatedescapesequences/NonTerminatedEscapeSequences.expected @@ -0,0 +1,21 @@ +| test.cpp:37:18:37:24 | \u001aG | Invalid hexadecimal escape in string literal at '\\x1AG"'. | +| test.cpp:40:18:40:23 | \u00029 | Invalid octal escape in string literal at '\\029"'. | +| test.cpp:43:18:43:24 | \n7 | Invalid octal escape in string literal at '\\0127"'. | +| test.cpp:44:18:44:24 | \r7 | Invalid octal escape in string literal at '\\0157"'. | +| test.cpp:46:19:46:29 | \n\n9 | Invalid octal escape in string literal at '\\0129"'. | +| test.cpp:47:19:47:28 | \n\u00019 | Invalid octal escape in string literal at '\\019"'. | +| test.cpp:50:19:50:31 | \nAAA\u000f | Invalid octal escape in string literal at '\\012AAA\\017"'. | +| test.cpp:53:19:53:39 | Some Data \n\u000fA | Invalid octal escape in string literal at '\\017A"'. | +| test.cpp:54:19:55:21 | Some Data \n\u000fA5 | Invalid octal escape in string literal at '\\017A"\n "5"'. | +| test.cpp:56:19:58:25 | Some Data \n\u000fA\n1 | Invalid octal escape in string literal at '\\0121"'. | +| test.cpp:62:19:63:26 | \u0011G\u00012 | Invalid octal escape in string literal at '\\0012"'. | +| test.cpp:64:19:65:25 | \u0011GG\u0001 | Invalid hexadecimal escape in string literal at '\\x11G"\n "G\\001"'. | +| test.cpp:66:19:67:26 | \u0011GG\u00013 | Invalid hexadecimal escape in string literal at '\\x11G"\n "G\\0013"'. | +| test.cpp:66:19:67:26 | \u0011GG\u00013 | Invalid octal escape in string literal at '\\0013"'. | +| test.cpp:73:18:73:42 | Some Data \n\u000fA5 | Invalid octal escape in string literal at '\\017A" "5"'. | +| test.cpp:74:18:74:49 | Some Data \n\u000fA\n1 | Invalid octal escape in string literal at '\\0121"'. | +| test.cpp:76:18:76:32 | \u0011G\u00012 | Invalid octal escape in string literal at '\\0012"'. | +| test.cpp:77:18:77:32 | \u0011GG\u0001 | Invalid hexadecimal escape in string literal at '\\x11G" "G\\001"'. | +| test.cpp:78:18:78:33 | \u0011GG\u00013 | Invalid hexadecimal escape in string literal at '\\x11G" "G\\0013"'. | +| test.cpp:78:18:78:33 | \u0011GG\u00013 | Invalid octal escape in string literal at '\\0013"'. | +| test.cpp:81:11:81:16 | 10 | Invalid hexadecimal escape in string literal at '\\x0a''. | diff --git a/cpp/common/test/rules/nonterminatedescapesequences/NonTerminatedEscapeSequences.ql b/cpp/common/test/rules/nonterminatedescapesequences/NonTerminatedEscapeSequences.ql new file mode 100644 index 0000000000..c1aae3c31b --- /dev/null +++ b/cpp/common/test/rules/nonterminatedescapesequences/NonTerminatedEscapeSequences.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.nonterminatedescapesequences.NonTerminatedEscapeSequences + +class TestFileQuery extends NonTerminatedEscapeSequencesSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/nonterminatedescapesequences/test.cpp b/cpp/common/test/rules/nonterminatedescapesequences/test.cpp new file mode 100644 index 0000000000..aa1093b791 --- /dev/null +++ b/cpp/common/test/rules/nonterminatedescapesequences/test.cpp @@ -0,0 +1,81 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +#include + +struct SampleStruct { + int x1 : 1; // NON_COMPLIANT: very likely be signed, but if it's not, the + // query will automatically handle it since we use signed(), not + // isExplicitlySigned(). + signed int x2 : 1; // NON_COMPLIANT: single-bit named field with a signed type + signed char + x3 : 1; // NON_COMPLIANT: single-bit named field with a signed type + signed short + x4 : 1; // NON_COMPLIANT: single-bit named field with a signed type + unsigned int + x5 : 1; // COMPLIANT: single-bit named field but with an unsigned type + signed int x6 : 2; // COMPLIANT: named field with a signed type but declared + // to carry more than 1 bit + signed char : 1; // COMPLIANT: single-bit bit-field but unnamed +} sample_struct; + +struct S { + signed int x : 1; // NON-COMPLIANT + signed int y : 5; // COMPLIANT + signed int z : 7; // COMPLIANT + signed int : 0; // COMPLIANT + signed int : 1; // COMPLIANT + signed int : 2; // COMPLIANT +}; +const char *a1 = "\x11" + "G"; // COMPLIANT + +const char *a2 = "\x1" + "G"; // COMPLIANT + +const char *a3 = "\x1A"; // COMPLIANT + +const char *a4 = "\x1AG"; // NON_COMPLIANT + +const char *a5 = "\021"; // COMPLIANT +const char *a6 = "\029"; // NON_COMPLIANT +const char *a7 = "\0" + "0"; // COMPLIANT +const char *a8 = "\0127"; // NON_COMPLIANT +const char *a9 = "\0157"; // NON_COMPLIANT + +const char *a10 = "\012\0129"; // NON_COMPLIANT (1x) +const char *a11 = "\012\019"; // NON_COMPLIANT +const char *a12 = "\012\017"; // COMPLIANT + +const char *a13 = "\012AAA\017"; // NON_COMPLIANT (1x) + +const char *a14 = "Some Data \012\017"; // COMPLIANT +const char *a15 = "Some Data \012\017A"; // NON_COMPLIANT (1x) +const char *a16 = "Some Data \012\017A" + "5"; // NON_COMPLIANT (1x) +const char *a17 = "Some Data \012\017" + "A" + "\0121"; // NON_COMPLIANT (1x) + +const char *a18 = "\x11" + "G\001"; // COMPLIANT +const char *a19 = "\x11" + "G\0012"; // NON_COMPLIANT (1x) +const char *a20 = "\x11G" + "G\001"; // NON_COMPLIANT (1x) +const char *a21 = "\x11G" + "G\0013"; // NON_COMPLIANT (2x) + +// clang-format off +const char *b1 = "\x11" "G"; // COMPLIANT +const char *b2 = "\x1" "G"; // COMPLIANT +const char *b3 = "\0" "0"; // COMPLIANT +const char *b4 = "Some Data \012\017A" "5"; // NON_COMPLIANT (1x) +const char *b5 = "Some Data \012\017" "A" "\0121"; // NON_COMPLIANT (1x) +const char *b6 = "\x11" "G\001"; // COMPLIANT +const char *b7 = "\x11" "G\0012"; // NON_COMPLIANT (1x) +const char *b8 = "\x11G" "G\001"; // NON_COMPLIANT (1x) +const char *b9 = "\x11G" "G\0013"; // NON_COMPLIANT (2x) + +char c1 = '\023'; // COMPLIANT +char c2 = '\x0a'; // COMPLIANT diff --git a/cpp/common/test/rules/nonuniqueenumerationconstant/NonUniqueEnumerationConstant.expected b/cpp/common/test/rules/nonuniqueenumerationconstant/NonUniqueEnumerationConstant.expected new file mode 100644 index 0000000000..662a21b5d6 --- /dev/null +++ b/cpp/common/test/rules/nonuniqueenumerationconstant/NonUniqueEnumerationConstant.expected @@ -0,0 +1 @@ +| test.cpp:5:19:5:20 | c4 | Nonunique value of enum constant compared to $@ | test.cpp:5:23:5:24 | c5 | c5 | diff --git a/cpp/common/test/rules/nonuniqueenumerationconstant/NonUniqueEnumerationConstant.ql b/cpp/common/test/rules/nonuniqueenumerationconstant/NonUniqueEnumerationConstant.ql new file mode 100644 index 0000000000..97ba6f516e --- /dev/null +++ b/cpp/common/test/rules/nonuniqueenumerationconstant/NonUniqueEnumerationConstant.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.nonuniqueenumerationconstant.NonUniqueEnumerationConstant + +class TestFileQuery extends NonUniqueEnumerationConstantSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/nonuniqueenumerationconstant/test.cpp b/cpp/common/test/rules/nonuniqueenumerationconstant/test.cpp new file mode 100644 index 0000000000..0712cb59e4 --- /dev/null +++ b/cpp/common/test/rules/nonuniqueenumerationconstant/test.cpp @@ -0,0 +1,6 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +enum e { c = 3 }; // COMPLIANT +enum e1 { c1 = 3, c2 }; // COMPLIANT +enum e3 { c3 = 3, c4, c5 = 4 }; // NON_COMPLIANT +enum e4 { c6 = 3, c7, c8, c9 = 6 }; // COMPLIANT \ No newline at end of file diff --git a/cpp/autosar/test/rules/A4-10-1/NullPointerConstantNotNullptr.expected b/cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/NullptrNotTheOnlyFormOfTheNullPointerConstant.expected similarity index 100% rename from cpp/autosar/test/rules/A4-10-1/NullPointerConstantNotNullptr.expected rename to cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/NullptrNotTheOnlyFormOfTheNullPointerConstant.expected diff --git a/cpp/autosar/test/rules/A4-10-1/NullPointerConstantNotNullptr.expected.clang b/cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/NullptrNotTheOnlyFormOfTheNullPointerConstant.expected.clang similarity index 100% rename from cpp/autosar/test/rules/A4-10-1/NullPointerConstantNotNullptr.expected.clang rename to cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/NullptrNotTheOnlyFormOfTheNullPointerConstant.expected.clang diff --git a/cpp/autosar/test/rules/A4-10-1/NullPointerConstantNotNullptr.expected.gcc b/cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/NullptrNotTheOnlyFormOfTheNullPointerConstant.expected.gcc similarity index 100% rename from cpp/autosar/test/rules/A4-10-1/NullPointerConstantNotNullptr.expected.gcc rename to cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/NullptrNotTheOnlyFormOfTheNullPointerConstant.expected.gcc diff --git a/cpp/autosar/test/rules/A4-10-1/NullPointerConstantNotNullptr.expected.qcc b/cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/NullptrNotTheOnlyFormOfTheNullPointerConstant.expected.qcc similarity index 100% rename from cpp/autosar/test/rules/A4-10-1/NullPointerConstantNotNullptr.expected.qcc rename to cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/NullptrNotTheOnlyFormOfTheNullPointerConstant.expected.qcc diff --git a/cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/NullptrNotTheOnlyFormOfTheNullPointerConstant.ql b/cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/NullptrNotTheOnlyFormOfTheNullPointerConstant.ql new file mode 100644 index 0000000000..e3d6c4841f --- /dev/null +++ b/cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/NullptrNotTheOnlyFormOfTheNullPointerConstant.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.nullptrnottheonlyformofthenullpointerconstant.NullptrNotTheOnlyFormOfTheNullPointerConstant + +class TestFileQuery extends NullptrNotTheOnlyFormOfTheNullPointerConstantSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/A4-10-1/test.cpp b/cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A4-10-1/test.cpp rename to cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/test.cpp diff --git a/cpp/autosar/test/rules/A4-10-1/test.cpp.clang b/cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/test.cpp.clang similarity index 100% rename from cpp/autosar/test/rules/A4-10-1/test.cpp.clang rename to cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/test.cpp.clang diff --git a/cpp/autosar/test/rules/A4-10-1/test.cpp.gcc b/cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/test.cpp.gcc similarity index 100% rename from cpp/autosar/test/rules/A4-10-1/test.cpp.gcc rename to cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/test.cpp.gcc diff --git a/cpp/autosar/test/rules/A4-10-1/test.cpp.qcc b/cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/test.cpp.qcc similarity index 100% rename from cpp/autosar/test/rules/A4-10-1/test.cpp.qcc rename to cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/test.cpp.qcc diff --git a/cpp/autosar/test/rules/M12-1-1/DynamicTypeOfThisUsedFromConstructorOrDestructor.expected b/cpp/common/test/rules/objectsdynamictypeusedfromconstructorordestructor/ObjectsDynamicTypeUsedFromConstructorOrDestructor.expected similarity index 100% rename from cpp/autosar/test/rules/M12-1-1/DynamicTypeOfThisUsedFromConstructorOrDestructor.expected rename to cpp/common/test/rules/objectsdynamictypeusedfromconstructorordestructor/ObjectsDynamicTypeUsedFromConstructorOrDestructor.expected diff --git a/cpp/common/test/rules/objectsdynamictypeusedfromconstructorordestructor/ObjectsDynamicTypeUsedFromConstructorOrDestructor.ql b/cpp/common/test/rules/objectsdynamictypeusedfromconstructorordestructor/ObjectsDynamicTypeUsedFromConstructorOrDestructor.ql new file mode 100644 index 0000000000..151af6a5a3 --- /dev/null +++ b/cpp/common/test/rules/objectsdynamictypeusedfromconstructorordestructor/ObjectsDynamicTypeUsedFromConstructorOrDestructor.ql @@ -0,0 +1,5 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.objectsdynamictypeusedfromconstructorordestructor.ObjectsDynamicTypeUsedFromConstructorOrDestructor + +class TestFileQuery extends ObjectsDynamicTypeUsedFromConstructorOrDestructorSharedQuery, TestQuery { +} diff --git a/cpp/autosar/test/rules/M12-1-1/test.cpp b/cpp/common/test/rules/objectsdynamictypeusedfromconstructorordestructor/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M12-1-1/test.cpp rename to cpp/common/test/rules/objectsdynamictypeusedfromconstructorordestructor/test.cpp diff --git a/cpp/common/test/rules/overridingshallspecifydifferentdefaultarguments/OverridingShallSpecifyDifferentDefaultArguments.expected b/cpp/common/test/rules/overridingshallspecifydifferentdefaultarguments/OverridingShallSpecifyDifferentDefaultArguments.expected new file mode 100644 index 0000000000..d2d80e0572 --- /dev/null +++ b/cpp/common/test/rules/overridingshallspecifydifferentdefaultarguments/OverridingShallSpecifyDifferentDefaultArguments.expected @@ -0,0 +1,2 @@ +| test.cpp:16:8:16:8 | f | Overriding function does not have the same default parameters as $@ | test.cpp:4:16:4:16 | f | overridden function | +| test.cpp:21:8:21:8 | f | Overriding function does not have the same default parameters as $@ | test.cpp:4:16:4:16 | f | overridden function | diff --git a/cpp/common/test/rules/overridingshallspecifydifferentdefaultarguments/OverridingShallSpecifyDifferentDefaultArguments.ql b/cpp/common/test/rules/overridingshallspecifydifferentdefaultarguments/OverridingShallSpecifyDifferentDefaultArguments.ql new file mode 100644 index 0000000000..2bb15bb684 --- /dev/null +++ b/cpp/common/test/rules/overridingshallspecifydifferentdefaultarguments/OverridingShallSpecifyDifferentDefaultArguments.ql @@ -0,0 +1,5 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.overridingshallspecifydifferentdefaultarguments.OverridingShallSpecifyDifferentDefaultArguments + +class TestFileQuery extends OverridingShallSpecifyDifferentDefaultArgumentsSharedQuery, TestQuery { +} diff --git a/cpp/autosar/test/rules/M8-3-1/test.cpp b/cpp/common/test/rules/overridingshallspecifydifferentdefaultarguments/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M8-3-1/test.cpp rename to cpp/common/test/rules/overridingshallspecifydifferentdefaultarguments/test.cpp diff --git a/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected b/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected index 3d00ff0d6a..7790582443 100644 --- a/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected +++ b/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected @@ -6,21 +6,22 @@ problems | test.cpp:12:28:12:29 | v2 | test.cpp:10:8:10:17 | new | test.cpp:12:28:12:29 | v2 | Raw pointer flows to initialize multiple unrelated smart pointers. | | test.cpp:17:27:17:28 | v1 | test.cpp:16:13:16:22 | new | test.cpp:17:27:17:28 | v1 | Raw pointer flows to initialize multiple unrelated smart pointers. | edges -| test.cpp:3:14:3:15 | v1 | test.cpp:5:27:5:28 | v1 | -| test.cpp:3:14:3:15 | v1 | test.cpp:5:27:5:28 | v1 | -| test.cpp:3:14:3:15 | v1 | test.cpp:7:28:7:29 | v2 | -| test.cpp:4:13:4:14 | v1 | test.cpp:7:28:7:29 | v2 | -| test.cpp:5:27:5:28 | v1 | test.cpp:5:27:5:29 | call to shared_ptr | -| test.cpp:5:27:5:29 | call to shared_ptr | test.cpp:6:28:6:29 | p1 | -| test.cpp:5:27:5:29 | call to shared_ptr | test.cpp:6:28:6:29 | p1 | -| test.cpp:6:28:6:29 | p1 | test.cpp:6:31:6:33 | call to get | -| test.cpp:6:28:6:29 | p1 | test.cpp:6:31:6:33 | call to get | -| test.cpp:8:8:8:14 | 0 | test.cpp:9:28:9:29 | v2 | -| test.cpp:10:8:10:17 | new | test.cpp:11:28:11:29 | v2 | -| test.cpp:10:8:10:17 | new | test.cpp:12:28:12:29 | v2 | -| test.cpp:16:13:16:22 | new | test.cpp:17:27:17:28 | v1 | -| test.cpp:16:13:16:22 | new | test.cpp:19:6:19:7 | v1 | -| test.cpp:19:6:19:7 | v1 | test.cpp:3:14:3:15 | v1 | +| test.cpp:3:14:3:15 | v1 | test.cpp:5:27:5:28 | v1 | provenance | | +| test.cpp:3:14:3:15 | v1 | test.cpp:5:27:5:28 | v1 | provenance | | +| test.cpp:3:14:3:15 | v1 | test.cpp:7:28:7:29 | v2 | provenance | | +| test.cpp:4:13:4:14 | v1 | test.cpp:7:28:7:29 | v2 | provenance | | +| test.cpp:5:27:5:28 | v1 | test.cpp:5:27:5:29 | call to shared_ptr | provenance | | +| test.cpp:5:27:5:28 | v1 | test.cpp:5:27:5:29 | call to shared_ptr | provenance | Config | +| test.cpp:5:27:5:29 | call to shared_ptr | test.cpp:6:28:6:29 | p1 | provenance | | +| test.cpp:5:27:5:29 | call to shared_ptr | test.cpp:6:28:6:29 | p1 | provenance | | +| test.cpp:6:28:6:29 | p1 | test.cpp:6:31:6:33 | call to get | provenance | Config | +| test.cpp:6:28:6:29 | p1 | test.cpp:6:31:6:33 | call to get | provenance | Config | +| test.cpp:8:8:8:14 | 0 | test.cpp:9:28:9:29 | v2 | provenance | | +| test.cpp:10:8:10:17 | new | test.cpp:11:28:11:29 | v2 | provenance | | +| test.cpp:10:8:10:17 | new | test.cpp:12:28:12:29 | v2 | provenance | | +| test.cpp:16:13:16:22 | new | test.cpp:17:27:17:28 | v1 | provenance | | +| test.cpp:16:13:16:22 | new | test.cpp:19:6:19:7 | v1 | provenance | | +| test.cpp:19:6:19:7 | v1 | test.cpp:3:14:3:15 | v1 | provenance | | nodes | test.cpp:3:14:3:15 | v1 | semmle.label | v1 | | test.cpp:4:13:4:14 | v1 | semmle.label | v1 | diff --git a/cpp/common/test/rules/placementnewinsufficientstorage/PlacementNewInsufficientStorage.expected b/cpp/common/test/rules/placementnewinsufficientstorage/PlacementNewInsufficientStorage.expected index 3c38e192bc..a4c3bb1df6 100644 --- a/cpp/common/test/rules/placementnewinsufficientstorage/PlacementNewInsufficientStorage.expected +++ b/cpp/common/test/rules/placementnewinsufficientstorage/PlacementNewInsufficientStorage.expected @@ -7,18 +7,18 @@ problems | test.cpp:100:16:100:39 | new | test.cpp:65:36:65:38 | call to pop | test.cpp:100:21:100:28 | badAlloc | Placement new expression is used with an insufficiently large memory allocation from $@. | test.cpp:65:36:65:38 | call to pop | call to pop | | test.cpp:113:7:113:32 | new[] | test.cpp:113:14:113:21 | badAlloc | test.cpp:113:14:113:21 | badAlloc | Placement new expression is used with an insufficiently large memory allocation from $@. | test.cpp:113:14:113:21 | badAlloc | badAlloc | edges -| test.cpp:18:36:18:49 | call to operator new | test.cpp:19:21:19:44 | correctlyAllocatedMemory | -| test.cpp:24:37:24:50 | call to operator new | test.cpp:25:21:25:45 | correctlyAllocatedMemory2 | -| test.cpp:29:32:29:45 | call to operator new | test.cpp:31:21:31:40 | badlyAllocatedMemory | -| test.cpp:35:33:35:46 | call to operator new | test.cpp:37:21:37:41 | badlyAllocatedMemory2 | -| test.cpp:62:16:62:29 | call to operator new | test.cpp:67:12:67:17 | memory | -| test.cpp:62:16:62:29 | call to operator new | test.cpp:67:12:67:17 | memory | -| test.cpp:65:36:65:38 | call to pop | test.cpp:67:12:67:17 | memory | -| test.cpp:65:36:65:38 | call to pop | test.cpp:67:12:67:17 | memory | -| test.cpp:67:12:67:17 | memory | test.cpp:94:32:94:39 | call to allocate | -| test.cpp:67:12:67:17 | memory | test.cpp:98:31:98:38 | call to allocate | -| test.cpp:94:32:94:39 | call to allocate | test.cpp:95:21:95:29 | goodAlloc | -| test.cpp:98:31:98:38 | call to allocate | test.cpp:100:21:100:28 | badAlloc | +| test.cpp:18:36:18:49 | call to operator new | test.cpp:19:21:19:44 | correctlyAllocatedMemory | provenance | | +| test.cpp:24:37:24:50 | call to operator new | test.cpp:25:21:25:45 | correctlyAllocatedMemory2 | provenance | | +| test.cpp:29:32:29:45 | call to operator new | test.cpp:31:21:31:40 | badlyAllocatedMemory | provenance | | +| test.cpp:35:33:35:46 | call to operator new | test.cpp:37:21:37:41 | badlyAllocatedMemory2 | provenance | | +| test.cpp:62:16:62:29 | call to operator new | test.cpp:67:12:67:17 | memory | provenance | | +| test.cpp:62:16:62:29 | call to operator new | test.cpp:67:12:67:17 | memory | provenance | | +| test.cpp:65:36:65:38 | call to pop | test.cpp:67:12:67:17 | memory | provenance | | +| test.cpp:65:36:65:38 | call to pop | test.cpp:67:12:67:17 | memory | provenance | | +| test.cpp:67:12:67:17 | memory | test.cpp:94:32:94:39 | call to allocate | provenance | | +| test.cpp:67:12:67:17 | memory | test.cpp:98:31:98:38 | call to allocate | provenance | | +| test.cpp:94:32:94:39 | call to allocate | test.cpp:95:21:95:29 | goodAlloc | provenance | | +| test.cpp:98:31:98:38 | call to allocate | test.cpp:100:21:100:28 | badAlloc | provenance | | nodes | test.cpp:18:36:18:49 | call to operator new | semmle.label | call to operator new | | test.cpp:19:21:19:44 | correctlyAllocatedMemory | semmle.label | correctlyAllocatedMemory | diff --git a/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.expected b/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.expected new file mode 100644 index 0000000000..37e2557b81 --- /dev/null +++ b/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.expected @@ -0,0 +1,4 @@ +| test.cpp:41:12:41:37 | reinterpret_cast... | dynamic_cast not used for cast from pointer to base class C1 to derived class C2 which is $@. | test.cpp:11:12:11:28 | derivation | derived through virtual base class C1 | +| test.cpp:47:12:47:38 | reinterpret_cast... | dynamic_cast not used for cast from reference to base class C1 to derived class C2 which is $@. | test.cpp:11:12:11:28 | derivation | derived through virtual base class C1 | +| test.cpp:53:17:53:48 | reinterpret_cast... | dynamic_cast not used for cast from reference to base class C1 to derived class C2 which is $@. | test.cpp:11:12:11:28 | derivation | derived through virtual base class C1 | +| test.cpp:86:12:86:37 | reinterpret_cast... | dynamic_cast not used for cast from pointer to base class C0 to derived class C2 which is $@. | test.cpp:11:12:11:28 | derivation | derived through virtual base class C1 | diff --git a/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.ql b/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.ql new file mode 100644 index 0000000000..973b707e13 --- /dev/null +++ b/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.pointertoavirtualbaseclasscasttoapointer.PointerToAVirtualBaseClassCastToAPointer + +class TestFileQuery extends PointerToAVirtualBaseClassCastToAPointerSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/test.cpp b/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/test.cpp new file mode 100644 index 0000000000..ab4666069e --- /dev/null +++ b/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/test.cpp @@ -0,0 +1,87 @@ +class C0 { +public: + virtual ~C0() {} +}; + +class C1 : public C0 { +public: + virtual ~C1() {} +}; + +class C2 : public virtual C1 { +public: + C2() {} + ~C2() {} +}; + +typedef C1 Base; +typedef C2 Derived; + +void test_dynamic_cast_pointer_compliant() { + C2 l1; + C1 *p1 = &l1; + C2 *p2 = dynamic_cast(p1); // COMPLIANT +} + +void test_dynamic_cast_reference_compliant() { + C2 l1; + C1 *p1 = &l1; + C2 &l2 = dynamic_cast(*p1); // COMPLIANT +} + +void test_dynamic_cast_reference_compliant_typedefs() { + Derived l1; + Base *p1 = &l1; + Derived &l2 = dynamic_cast(*p1); // COMPLIANT +} + +void test_reinterpret_cast_pointer_non_compliant() { + C2 l1; + C1 *p1 = &l1; + C2 *p2 = reinterpret_cast(p1); // NON_COMPLIANT +} + +void test_reinterpret_cast_reference_non_compliant() { + C2 l1; + C1 *p1 = &l1; + C2 &l2 = reinterpret_cast(*p1); // NON_COMPLIANT +} + +void test_reinterpret_cast_typedefs_non_compliant() { + Derived l1; + Base *p1 = &l1; + Derived &l2 = reinterpret_cast(*p1); // NON_COMPLIANT +} + +void test_c_style_cast_pointer_non_compliant() { + C2 l1; + C1 *p1 = &l1; + // C2 *p2 = (C2 *)p1; // NON_COMPLIANT - prohibited by the compiler +} + +void test_c_style_cast_reference_non_compliant() { + C2 l1; + C1 *p1 = &l1; + // C2 &l2 = (C2 &)*p1; // NON_COMPLIANT - prohibited by the compiler +} + +void test_static_cast_pointer_non_compliant() { + C2 l1; + C1 *p1 = &l1; + // C2 *p2 = static_cast(p1); // NON_COMPLIANT - prohibited by the + // compiler +} + +void test_static_cast_reference_non_compliant() { + C2 l1; + C1 *p1 = &l1; + // C2 &l2 = static_cast(*p1); // NON_COMPLIANT - prohibited by the + // compiler +} + +void test_skipped_base_class() { + C2 l1; + C0 *p1 = &l1; + C2 *l2 = dynamic_cast(p1); // COMPLIANT + C2 *p2 = reinterpret_cast(p1); // NON_COMPLIANT +} \ No newline at end of file diff --git a/cpp/common/test/rules/potentiallyvirtualpointeronlycomparestonullptr/PotentiallyVirtualPointerOnlyComparesToNullptr.expected b/cpp/common/test/rules/potentiallyvirtualpointeronlycomparestonullptr/PotentiallyVirtualPointerOnlyComparesToNullptr.expected new file mode 100644 index 0000000000..71c0662377 --- /dev/null +++ b/cpp/common/test/rules/potentiallyvirtualpointeronlycomparestonullptr/PotentiallyVirtualPointerOnlyComparesToNullptr.expected @@ -0,0 +1,2 @@ +| test.cpp:14:14:14:29 | ... == ... | A pointer to member virtual function $@ is tested for equality with non-null-pointer-constant $@. | test.cpp:6:16:6:17 | F3 | F3 | test.cpp:14:24:14:29 | F1 | F1 | +| test.cpp:15:14:15:29 | ... == ... | A pointer to member virtual function $@ is tested for equality with non-null-pointer-constant $@. | test.cpp:6:16:6:17 | F3 | F3 | test.cpp:15:24:15:29 | F2 | F2 | diff --git a/cpp/common/test/rules/potentiallyvirtualpointeronlycomparestonullptr/PotentiallyVirtualPointerOnlyComparesToNullptr.ql b/cpp/common/test/rules/potentiallyvirtualpointeronlycomparestonullptr/PotentiallyVirtualPointerOnlyComparesToNullptr.ql new file mode 100644 index 0000000000..84263abc91 --- /dev/null +++ b/cpp/common/test/rules/potentiallyvirtualpointeronlycomparestonullptr/PotentiallyVirtualPointerOnlyComparesToNullptr.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.potentiallyvirtualpointeronlycomparestonullptr.PotentiallyVirtualPointerOnlyComparesToNullptr + +class TestFileQuery extends PotentiallyVirtualPointerOnlyComparesToNullptrSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/A5-10-1/test.cpp b/cpp/common/test/rules/potentiallyvirtualpointeronlycomparestonullptr/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A5-10-1/test.cpp rename to cpp/common/test/rules/potentiallyvirtualpointeronlycomparestonullptr/test.cpp diff --git a/cpp/common/test/rules/readofuninitializedmemory/test.cpp b/cpp/common/test/rules/readofuninitializedmemory/test.cpp index bdd3fdc203..6ed07d795f 100644 --- a/cpp/common/test/rules/readofuninitializedmemory/test.cpp +++ b/cpp/common/test/rules/readofuninitializedmemory/test.cpp @@ -121,4 +121,6 @@ void test_non_default_init() { use(slp); // COMPLIANT - static variables are zero initialized thread_local int *tlp; use(tlp); // COMPLIANT - thread local variables are zero initialized + _Atomic int ai; + use(ai); // COMPLIANT - atomics are special and not covered by this rule } \ No newline at end of file diff --git a/cpp/autosar/test/rules/A5-2-4/ReinterpretCastUsed.expected b/cpp/common/test/rules/reinterpretcastused/ReinterpretCastUsed.expected similarity index 100% rename from cpp/autosar/test/rules/A5-2-4/ReinterpretCastUsed.expected rename to cpp/common/test/rules/reinterpretcastused/ReinterpretCastUsed.expected diff --git a/cpp/common/test/rules/reinterpretcastused/ReinterpretCastUsed.ql b/cpp/common/test/rules/reinterpretcastused/ReinterpretCastUsed.ql new file mode 100644 index 0000000000..b58a7f4dbb --- /dev/null +++ b/cpp/common/test/rules/reinterpretcastused/ReinterpretCastUsed.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.reinterpretcastused.ReinterpretCastUsed + +class TestFileQuery extends ReinterpretCastUsedSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/A5-2-4/test.cpp b/cpp/common/test/rules/reinterpretcastused/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A5-2-4/test.cpp rename to cpp/common/test/rules/reinterpretcastused/test.cpp diff --git a/cpp/common/test/rules/resultofanassignmentoperatorshouldnotbeused/ResultOfAnAssignmentOperatorShouldNotBeUsed.expected b/cpp/common/test/rules/resultofanassignmentoperatorshouldnotbeused/ResultOfAnAssignmentOperatorShouldNotBeUsed.expected new file mode 100644 index 0000000000..3f2720dd76 --- /dev/null +++ b/cpp/common/test/rules/resultofanassignmentoperatorshouldnotbeused/ResultOfAnAssignmentOperatorShouldNotBeUsed.expected @@ -0,0 +1,3 @@ +| test.cpp:9:7:9:12 | ... = ... | Use of an assignment operator's result. | +| test.cpp:13:11:13:16 | ... = ... | Use of an assignment operator's result. | +| test.cpp:15:8:15:13 | ... = ... | Use of an assignment operator's result. | diff --git a/cpp/common/test/rules/resultofanassignmentoperatorshouldnotbeused/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql b/cpp/common/test/rules/resultofanassignmentoperatorshouldnotbeused/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql new file mode 100644 index 0000000000..286e4424a4 --- /dev/null +++ b/cpp/common/test/rules/resultofanassignmentoperatorshouldnotbeused/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.resultofanassignmentoperatorshouldnotbeused.ResultOfAnAssignmentOperatorShouldNotBeUsed + +class TestFileQuery extends ResultOfAnAssignmentOperatorShouldNotBeUsedSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/resultofanassignmentoperatorshouldnotbeused/test.cpp b/cpp/common/test/rules/resultofanassignmentoperatorshouldnotbeused/test.cpp new file mode 100644 index 0000000000..21fb4c0910 --- /dev/null +++ b/cpp/common/test/rules/resultofanassignmentoperatorshouldnotbeused/test.cpp @@ -0,0 +1,16 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +void test() { + int l1, l2; + int l3[1]; + + l1 = l2; // COMPLIANT + + if (l1 = 1) // NON_COMPLIANT + { + } + + l1 = l3[l2 = 0]; // NON_COMPLIANT + + l1 = l2 = 0; // NON_COMPLIANT +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/M7-5-1/FunctionReturnAutomaticVarCondition.expected b/cpp/common/test/rules/returnreferenceorpointertoautomaticlocalvariable/ReturnReferenceOrPointerToAutomaticLocalVariable.expected similarity index 100% rename from cpp/autosar/test/rules/M7-5-1/FunctionReturnAutomaticVarCondition.expected rename to cpp/common/test/rules/returnreferenceorpointertoautomaticlocalvariable/ReturnReferenceOrPointerToAutomaticLocalVariable.expected diff --git a/cpp/common/test/rules/returnreferenceorpointertoautomaticlocalvariable/ReturnReferenceOrPointerToAutomaticLocalVariable.ql b/cpp/common/test/rules/returnreferenceorpointertoautomaticlocalvariable/ReturnReferenceOrPointerToAutomaticLocalVariable.ql new file mode 100644 index 0000000000..c6c9c9e8fc --- /dev/null +++ b/cpp/common/test/rules/returnreferenceorpointertoautomaticlocalvariable/ReturnReferenceOrPointerToAutomaticLocalVariable.ql @@ -0,0 +1,5 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.returnreferenceorpointertoautomaticlocalvariable.ReturnReferenceOrPointerToAutomaticLocalVariable + +class TestFileQuery extends ReturnReferenceOrPointerToAutomaticLocalVariableSharedQuery, TestQuery { +} diff --git a/cpp/common/test/rules/returnreferenceorpointertoautomaticlocalvariable/test.cpp b/cpp/common/test/rules/returnreferenceorpointertoautomaticlocalvariable/test.cpp new file mode 100644 index 0000000000..d383d7859f --- /dev/null +++ b/cpp/common/test/rules/returnreferenceorpointertoautomaticlocalvariable/test.cpp @@ -0,0 +1,48 @@ +int *test_ptr_return_f2() { + int x = 100; + return &x; // NON_COMPLIANT +} + +int *test_ptr_return_f3(int y) { return &y; } // NON_COMPLIANT + +int &test_ref_return_f2() { + int x = 100; + return x; // NON_COMPLIANT +} + +int &test_ref_return_f3(int y) { return y; } // NON_COMPLIANT + +int *test_ptr_return_f4() { + static int x = 1; + return &x; // COMPLIANT +} + +int test_return_f2() { + int x = 100; + return x; // COMPLIANT +} +template void t1(T &x, T &y) { + if (x > y) + x = y; // NON_COMPLIANT[FALSE NEGATIVE] + else + x = -y; // NON_COMPLIANT[FALSE NEGATIVE] +} + +void test_templatefunction_return() { + int j = 2; + int k = 3; + t1(j, k); +} + +class C1 { +private: + int x; + +public: + int test() { return x; } // COMPLIANT - ignore member vars +}; + +int x; +int test_global() { + return x; // COMPLIANT - ignore global vars +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/M6-3-1/SwitchCompoundCondition.expected b/cpp/common/test/rules/switchcompoundcondition/SwitchCompoundCondition.expected similarity index 100% rename from cpp/autosar/test/rules/M6-3-1/SwitchCompoundCondition.expected rename to cpp/common/test/rules/switchcompoundcondition/SwitchCompoundCondition.expected diff --git a/cpp/common/test/rules/switchcompoundcondition/SwitchCompoundCondition.ql b/cpp/common/test/rules/switchcompoundcondition/SwitchCompoundCondition.ql new file mode 100644 index 0000000000..8fb855036c --- /dev/null +++ b/cpp/common/test/rules/switchcompoundcondition/SwitchCompoundCondition.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.switchcompoundcondition.SwitchCompoundCondition + +class TestFileQuery extends SwitchCompoundConditionSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/switchcompoundcondition/test.cpp b/cpp/common/test/rules/switchcompoundcondition/test.cpp new file mode 100644 index 0000000000..487c007fdc --- /dev/null +++ b/cpp/common/test/rules/switchcompoundcondition/test.cpp @@ -0,0 +1,56 @@ +void test_loop_missing_braces(int expression) { + for (int i = 0; i < expression; i++) // BAD + expression = expression % 2; +} + +void test_loop_valid_braces_check(int expression) { + for (int i = 0; i < expression; i++) { // GOOD + expression = expression % 2; + } + + int j = 10; + while (expression < 10) // BAD + j = j + 10; +} + +void test_loop_mix_validity(int expression) { + do // BAD + expression = expression % 2; + while (expression < 10); + + while (expression > 10) // GOOD + { + expression = expression * 2; + } + + do { // GOOD + expression = expression % 2; + } while (expression < 5); +} + +void test_switch_valid_braces(int i, int expression) { + // GOOD + switch (expression) { + case 0: + while (i < 10) { + i = i + expression; + } + break; + case 1: + if (i > 10) { + i = i * i; + } + break; + default: + break; + } +} + +void test_switch_invalid_braces(int i, int expression) { + // BAD + switch (expression) + case 0: + while (i < 10) { + i = i + expression; + } +} diff --git a/cpp/common/test/rules/throwingoperatornewreturnsnull/ThrowingOperatorNewReturnsNull.expected b/cpp/common/test/rules/throwingoperatornewreturnsnull/ThrowingOperatorNewReturnsNull.expected index ae8a0d626b..5e047a77da 100644 --- a/cpp/common/test/rules/throwingoperatornewreturnsnull/ThrowingOperatorNewReturnsNull.expected +++ b/cpp/common/test/rules/throwingoperatornewreturnsnull/ThrowingOperatorNewReturnsNull.expected @@ -3,8 +3,8 @@ problems | test.cpp:12:5:12:19 | return ... | test.cpp:12:12:12:18 | 0 | test.cpp:12:12:12:18 | 0 | operator new(size_t) may return null instead of throwing a std::bad_alloc exception. | | test.cpp:14:5:14:33 | return ... | test.cpp:4:10:4:23 | call to operator new | test.cpp:14:12:14:26 | call to can_return_null | operator new(size_t) may return null instead of throwing a std::bad_alloc exception. | edges -| test.cpp:4:10:4:23 | call to operator new | test.cpp:14:12:14:26 | call to can_return_null | -| test.cpp:8:23:8:23 | 0 | test.cpp:10:12:10:24 | localVariable | +| test.cpp:4:10:4:23 | call to operator new | test.cpp:14:12:14:26 | call to can_return_null | provenance | | +| test.cpp:8:23:8:23 | 0 | test.cpp:10:12:10:24 | localVariable | provenance | | nodes | test.cpp:4:10:4:23 | call to operator new | semmle.label | call to operator new | | test.cpp:8:23:8:23 | 0 | semmle.label | 0 | diff --git a/cpp/common/test/rules/unnecessaryexposedidentifierdeclarationshared/test.cpp b/cpp/common/test/rules/unnecessaryexposedidentifierdeclarationshared/test.cpp index ae3bb7b887..c4e01b8224 100644 --- a/cpp/common/test/rules/unnecessaryexposedidentifierdeclarationshared/test.cpp +++ b/cpp/common/test/rules/unnecessaryexposedidentifierdeclarationshared/test.cpp @@ -136,4 +136,96 @@ void f17() { ptr = &i; } *ptr = 1; -} \ No newline at end of file +} + +namespace a_namespace { + +constexpr static unsigned int a_constexpr_var{ + 10U}; // COMPLIANT; used in + // a_namespace and + // another_namespace_function +static unsigned int + a_namespace_var[a_constexpr_var]{}; // COMPLIANT; used in + // a_namespace_function and + // another_namespace_function + +constexpr static unsigned int a_namespace_function(void) noexcept { + unsigned int a_return_value{0U}; + + for (auto loop_var : a_namespace_var) { // usage of a_namespace_var + a_return_value += loop_var; + } + return a_return_value; +} + +constexpr static unsigned int another_namespace_function(void) noexcept { + unsigned int a_return_value{0U}; + + for (unsigned int i{0U}; i < a_constexpr_var; + i++) { // usage of a_constexpr_var + a_return_value += a_namespace_var[i]; // usage of a_namespace_var + } + return a_return_value; +} +} // namespace a_namespace + +namespace parent_namespace { +namespace child_namespace { +template class a_class_in_child_namespace { +public: + template constexpr auto &&operator()(To &&val) const noexcept { + return static_cast(val); + } +}; // a_class_in_child_namespace end + +template +extern constexpr a_class_in_child_namespace + a_class_in_child_namespace_impl{}; + +} // namespace child_namespace + +template +static constexpr auto const &a_parent_namespace_variable = + child_namespace::a_class_in_child_namespace_impl< + From>; // COMPLIANT; used in child_namespace2::a_class::bar() and + // parent_namespace::another_class::foo() + +namespace child_namespace2 { +class a_class { +public: + int func(...) { return 0; } + void foo(int x) { x++; } + template constexpr auto bar(F(*func), int b) { + foo(func(a_parent_namespace_variable( + b))); // usage of a_parent_namespace_variable + } +}; // a_class +} // namespace child_namespace2 + +class another_class { + int a; + int b; + void bar(int param) { param++; } + + bool has_value() { return a == b; } + +public: + template int foo(F(*func), int b) { + if (has_value()) { + bar(func(a_parent_namespace_variable( + b))); // usage of a_parent_namespace_variable + } + return 0; + } +}; // another_class +} // namespace parent_namespace + +template T a_func(T v) { return v++; } + +int main() { + parent_namespace::child_namespace2::a_class a_class_obj; + a_class_obj.bar(a_func, 10); + parent_namespace::another_class another_class_obj; + another_class_obj.foo(a_func, 10); + return 0; +} diff --git a/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.expected b/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.expected new file mode 100644 index 0000000000..3326ede548 --- /dev/null +++ b/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.expected @@ -0,0 +1,18 @@ +| test.cpp:111:3:111:12 | 2147483648 | Hex literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:116:3:116:20 | 9223372036854775808 | Hex literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:139:3:139:21 | 9223372036854775808 | Hex literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:162:3:162:21 | 9223372036854775808 | Hex literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:185:3:185:22 | 9223372036854775808 | Hex literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:208:3:208:22 | 9223372036854775808 | Hex literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:227:3:227:14 | 2147483648 | Octal literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:232:3:232:25 | 9223372036854775808 | Octal literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:249:3:249:26 | 9223372036854775808 | Octal literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:266:3:266:26 | 9223372036854775808 | Octal literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:283:3:283:27 | 9223372036854775808 | Octal literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:300:3:300:27 | 9223372036854775808 | Octal literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:315:3:315:36 | 2147483648 | Binary literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:322:3:322:68 | 9223372036854775808 | Binary literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:365:3:365:69 | 9223372036854775808 | Binary literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:412:3:412:69 | 9223372036854775808 | Binary literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:457:3:457:70 | 9223372036854775808 | Binary literal is an unsigned integer but does not include a 'U' suffix. | +| test.cpp:502:3:502:70 | 9223372036854775808 | Binary literal is an unsigned integer but does not include a 'U' suffix. | diff --git a/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.ql b/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.ql new file mode 100644 index 0000000000..30f07a3f22 --- /dev/null +++ b/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.ql @@ -0,0 +1,5 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.unsignedintegerliteralsnotappropriatelysuffixed.UnsignedIntegerLiteralsNotAppropriatelySuffixed + +class TestFileQuery extends UnsignedIntegerLiteralsNotAppropriatelySuffixedSharedQuery, TestQuery { +} diff --git a/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/test.cpp b/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/test.cpp new file mode 100644 index 0000000000..fcbd51b3de --- /dev/null +++ b/cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/test.cpp @@ -0,0 +1,546 @@ +// Assumed platform in qltest is linux_x86_64, so +// int, long, long long sizes are assumed to be 32, 64, 64 bits respectively + +// The type of an integer constant is determined by "6.4.4.1 Integer constants" +// in the C11 Standard. The principle is that any decimal integer constant will +// be signed, unless it has the `U` or `u` suffix. Any hexadecimal integer will +// depend on whether it is larger than the maximum value of the smallest signed +// integer value that can hold the value. So the signedness depends on the +// magnitude of the constant. + +void test_decimal_constants() { + 0; // COMPLIANT + 2147483648; // COMPLIANT - larger than int, but decimal constants never use + // unsigned without the suffix, so will be `long` + 4294967296; // COMPLIANT - larger than unsigned int, still `long` + 9223372036854775807; // COMPLIANT - max long int + // 9223372036854775808; Not a valid integer constant, out of signed range + 0U; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648U; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296U; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807U; // COMPLIANT - max long int + 9223372036854775808U; // COMPLIANT - explicitly unsigned, so can go large than + // max long int + 0u; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648u; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296u; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807u; // COMPLIANT - max long int + 9223372036854775808u; // COMPLIANT - explicitly unsigned, so can go large than + // max long int + + // l suffix + 0l; // COMPLIANT + 2147483648l; // COMPLIANT - within the range of long int + 4294967296l; // COMPLIANT - within the range of long int + 9223372036854775807l; // COMPLIANT - max long int + // 9223372036854775808l; Not a valid integer constant, out of signed range + 0lU; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648lU; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296lU; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807lU; // COMPLIANT - max long int + 9223372036854775808lU; // COMPLIANT - explicitly unsigned, so can go large + // than max long int + 0lu; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648lu; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296lu; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807lu; // COMPLIANT - max long int + 9223372036854775808lu; // COMPLIANT - explicitly unsigned, so can go large + // than max long int + + // L suffix + 0L; // COMPLIANT + 2147483648L; // COMPLIANT - within the range of long int + 4294967296L; // COMPLIANT - within the range of long int + 9223372036854775807L; // COMPLIANT - max long int + // 9223372036854775808L; Not a valid integer constant, out of signed range + 0LU; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648LU; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296LU; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807LU; // COMPLIANT - max long int + 9223372036854775808LU; // COMPLIANT - explicitly unsigned, so can go large + // than max long int + 0Lu; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648Lu; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296Lu; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807Lu; // COMPLIANT - max long int + 9223372036854775808Lu; // COMPLIANT - explicitly unsigned, so can go large + // than max long int + + // ll suffix + 0ll; // COMPLIANT + 2147483648ll; // COMPLIANT - within the range of long long int + 4294967296ll; // COMPLIANT - within the range of long long int + 9223372036854775807ll; // COMPLIANT - max long long int + // 9223372036854775808ll; Not a valid integer constant, out of signed range + 0llU; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648llU; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296llU; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807llU; // COMPLIANT - max long long int + 9223372036854775808llU; // COMPLIANT - explicitly unsigned, so can go large + // than max long long int + 0llu; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648llu; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296llu; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807llu; // COMPLIANT - max long long int + 9223372036854775808llu; // COMPLIANT - explicitly unsigned, so can go large + // than max long long int + + // LL suffix + 0LL; // COMPLIANT + 2147483648LL; // COMPLIANT - within the range of long long int + 4294967296LL; // COMPLIANT - within the range of long long int + 9223372036854775807LL; // COMPLIANT - max long long int + // 9223372036854775808LL; Not a valid integer constant, out of signed range + 0LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807LLU; // COMPLIANT - max long long int + 9223372036854775808LLU; // COMPLIANT - explicitly unsigned, so can go large + // than max long long int + 0LLu; // COMPLIANT - unsigned, but uses the suffix correctly + 2147483648LLu; // COMPLIANT - unsigned, but uses the suffix correctly + 4294967296LLu; // COMPLIANT - unsigned, but uses the suffix correctly + 9223372036854775807LLu; // COMPLIANT - max long long int + 9223372036854775808LLu; // COMPLIANT - explicitly unsigned, so can go large + // than max long long int +} + +void test_hexadecimal_constants() { + 0x0; // COMPLIANT - uses signed int + 0x7FFFFFFF; // COMPLIANT - max value held by signed int + 0x80000000; // NON_COMPLIANT - larger than max signed int, so will be unsigned + // int + 0x100000000; // COMPLIANT - larger than unsigned int, but smaller than long + // int + 0x7FFFFFFFFFFFFFFF; // COMPLIANT - max long int + 0x8000000000000000; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 0x0U; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000U; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000U; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000U; // COMPLIANT - unsigned, but uses the suffix correctly + 0x0u; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000u; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000u; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000u; // COMPLIANT - unsigned, but uses the suffix correctly + + // Use of the `l` suffix + 0x0l; // COMPLIANT - uses signed int + 0x7FFFFFFFl; // COMPLIANT - max value held by signed int + 0x80000000l; // COMPLIANT - larger than max signed int, but smaller than long + // int + 0x100000000l; // COMPLIANT - larger than unsigned int, but smaller than long + // int + 0x7FFFFFFFFFFFFFFFl; // COMPLIANT - max long int + 0x8000000000000000l; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 0x0lU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFlU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000lU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000lU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFlU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000lU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x0lu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFlu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000lu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000lu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFlu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000lu; // COMPLIANT - unsigned, but uses the suffix correctly + + // Use of the `L` suffix + 0x0L; // COMPLIANT - uses signed int + 0x7FFFFFFFL; // COMPLIANT - max value held by signed int + 0x80000000L; // COMPLIANT - larger than max signed int, but smaller than long + // int + 0x100000000L; // COMPLIANT - larger than unsigned int, but smaller than long + // int + 0x7FFFFFFFFFFFFFFFL; // COMPLIANT - max long int + 0x8000000000000000L; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 0x0LU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000LU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000LU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000LU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x0Lu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000Lu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000Lu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000Lu; // COMPLIANT - unsigned, but uses the suffix correctly + + // Use of the `ll` suffix + 0x0ll; // COMPLIANT - uses signed int + 0x7FFFFFFFll; // COMPLIANT - max value held by signed int + 0x80000000ll; // COMPLIANT - larger than max signed int, but smaller than long + // long int + 0x100000000ll; // COMPLIANT - larger than unsigned int, but smaller than long + // long int + 0x7FFFFFFFFFFFFFFFll; // COMPLIANT - max long long int + 0x8000000000000000ll; // NON_COMPLIANT - larger than long long int, so will be + // unsigned long long int + 0x0llU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFllU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000llU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000llU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFllU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000llU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x0llu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFllu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000llu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000llu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFllu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000llu; // COMPLIANT - unsigned, but uses the suffix correctly + + // Use of the `LL` suffix + 0x0LL; // COMPLIANT - uses signed int + 0x7FFFFFFFLL; // COMPLIANT - max value held by signed int + 0x80000000LL; // COMPLIANT - larger than max signed int, but smaller than long + // long int + 0x100000000LL; // COMPLIANT - larger than unsigned int, but smaller than long + // long int + 0x7FFFFFFFFFFFFFFFLL; // COMPLIANT - max long long int + 0x8000000000000000LL; // NON_COMPLIANT - larger than long long int, so will be + // unsigned long long int + 0x0LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFLLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFLLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000LLU; // COMPLIANT - unsigned, but uses the suffix correctly + 0x0LLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFLLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x80000000LLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x100000000LLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x7FFFFFFFFFFFFFFFLLu; // COMPLIANT - unsigned, but uses the suffix correctly + 0x8000000000000000LLu; // COMPLIANT - unsigned, but uses the suffix correctly +} + +void test_octal_constants() { + 00; // COMPLIANT - uses signed int + 017777777777; // COMPLIANT - max value held by signed int + 020000000000; // NON_COMPLIANT - larger than max signed int, so will be + // unsigned int + 040000000000; // COMPLIANT - larger than unsigned int, but smaller than long + // int + 0777777777777777777777; // COMPLIANT - max long int + 01000000000000000000000; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00U; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777U; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000U; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000U; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777U; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000U; // COMPLIANT - unsigned, but uses the suffix + // correctly + + // Use of the `l` suffix + 00l; // COMPLIANT - uses signed long + 017777777777l; // COMPLIANT - uses signed long + 020000000000l; // COMPLIANT - uses signed long + 040000000000l; // COMPLIANT - uses signed long + 0777777777777777777777l; // COMPLIANT - max long int + 01000000000000000000000l; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00Ul; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777Ul; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000Ul; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000Ul; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777Ul; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000Ul; // COMPLIANT - unsigned, but uses the suffix + // correctly + + // Use of the `L` suffix + 00L; // COMPLIANT - uses signed long + 017777777777L; // COMPLIANT - uses signed long + 020000000000L; // COMPLIANT - uses signed long + 040000000000L; // COMPLIANT - uses signed long + 0777777777777777777777L; // COMPLIANT - COMPLIANT - uses signed long + 01000000000000000000000L; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00UL; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777UL; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000UL; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000UL; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777UL; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000UL; // COMPLIANT - unsigned, but uses the suffix + // correctly + + // Use of the `ll` suffix + 00ll; // COMPLIANT - uses signed long long + 017777777777ll; // COMPLIANT - uses signed long long + 020000000000ll; // COMPLIANT - uses signed long long + 040000000000ll; // COMPLIANT - uses signed long long + 0777777777777777777777ll; // COMPLIANT - max long int + 01000000000000000000000ll; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00Ull; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777Ull; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000Ull; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000Ull; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777Ull; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000Ull; // COMPLIANT - unsigned, but uses the suffix + // correctly + + // Use of the `LL` suffix + 00LL; // COMPLIANT - uses signed long long + 017777777777LL; // COMPLIANT - uses signed long long + 020000000000LL; // COMPLIANT - uses signed long long + 040000000000LL; // COMPLIANT - uses signed long long + 0777777777777777777777LL; // COMPLIANT - max long int + 01000000000000000000000LL; // NON_COMPLIANT - larger than long int, so will be + // unsigned long int + 00ULL; // COMPLIANT - unsigned, but uses the suffix correctly + 017777777777ULL; // COMPLIANT - unsigned, but uses the suffix correctly + 020000000000ULL; // COMPLIANT - unsigned, but uses the suffix correctly + 040000000000ULL; // COMPLIANT - unsigned, but uses the suffix correctly + 0777777777777777777777ULL; // COMPLIANT - unsigned, but uses the suffix + // correctly + 01000000000000000000000ULL; // COMPLIANT - unsigned, but uses the suffix + // correctly +} + +void test_binary_constants() { + 0b0; // COMPLIANT - uses signed int + 0b1111111111111111111111111111111; // COMPLIANT - max value held by signed int + 0b10000000000000000000000000000000; // NON_COMPLIANT - larger than max signed + // int, so will be unsigned int + 0b100000000000000000000000000000000; // COMPLIANT - larger than unsigned int, + // but smaller than long int + 0b111111111111111111111111111111111111111111111111111111111111111; // COMPLIANT + // - max + // long int + 0b1000000000000000000000000000000000000000000000000000000000000000; // NON_COMPLIANT + // - + // larger + // than + // long + // int, so + // will be + // unsigned + // long + // int + 0b0U; // COMPLIANT - unsigned, but uses the suffix correctly + 0b1111111111111111111111111111111U; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b10000000000000000000000000000000U; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b100000000000000000000000000000000U; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b111111111111111111111111111111111111111111111111111111111111111U; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly + 0b1000000000000000000000000000000000000000000000000000000000000000U; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly + + // Use of the `l` suffix + 0b0l; // COMPLIANT - uses signed long + 0b1111111111111111111111111111111l; // COMPLIANT - uses signed long + 0b10000000000000000000000000000000l; // COMPLIANT - uses signed long + 0b100000000000000000000000000000000l; // COMPLIANT - uses signed long + 0b111111111111111111111111111111111111111111111111111111111111111l; // COMPLIANT + // - max + // long + // int + 0b1000000000000000000000000000000000000000000000000000000000000000l; // NON_COMPLIANT + // - + // larger + // than + // long + // int, + // so + // will + // be + // unsigned + // long + // int + 0b0Ul; // COMPLIANT - unsigned, but uses the suffix correctly + 0b1111111111111111111111111111111Ul; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b10000000000000000000000000000000Ul; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b100000000000000000000000000000000Ul; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b111111111111111111111111111111111111111111111111111111111111111Ul; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly + 0b1000000000000000000000000000000000000000000000000000000000000000Ul; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly + + // Use of the `L` suffix + 0b0L; // COMPLIANT - uses signed long + 0b1111111111111111111111111111111L; // COMPLIANT - uses signed long + 0b10000000000000000000000000000000L; // COMPLIANT - uses signed long + 0b100000000000000000000000000000000L; // COMPLIANT - uses signed long + 0b111111111111111111111111111111111111111111111111111111111111111L; // COMPLIANT + // - + // COMPLIANT + // - uses + // signed + // long + 0b1000000000000000000000000000000000000000000000000000000000000000L; // NON_COMPLIANT + // - + // larger + // than + // long + // int, + // so + // will + // be + // unsigned + // long + // int + 0b0UL; // COMPLIANT - unsigned, but uses the suffix correctly + 0b1111111111111111111111111111111UL; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b10000000000000000000000000000000UL; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b100000000000000000000000000000000UL; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b111111111111111111111111111111111111111111111111111111111111111UL; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly + 0b1000000000000000000000000000000000000000000000000000000000000000UL; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly + + // Use of the `ll` suffix + 0b0ll; // COMPLIANT - uses signed long long + 0b1111111111111111111111111111111ll; // COMPLIANT - uses signed long long + 0b10000000000000000000000000000000ll; // COMPLIANT - uses signed long long + 0b100000000000000000000000000000000ll; // COMPLIANT - uses signed long long + 0b111111111111111111111111111111111111111111111111111111111111111ll; // COMPLIANT + // - max + // long + // int + 0b1000000000000000000000000000000000000000000000000000000000000000ll; // NON_COMPLIANT + // - + // larger + // than + // long + // int, + // so + // will + // be + // unsigned + // long + // int + 0b0Ull; // COMPLIANT - unsigned, but uses the suffix correctly + 0b1111111111111111111111111111111Ull; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b10000000000000000000000000000000Ull; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b100000000000000000000000000000000Ull; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b111111111111111111111111111111111111111111111111111111111111111Ull; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly + 0b1000000000000000000000000000000000000000000000000000000000000000Ull; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly + + // Use of the `LL` suffix + 00LL; // COMPLIANT - uses signed long long + 0b1111111111111111111111111111111LL; // COMPLIANT - uses signed long long + 0b10000000000000000000000000000000LL; // COMPLIANT - uses signed long long + 0b100000000000000000000000000000000LL; // COMPLIANT - uses signed long long + 0b111111111111111111111111111111111111111111111111111111111111111LL; // COMPLIANT + // - max + // long + // int + 0b1000000000000000000000000000000000000000000000000000000000000000LL; // NON_COMPLIANT + // - + // larger + // than + // long + // int, + // so + // will + // be + // unsigned + // long + // int + 00ULL; // COMPLIANT - unsigned, but uses the suffix correctly + 0b1111111111111111111111111111111ULL; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b10000000000000000000000000000000ULL; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b100000000000000000000000000000000ULL; // COMPLIANT - unsigned, but uses the + // suffix correctly + 0b111111111111111111111111111111111111111111111111111111111111111ULL; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly + 0b1000000000000000000000000000000000000000000000000000000000000000ULL; // COMPLIANT + // - + // unsigned, + // but + // uses + // the + // suffix + // correctly +} + +#define COMPLIANT_VAL 0x80000000U +#define NON_COMPLIANT_VAL 0x80000000 + +void test_macro() { + COMPLIANT_VAL; // COMPLIANT + NON_COMPLIANT_VAL; // NON_COMPLIANT[FALSE_NEGATIVE] - cannot determine suffix + // in macro expansions +} \ No newline at end of file diff --git a/cpp/common/test/rules/unsignedoperationwithconstantoperandswraps/UnsignedOperationWithConstantOperandsWraps.expected b/cpp/common/test/rules/unsignedoperationwithconstantoperandswraps/UnsignedOperationWithConstantOperandsWraps.expected new file mode 100644 index 0000000000..3902cae09d --- /dev/null +++ b/cpp/common/test/rules/unsignedoperationwithconstantoperandswraps/UnsignedOperationWithConstantOperandsWraps.expected @@ -0,0 +1,4 @@ +| test.cpp:7:3:7:9 | ... + ... | Operation + of type unsigned int may wrap. | +| test.cpp:8:3:8:10 | ... += ... | Operation += of type unsigned int may wrap. | +| test.cpp:61:3:61:9 | ... - ... | Operation - of type unsigned int may wrap. | +| test.cpp:62:3:62:10 | ... -= ... | Operation -= of type unsigned int may wrap. | diff --git a/cpp/common/test/rules/unsignedoperationwithconstantoperandswraps/UnsignedOperationWithConstantOperandsWraps.ql b/cpp/common/test/rules/unsignedoperationwithconstantoperandswraps/UnsignedOperationWithConstantOperandsWraps.ql new file mode 100644 index 0000000000..b88e7637c1 --- /dev/null +++ b/cpp/common/test/rules/unsignedoperationwithconstantoperandswraps/UnsignedOperationWithConstantOperandsWraps.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.unsignedoperationwithconstantoperandswraps.UnsignedOperationWithConstantOperandsWraps + +class TestFileQuery extends UnsignedOperationWithConstantOperandsWrapsSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/unsignedoperationwithconstantoperandswraps/test.cpp b/cpp/common/test/rules/unsignedoperationwithconstantoperandswraps/test.cpp new file mode 100644 index 0000000000..8f76fbeeeb --- /dev/null +++ b/cpp/common/test/rules/unsignedoperationwithconstantoperandswraps/test.cpp @@ -0,0 +1,83 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. + +#include + +void test_add_simple(unsigned int i1, unsigned int i2) { + i1 + i2; // NON_COMPLIANT - not bounds checked + i1 += i2; // NON_COMPLIANT - not bounds checked +} + +void test_add_precheck(unsigned int i1, unsigned int i2) { + if (UINT_MAX - i1 < i2) { + // handle error + } else { + i1 + i2; // COMPLIANT - bounds checked + i1 += i2; // COMPLIANT - bounds checked + } +} + +void test_add_precheck_2(unsigned int i1, unsigned int i2) { + if (i1 + i2 < i1) { + // handle error + } else { + i1 + i2; // COMPLIANT - bounds checked + i1 += i2; // COMPLIANT - bounds checked + } +} + +void test_add_postcheck(unsigned int i1, unsigned int i2) { + unsigned int i3 = i1 + i2; // COMPLIANT - checked for overflow afterwards + if (i3 < i1) { + // handle error + } + i1 += i2; // COMPLIANT - checked for overflow afterwards + if (i1 < i2) { + // handle error + } +} + +void test_ex2(unsigned int i1, unsigned int i2) { + unsigned int ci1 = 2; + unsigned int ci2 = 3; + ci1 + ci2; // COMPLIANT, compile time constants + i1 + 0; // COMPLIANT + i1 += 0; // COMPLIANT + i1 - 0; // COMPLIANT + i1 -= 0; // COMPLIANT + UINT_MAX - i1; // COMPLIANT - cannot be smaller than 0 + i1 * 1; // COMPLIANT + i1 *= 1; // COMPLIANT + if (0 <= i1 && i1 < 32) { + UINT_MAX >> i1; // COMPLIANT + } +} + +void test_ex3(unsigned int i1, unsigned int i2) { + i1 << i2; // COMPLIANT - by EX3 +} + +void test_sub_simple(unsigned int i1, unsigned int i2) { + i1 - i2; // NON_COMPLIANT - not bounds checked + i1 -= i2; // NON_COMPLIANT - not bounds checked +} + +void test_sub_precheck(unsigned int i1, unsigned int i2) { + if (i1 < i2) { + // handle error + } else { + i1 - i2; // COMPLIANT - bounds checked + i1 -= i2; // COMPLIANT - bounds checked + } +} + +void test_sub_postcheck(unsigned int i1, unsigned int i2) { + unsigned int i3 = i1 - i2; // COMPLIANT - checked for wrap afterwards + if (i3 > i1) { + // handle error + } + i1 -= i2; // COMPLIANT - checked for wrap afterwards + if (i1 > i2) { + // handle error + } +} \ No newline at end of file diff --git a/cpp/common/test/rules/useofnonzerooctalliteral/UseOfNonZeroOctalLiteral.expected b/cpp/common/test/rules/useofnonzerooctalliteral/UseOfNonZeroOctalLiteral.expected new file mode 100644 index 0000000000..e4280f2f1a --- /dev/null +++ b/cpp/common/test/rules/useofnonzerooctalliteral/UseOfNonZeroOctalLiteral.expected @@ -0,0 +1,2 @@ +| test.cpp:5:3:5:5 | 10 | Non zero octal literal 012. | +| test.cpp:6:3:6:5 | 44 | Non zero octal literal 054. | diff --git a/cpp/common/test/rules/useofnonzerooctalliteral/UseOfNonZeroOctalLiteral.ql b/cpp/common/test/rules/useofnonzerooctalliteral/UseOfNonZeroOctalLiteral.ql new file mode 100644 index 0000000000..0404a7bc0c --- /dev/null +++ b/cpp/common/test/rules/useofnonzerooctalliteral/UseOfNonZeroOctalLiteral.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.useofnonzerooctalliteral.UseOfNonZeroOctalLiteral + +class TestFileQuery extends UseOfNonZeroOctalLiteralSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/useofnonzerooctalliteral/test.cpp b/cpp/common/test/rules/useofnonzerooctalliteral/test.cpp new file mode 100644 index 0000000000..0bf928c9ec --- /dev/null +++ b/cpp/common/test/rules/useofnonzerooctalliteral/test.cpp @@ -0,0 +1,7 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +void test_non_zero_octal() { + 0; // COMPLIANT - octal literal zero permitted + 012; // NON_COMPLIANT + 054; // NON_COMPLIANT +} \ No newline at end of file diff --git a/cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.expected b/cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.expected new file mode 100644 index 0000000000..eab4694e7c --- /dev/null +++ b/cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.expected @@ -0,0 +1,52 @@ +| test.cpp:5:17:5:18 | uc | Variable 'uc' has variable-width type. | +| test.cpp:6:15:6:16 | sc | Variable 'sc' has variable-width type. | +| test.cpp:8:7:8:7 | i | Variable 'i' has variable-width type. | +| test.cpp:9:16:9:17 | ui | Variable 'ui' has variable-width type. | +| test.cpp:10:12:10:12 | u | Variable 'u' has variable-width type. | +| test.cpp:11:14:11:15 | si | Variable 'si' has variable-width type. | +| test.cpp:12:10:12:10 | s | Variable 's' has variable-width type. | +| test.cpp:14:9:14:10 | sh | Variable 'sh' has variable-width type. | +| test.cpp:15:18:15:20 | ush | Variable 'ush' has variable-width type. | +| test.cpp:16:16:16:18 | ssh | Variable 'ssh' has variable-width type. | +| test.cpp:18:8:18:8 | l | Variable 'l' has variable-width type. | +| test.cpp:19:17:19:18 | ul | Variable 'ul' has variable-width type. | +| test.cpp:20:15:20:16 | sl | Variable 'sl' has variable-width type. | +| test.cpp:39:23:39:25 | uc1 | Variable 'uc1' has variable-width type. | +| test.cpp:40:21:40:23 | sc1 | Variable 'sc1' has variable-width type. | +| test.cpp:42:13:42:14 | i1 | Variable 'i1' has variable-width type. | +| test.cpp:43:22:43:24 | ui1 | Variable 'ui1' has variable-width type. | +| test.cpp:44:18:44:19 | u1 | Variable 'u1' has variable-width type. | +| test.cpp:45:20:45:22 | si1 | Variable 'si1' has variable-width type. | +| test.cpp:46:16:46:17 | s1 | Variable 's1' has variable-width type. | +| test.cpp:48:15:48:17 | sh1 | Variable 'sh1' has variable-width type. | +| test.cpp:49:24:49:27 | ush1 | Variable 'ush1' has variable-width type. | +| test.cpp:50:22:50:25 | ssh1 | Variable 'ssh1' has variable-width type. | +| test.cpp:52:14:52:15 | l1 | Variable 'l1' has variable-width type. | +| test.cpp:53:23:53:25 | ul1 | Variable 'ul1' has variable-width type. | +| test.cpp:54:21:54:23 | sl1 | Variable 'sl1' has variable-width type. | +| test.cpp:57:26:57:28 | uc2 | Variable 'uc2' has variable-width type. | +| test.cpp:58:24:58:26 | sc2 | Variable 'sc2' has variable-width type. | +| test.cpp:60:16:60:17 | i2 | Variable 'i2' has variable-width type. | +| test.cpp:61:25:61:27 | ui2 | Variable 'ui2' has variable-width type. | +| test.cpp:62:21:62:22 | u2 | Variable 'u2' has variable-width type. | +| test.cpp:63:23:63:25 | si2 | Variable 'si2' has variable-width type. | +| test.cpp:64:19:64:20 | s2 | Variable 's2' has variable-width type. | +| test.cpp:66:18:66:20 | sh2 | Variable 'sh2' has variable-width type. | +| test.cpp:67:27:67:30 | ush2 | Variable 'ush2' has variable-width type. | +| test.cpp:68:25:68:28 | ssh2 | Variable 'ssh2' has variable-width type. | +| test.cpp:70:17:70:18 | l2 | Variable 'l2' has variable-width type. | +| test.cpp:71:26:71:28 | ul2 | Variable 'ul2' has variable-width type. | +| test.cpp:72:24:72:26 | sl2 | Variable 'sl2' has variable-width type. | +| test.cpp:93:15:93:39 | test_unsigned_char_return | Function 'test_unsigned_char_return' has variable-width return type. | +| test.cpp:96:13:96:35 | test_signed_char_return | Function 'test_signed_char_return' has variable-width return type. | +| test.cpp:99:5:99:19 | test_int_return | Function 'test_int_return' has variable-width return type. | +| test.cpp:102:14:102:37 | test_unsigned_int_return | Function 'test_unsigned_int_return' has variable-width return type. | +| test.cpp:105:10:105:29 | test_unsigned_return | Function 'test_unsigned_return' has variable-width return type. | +| test.cpp:108:12:108:33 | test_signed_int_return | Function 'test_signed_int_return' has variable-width return type. | +| test.cpp:111:8:111:25 | test_signed_return | Function 'test_signed_return' has variable-width return type. | +| test.cpp:114:7:114:23 | test_short_return | Function 'test_short_return' has variable-width return type. | +| test.cpp:117:16:117:41 | test_unsigned_short_return | Function 'test_unsigned_short_return' has variable-width return type. | +| test.cpp:120:14:120:37 | test_signed_short_return | Function 'test_signed_short_return' has variable-width return type. | +| test.cpp:123:6:123:21 | test_long_return | Function 'test_long_return' has variable-width return type. | +| test.cpp:126:15:126:39 | test_unsigned_long_return | Function 'test_unsigned_long_return' has variable-width return type. | +| test.cpp:129:13:129:35 | test_signed_long_return | Function 'test_signed_long_return' has variable-width return type. | diff --git a/cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.ql b/cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.ql new file mode 100644 index 0000000000..1c86ca86d7 --- /dev/null +++ b/cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.variablewidthintegertypesused.VariableWidthIntegerTypesUsed + +class TestFileQuery extends VariableWidthIntegerTypesUsedSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/variablewidthintegertypesused/test.cpp b/cpp/common/test/rules/variablewidthintegertypesused/test.cpp new file mode 100644 index 0000000000..bee63342e2 --- /dev/null +++ b/cpp/common/test/rules/variablewidthintegertypesused/test.cpp @@ -0,0 +1,155 @@ +#include + +void test_variable_width_type_variables() { + char c; // COMPLIANT + unsigned char uc; // NON_COMPLIANT + signed char sc; // NON_COMPLIANT + + int i; // NON_COMPLIANT + unsigned int ui; // NON_COMPLIANT + unsigned u; // NON_COMPLIANT + signed int si; // NON_COMPLIANT + signed s; // NON_COMPLIANT + + short sh; // NON_COMPLIANT + unsigned short ush; // NON_COMPLIANT + signed short ssh; // NON_COMPLIANT + + long l; // NON_COMPLIANT + unsigned long ul; // NON_COMPLIANT + signed long sl; // NON_COMPLIANT + + std::int8_t i8; // COMPLIANT + std::int16_t i16; // COMPLIANT + std::int32_t i32; // COMPLIANT + std::int64_t i64; // COMPLIANT + + std::uint8_t u8; // COMPLIANT + std::uint16_t u16; // COMPLIANT + std::uint32_t u32; // COMPLIANT + std::uint64_t u64; // COMPLIANT +} + +int main(int argc, char *argv[]) { // COMPLIANT + // main as an exception +} + +void test_variable_width_type_qualified_variables() { + const char c1 = 0; // COMPLIANT + const unsigned char uc1 = 0; // NON_COMPLIANT + const signed char sc1 = 0; // NON_COMPLIANt + + const int i1 = 0; // NON_COMPLIANT + const unsigned int ui1 = 0; // NON_COMPLIANT + const unsigned u1 = 0; // NON_COMPLIANT + const signed int si1 = 0; // NON_COMPLIANT + const signed s1 = 0; // NON_COMPLIANT + + const short sh1 = 0; // NON_COMPLIANT + const unsigned short ush1 = 0; // NON_COMPLIANT + const signed short ssh1 = 0; // NON_COMPLIANT + + const long l1 = 0; // NON_COMPLIANT + const unsigned long ul1 = 0; // NON_COMPLIANT + const signed long sl1 = 0; // NON_COMPLIANT + + volatile char c2; // COMPLIANT + volatile unsigned char uc2; // NON_COMPLIANT + volatile signed char sc2; // NON_COMPLIANt + + volatile int i2; // NON_COMPLIANT + volatile unsigned int ui2; // NON_COMPLIANT + volatile unsigned u2; // NON_COMPLIANT + volatile signed int si2; // NON_COMPLIANT + volatile signed s2; // NON_COMPLIANT + + volatile short sh2; // NON_COMPLIANT + volatile unsigned short ush2; // NON_COMPLIANT + volatile signed short ssh2; // NON_COMPLIANT + + volatile long l2; // NON_COMPLIANT + volatile unsigned long ul2; // NON_COMPLIANT + volatile signed long sl2; // NON_COMPLIANT +} + +struct test_fix_fp_614 { + test_fix_fp_614 operator++(int); // COMPLIANT + test_fix_fp_614 operator--(int); // COMPLIANT +}; + +// COMPLIANT - instantiated with Fixed Width Types. +template constexpr void test_fix_fp_540(MyType value) { + value++; +} + +void call_test_fix_fp_540() { + test_fix_fp_540(19); + test_fix_fp_540(20); +} + +char test_char_return() { // COMPLIANT + return 'a'; +} +unsigned char test_unsigned_char_return() { // NON_COMPLIANT + return 'b'; +} +signed char test_signed_char_return() { // NON_COMPLIANT + return 'c'; +} +int test_int_return() { // NON_COMPLIANT + return 42; +} +unsigned int test_unsigned_int_return() { // NON_COMPLIANT + return 43; +} +unsigned test_unsigned_return() { // NON_COMPLIANT + return 44; +} +signed int test_signed_int_return() { // NON_COMPLIANT + return 45; +} +signed test_signed_return() { // NON_COMPLIANT + return 46; +} +short test_short_return() { // NON_COMPLIANT + return 47; +} +unsigned short test_unsigned_short_return() { // NON_COMPLIANT + return 48; +} +signed short test_signed_short_return() { // NON_COMPLIANT + return 49; +} +long test_long_return() { // NON_COMPLIANT + return 50; +} +unsigned long test_unsigned_long_return() { // NON_COMPLIANT + return 51; +} +signed long test_signed_long_return() { // NON_COMPLIANT + return 52; +} +std::int8_t test_int8_t_return() { // COMPLIANT + return 53; +} +std::int16_t test_int16_t_return() { // COMPLIANT + return 54; +} +std::int32_t test_int32_t_return() { // COMPLIANT + return 55; +} +std::int64_t test_int64_t_return() { // COMPLIANT + return 56; +} +std::uint8_t test_uint8_t_return() { // COMPLIANT + return 57; +} +std::uint16_t test_uint16_t_return() { // COMPLIANT + return 58; +} +std::uint32_t test_uint32_t_return() { // COMPLIANT + return 59; +} +std::uint64_t test_uint64_t_return() { // COMPLIANT + return 60; +} diff --git a/cpp/autosar/test/rules/A18-1-2/VectorboolSpecializationUsed.expected b/cpp/common/test/rules/vectorshouldnotbespecializedwithbool/VectorShouldNotBeSpecializedWithBool.expected similarity index 100% rename from cpp/autosar/test/rules/A18-1-2/VectorboolSpecializationUsed.expected rename to cpp/common/test/rules/vectorshouldnotbespecializedwithbool/VectorShouldNotBeSpecializedWithBool.expected diff --git a/cpp/autosar/test/rules/A18-1-2/VectorboolSpecializationUsed.expected.qcc b/cpp/common/test/rules/vectorshouldnotbespecializedwithbool/VectorShouldNotBeSpecializedWithBool.expected.qcc similarity index 100% rename from cpp/autosar/test/rules/A18-1-2/VectorboolSpecializationUsed.expected.qcc rename to cpp/common/test/rules/vectorshouldnotbespecializedwithbool/VectorShouldNotBeSpecializedWithBool.expected.qcc diff --git a/cpp/common/test/rules/vectorshouldnotbespecializedwithbool/VectorShouldNotBeSpecializedWithBool.ql b/cpp/common/test/rules/vectorshouldnotbespecializedwithbool/VectorShouldNotBeSpecializedWithBool.ql new file mode 100644 index 0000000000..a965d5e5d6 --- /dev/null +++ b/cpp/common/test/rules/vectorshouldnotbespecializedwithbool/VectorShouldNotBeSpecializedWithBool.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.vectorshouldnotbespecializedwithbool.VectorShouldNotBeSpecializedWithBool + +class TestFileQuery extends VectorShouldNotBeSpecializedWithBoolSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/A18-1-2/test.cpp b/cpp/common/test/rules/vectorshouldnotbespecializedwithbool/test.cpp similarity index 100% rename from cpp/autosar/test/rules/A18-1-2/test.cpp rename to cpp/common/test/rules/vectorshouldnotbespecializedwithbool/test.cpp diff --git a/cpp/autosar/test/rules/M10-1-3/AccessibleBaseClassBothVirtualAndNonVirtualInHierarchy.expected b/cpp/common/test/rules/virtualandnonvirtualclassinthehierarchy/VirtualAndNonVirtualClassInTheHierarchy.expected similarity index 100% rename from cpp/autosar/test/rules/M10-1-3/AccessibleBaseClassBothVirtualAndNonVirtualInHierarchy.expected rename to cpp/common/test/rules/virtualandnonvirtualclassinthehierarchy/VirtualAndNonVirtualClassInTheHierarchy.expected diff --git a/cpp/common/test/rules/virtualandnonvirtualclassinthehierarchy/VirtualAndNonVirtualClassInTheHierarchy.ql b/cpp/common/test/rules/virtualandnonvirtualclassinthehierarchy/VirtualAndNonVirtualClassInTheHierarchy.ql new file mode 100644 index 0000000000..2137cbeb66 --- /dev/null +++ b/cpp/common/test/rules/virtualandnonvirtualclassinthehierarchy/VirtualAndNonVirtualClassInTheHierarchy.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.virtualandnonvirtualclassinthehierarchy.VirtualAndNonVirtualClassInTheHierarchy + +class TestFileQuery extends VirtualAndNonVirtualClassInTheHierarchySharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/M10-1-3/test.cpp b/cpp/common/test/rules/virtualandnonvirtualclassinthehierarchy/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M10-1-3/test.cpp rename to cpp/common/test/rules/virtualandnonvirtualclassinthehierarchy/test.cpp diff --git a/cpp/misra/src/codeql-pack.lock.yml b/cpp/misra/src/codeql-pack.lock.yml index 514e6963d0..a45ea8f438 100644 --- a/cpp/misra/src/codeql-pack.lock.yml +++ b/cpp/misra/src/codeql-pack.lock.yml @@ -2,13 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.9.3 + version: 4.0.3 codeql/dataflow: - version: 0.0.4 + version: 2.0.3 + codeql/mad: + version: 1.0.19 + codeql/rangeanalysis: + version: 1.0.19 codeql/ssa: - version: 0.1.5 + version: 1.0.19 codeql/tutorial: - version: 0.1.5 + version: 1.0.19 + codeql/typeflow: + version: 1.0.19 + codeql/typetracking: + version: 2.0.3 codeql/util: - version: 0.1.5 + version: 2.0.6 + codeql/xml: + version: 1.0.19 compiled: false diff --git a/cpp/misra/src/codeql-suites/misra-cpp-advisory.qls b/cpp/misra/src/codeql-suites/misra-cpp-advisory.qls new file mode 100644 index 0000000000..5da16cc2af --- /dev/null +++ b/cpp/misra/src/codeql-suites/misra-cpp-advisory.qls @@ -0,0 +1,12 @@ +- description: MISRA C++ 2023 (Default) +- qlpack: codeql/misra-cpp-coding-standards +- include: + kind: + - problem + - path-problem + tags contain: + - external/misra/obligation/advisory +- exclude: + tags contain: + - external/misra/audit + - external/misra/default-disabled diff --git a/cpp/misra/src/codeql-suites/misra-cpp-default.qls b/cpp/misra/src/codeql-suites/misra-cpp-default.qls new file mode 100644 index 0000000000..670b043caa --- /dev/null +++ b/cpp/misra/src/codeql-suites/misra-cpp-default.qls @@ -0,0 +1,10 @@ +- description: MISRA C++ 2023 (Default) +- qlpack: codeql/misra-cpp-coding-standards +- include: + kind: + - problem + - path-problem +- exclude: + tags contain: + - external/misra/audit + - external/misra/default-disabled diff --git a/cpp/misra/src/codeql-suites/misra-cpp-mandatory.qls b/cpp/misra/src/codeql-suites/misra-cpp-mandatory.qls new file mode 100644 index 0000000000..0c5ec7155f --- /dev/null +++ b/cpp/misra/src/codeql-suites/misra-cpp-mandatory.qls @@ -0,0 +1,12 @@ +- description: MISRA C++ 2023 (Default) +- qlpack: codeql/misra-cpp-coding-standards +- include: + kind: + - problem + - path-problem + tags contain: + - external/misra/obligation/mandatory +- exclude: + tags contain: + - external/misra/audit + - external/misra/default-disabled diff --git a/cpp/misra/src/codeql-suites/misra-cpp-required.qls b/cpp/misra/src/codeql-suites/misra-cpp-required.qls new file mode 100644 index 0000000000..2fe61301e7 --- /dev/null +++ b/cpp/misra/src/codeql-suites/misra-cpp-required.qls @@ -0,0 +1,12 @@ +- description: MISRA C++ 2023 (Default) +- qlpack: codeql/misra-cpp-coding-standards +- include: + kind: + - problem + - path-problem + tags contain: + - external/misra/obligation/required +- exclude: + tags contain: + - external/misra/audit + - external/misra/default-disabled diff --git a/cpp/misra/src/codeql-suites/misra-cpp-single-translation-unit.qls b/cpp/misra/src/codeql-suites/misra-cpp-single-translation-unit.qls new file mode 100644 index 0000000000..0782dd876d --- /dev/null +++ b/cpp/misra/src/codeql-suites/misra-cpp-single-translation-unit.qls @@ -0,0 +1,12 @@ +- description: MISRA C++ 2023 (Single Translation Unit) +- qlpack: codeql/misra-cpp-coding-standards +- include: + kind: + - problem + - path-problem + tags contain: + - scope/single-translation-unit +- exclude: + tags contain: + - external/misra/audit + - external/misra/default-disabled diff --git a/cpp/misra/src/codeql-suites/misra-default.qls b/cpp/misra/src/codeql-suites/misra-default.qls new file mode 100644 index 0000000000..3c205157cd --- /dev/null +++ b/cpp/misra/src/codeql-suites/misra-default.qls @@ -0,0 +1,2 @@ +- description: "DEPRECATED - MISRA C++ 2023 - use misra-cpp-default.qls instead" +- import: codeql-suites/misra-cpp-default.qls diff --git a/cpp/misra/src/codeql-suites/misra-single-translation-unit.qls b/cpp/misra/src/codeql-suites/misra-single-translation-unit.qls new file mode 100644 index 0000000000..9dcd3f0c97 --- /dev/null +++ b/cpp/misra/src/codeql-suites/misra-single-translation-unit.qls @@ -0,0 +1,2 @@ +- description: "DEPRECATED - MISRA C++ 2023 (Single Translation Unit) - use misra-cpp-single-translation-unit.qls instead" +- import: codeql-suites/misra-cpp-single-translation-unit.qls diff --git a/cpp/misra/src/codingstandards/cpp/misra.qll b/cpp/misra/src/codingstandards/cpp/misra.qll new file mode 100644 index 0000000000..ff308d4fd2 --- /dev/null +++ b/cpp/misra/src/codingstandards/cpp/misra.qll @@ -0,0 +1,4 @@ +import cpp +import misra.Customizations +import codingstandards.cpp.CodingStandards +import codingstandards.cpp.exclusions.cpp.RuleMetadata diff --git a/cpp/misra/src/codingstandards/cpp/misra/ArithmeticConversions.qll b/cpp/misra/src/codingstandards/cpp/misra/ArithmeticConversions.qll new file mode 100644 index 0000000000..42ec1f3a10 --- /dev/null +++ b/cpp/misra/src/codingstandards/cpp/misra/ArithmeticConversions.qll @@ -0,0 +1,183 @@ +import cpp +import BuiltInTypeRules + +/** + * An expression that represents a integral promotion or usual arithmetic conversion. + * + * Such conversions are usual either explicitly described with a `Cast`, or, in the case + * of assign operations, implicitly applied to an lvalue. + */ +abstract class IntegerPromotionOrUsualArithmeticConversion extends Expr { + abstract MisraCpp23BuiltInTypes::NumericType getFromType(); + + abstract MisraCpp23BuiltInTypes::NumericType getToType(); + + abstract Expr getConvertedExpr(); + + abstract string getKindOfConversion(); +} + +/** + * A `Cast` which is either an integer promotion or usual arithmetic conversion. + */ +abstract class IntegerPromotionOrUsualArithmeticConversionAsCast extends IntegerPromotionOrUsualArithmeticConversion, + Cast +{ + MisraCpp23BuiltInTypes::NumericType fromType; + MisraCpp23BuiltInTypes::NumericType toType; + + IntegerPromotionOrUsualArithmeticConversionAsCast() { + fromType = this.getExpr().getType() and + toType = this.getType() and + this.isImplicit() + } + + override MisraCpp23BuiltInTypes::NumericType getFromType() { result = fromType } + + override MisraCpp23BuiltInTypes::NumericType getToType() { result = toType } + + override Expr getConvertedExpr() { result = this.getExpr() } +} + +class UsualArithmeticConversion extends IntegerPromotionOrUsualArithmeticConversionAsCast { + UsualArithmeticConversion() { + ( + // Most binary operations from and to numeric types participate in usual arithmetic conversions + exists(BinaryOperation op | + // Shifts do not participate in usual arithmetic conversions + not op instanceof LShiftExpr and + not op instanceof RShiftExpr and + op.getAnOperand().getFullyConverted() = this + ) + or + // Most binary assignment operations from and to numeric types participate in usual arithmetic + // conversions + exists(AssignOperation ao | + // Shifts do not participate in usual arithmetic conversions + not ao instanceof AssignLShiftExpr and + not ao instanceof AssignRShiftExpr and + ao.getRValue().getFullyConverted() = this + ) + ) + } + + override string getKindOfConversion() { result = "Usual arithmetic conversion" } +} + +class IntegerPromotion extends IntegerPromotionOrUsualArithmeticConversionAsCast { + IntegerPromotion() { + // In the case where a conversion involves both an integer promotion and a usual arithmetic conversion + // we only get a single `Conversion` which combines both. According to the rule, only the "final" type + // should be consider, so we handle these combined conversions as `UsualArithmeticConversion`s instead. + not this instanceof UsualArithmeticConversion and + // Only consider cases where the integer promotion is the last conversion applied + exists(Expr e | e.getFullyConverted() = this) and + // Integer promotion occurs where the from type is smaller than int + fromType.getBuiltInSize() < sizeOfInt() and + // To type is bigger than or equal to int + toType.getBuiltInSize() >= sizeOfInt() and + // An integer promotion is a conversion from an integral type to an integral type + // + // This deliberately excludes integer promotions from `bool` and unscoped enums which do not + // have a fixed underlying type, because neither of these are considered integral types in the + // MISRA C++ rules. + fromType.getTypeCategory() = MisraCpp23BuiltInTypes::IntegralTypeCategory() and + toType.getTypeCategory() = MisraCpp23BuiltInTypes::IntegralTypeCategory() + } + + override string getKindOfConversion() { result = "Integer promotion" } +} + +class ImpliedUsualArithmeticConversion extends IntegerPromotionOrUsualArithmeticConversion { + MisraCpp23BuiltInTypes::NumericType fromType; + MisraCpp23BuiltInTypes::NumericType toType; + + ImpliedUsualArithmeticConversion() { + // The lvalue of an assignment operation does not have a `Conversion` in our model, but + // it is still subject to usual arithmetic conversions (excepting shifts). + // + // rvalues are handled separately in the `UsualArithmeticConversion` class. + exists(AssignOperation aop | + not aop instanceof AssignLShiftExpr and + not aop instanceof AssignRShiftExpr and + // lvalue subject to usual arithmetic conversions + aop.getLValue() = this and + // From type is the type of the lvalue, which should be a numeric type under the MISRA rule + fromType = this.getType() and + // Under usual arithmetic conversions, the converted types of both arguments will be the same, + // so even though we don't have an explicit conversion, we can still deduce that the target + // type will be the same as the converted type of the rvalue. + toType = aop.getRValue().getFullyConverted().getType() and + // Only consider cases where the conversion is not a no-op, for consistency with the `Conversion` class + not fromType.isSameType(toType) + ) + } + + override MisraCpp23BuiltInTypes::NumericType getFromType() { result = fromType } + + override MisraCpp23BuiltInTypes::NumericType getToType() { result = toType } + + override Expr getConvertedExpr() { result = this } + + override string getKindOfConversion() { result = "Usual arithmetic conversion" } +} + +class ImpliedIntegerPromotion extends IntegerPromotionOrUsualArithmeticConversion { + MisraCpp23BuiltInTypes::NumericType fromType; + + ImpliedIntegerPromotion() { + ( + exists(AssignLShiftExpr aop | aop.getLValue() = this) or + exists(AssignRShiftExpr aop | aop.getLValue() = this) + ) and + // The rule applies to integer promotions from and to MISRA C++ numeric types + // However, you cannot have an integer promotion on a float, so we restrict + // this to integral types only + fromType = this.getType() and + fromType.getTypeCategory() = MisraCpp23BuiltInTypes::IntegralTypeCategory() and + // If the size is less than int, then it is an implied integer promotion + fromType.getBuiltInSize() < sizeOfInt() + } + + override MisraCpp23BuiltInTypes::NumericType getFromType() { result = fromType } + + override MisraCpp23BuiltInTypes::CanonicalIntegerNumericType getToType() { + // Only report the canonical type - e.g. `int` not `signed int` + if result instanceof Char16Type or result instanceof Char32Type or result instanceof Wchar_t + then + // Smallest type that can hold the value of the `fromType` + result = + min(MisraCpp23BuiltInTypes::NumericType candidateType | + ( + candidateType instanceof IntType or + candidateType instanceof LongType or + candidateType instanceof LongLongType + ) and + fromType.getIntegralUpperBound() <= candidateType.getIntegralUpperBound() + | + candidateType order by candidateType.getIntegralUpperBound() + ) + else ( + if + // If the `fromType` is signed, the result must be signed + fromType.getSignedness() = MisraCpp23BuiltInTypes::Signed() + or + // If the `fromType` is unsigned, but the result can fit into the signed int type, then the + // result must be signed as well. + fromType.getIntegralUpperBound() <= + any(IntType t | t.isSigned()) + .(MisraCpp23BuiltInTypes::NumericType) + .getIntegralUpperBound() + then + // `int` is returned + result.(IntType).isSigned() + else + // Otherwise `unsigned int` is returned + result.(IntType).isUnsigned() + ) + } + + override Expr getConvertedExpr() { result = this } + + override string getKindOfConversion() { result = "Integer promotion" } +} diff --git a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll new file mode 100644 index 0000000000..eb6652c342 --- /dev/null +++ b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll @@ -0,0 +1,311 @@ +/** + * A library for utility classes related to the built-in type rules in MISRA C++ 2023 (Section 4.7.0). + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.Call +import codingstandards.cpp.Type +import codingstandards.cpp.types.CanonicalTypes + +module MisraCpp23BuiltInTypes { + /** + * A MISRA C++ 2023 type category. + */ + newtype TypeCategory = + IntegralTypeCategory() or + FloatingPointTypeCategory() or + CharacterTypeCategory() or + OtherTypeCategory() + + /** + * Gets the type category of a built-in type. + * + * This does not apply the rules related to stripping specifiers or typedefs, or references. + */ + private TypeCategory getBuiltInTypeCategory(BuiltInType t) { + ( + t instanceof PlainCharType or + t instanceof WideCharType or + t instanceof Char16Type or + t instanceof Char32Type or + t instanceof Char8Type + ) and + result = CharacterTypeCategory() + or + ( + // The 5 standard integral types, covering both signed/unsigned variants + // Explicitly list the signed/unsigned `char` to avoid capturing plain `char`, which is of character type category + t instanceof SignedCharType or + t instanceof UnsignedCharType or + t instanceof ShortType or + t instanceof IntType or + t instanceof LongType or + t instanceof LongLongType + ) and + result = IntegralTypeCategory() + or + ( + t instanceof FloatType or + t instanceof DoubleType or + t instanceof LongDoubleType + ) and + result = FloatingPointTypeCategory() + or + ( + t instanceof BoolType or + t instanceof VoidType or + t instanceof NullPointerType + ) and + result = OtherTypeCategory() + } + + /** + * Gets the built-in type of a type, if it is a built-in type. + * + * This function will strip specifiers and typedefs to get the underlying built-in type. + */ + private BuiltInType getBuiltInType(Type t) { + // Get the built-in type of a type, if it is a built-in type + result = t + or + // Strip specifiers and typedefs to get the built-in type + result = getBuiltInType(t.getUnspecifiedType()) + or + // For reference types, get the base type and then the built-in type + result = getBuiltInType(t.(ReferenceType).getBaseType()) + or + // For enum types, get the explicit underlying type and then the built-in type + result = getBuiltInType(t.(Enum).getExplicitUnderlyingType()) + } + + /** + * The signedness of a MISRA C++ 2023 numeric type. + */ + newtype Signedness = + Signed() or + Unsigned() + + /** + * A `Type` which is considered to be a built-in type by MISRA. + * + * It differs from `BuiltInType` in that includes: + * - Built in types with specifiers (e.g., `const`, `volatile`, `restrict`). + * - Typedefs to built in types + * - References to built in types + * - Enum types with an explicit underlying type that is a built-in type. + * + * Note: this does not extend `Type` directly, to prevent accidental use of `getSize()`, which + * returns the "wrong" size for e.g. reference types. + */ + class MisraBuiltInType extends Element { + // The built in type underlying this MISRA built in type + BuiltInType builtInType; + + MisraBuiltInType() { builtInType = getBuiltInType(this) } + + private BuiltInType getBuiltInType() { result = builtInType } + + /** Gets the size of the underlying built in type. */ + int getBuiltInSize() { result = builtInType.getSize() } + + TypeCategory getTypeCategory() { result = getBuiltInTypeCategory(builtInType) } + + predicate isSameType(MisraBuiltInType other) { this.getBuiltInType() = other.getBuiltInType() } + + string getName() { result = this.(Type).getName() } + } + + class CharacterType extends MisraBuiltInType { + CharacterType() { + // A type whose type category is character + getBuiltInTypeCategory(builtInType) = CharacterTypeCategory() + } + } + + /** + * A MISRA C++ 2023 numeric type is a type that represents a number, either an integral or a floating-point. + * + * In addition to the basic integral and floating-point types, it includes: + * - Enum types with an explicit underlying type that is a numeric type. + * - Typedef'd types that are numeric types. + * - Numeric types with specifiers (e.g., `const`, `volatile`, `restrict`). + */ + class NumericType extends MisraBuiltInType { + NumericType() { + // A type whose type category is either integral or a floating-point + getBuiltInTypeCategory(builtInType) = + [IntegralTypeCategory().(TypeCategory), FloatingPointTypeCategory()] + } + + Signedness getSignedness() { + if builtInType.(IntegralType).isUnsigned() then result = Unsigned() else result = Signed() + } + + /** + * Gets the integeral upper bound of the numeric type, if it represents an integer type. + */ + QlBuiltins::BigInt getIntegralUpperBound() { integralTypeBounds(builtInType, _, result) } + + /** + * Gets the integeral lower bound of the numeric type, if it represents an integer type. + */ + QlBuiltins::BigInt getIntegralLowerBound() { integralTypeBounds(builtInType, result, _) } + } + + predicate isSignedType(NumericType t) { t.getSignedness() = Signed() } + + predicate isUnsignedType(NumericType t) { t.getSignedness() = Unsigned() } + + /** + * A canonical integer type for each unique size and signedness combination. + * + * Where multiple canonical arithmetic types exist for a given size/signedness combination, we + * prefer the type with the shortest name. + */ + class CanonicalIntegerNumericType extends NumericType { + CanonicalIntegerNumericType() { + // Where multiple types exist with the same size and signedness, prefer shorter names - mainly + // to disambiguate between `unsigned long` and `unsigned long long` on platforms where they + // are the same size + this.(CanonicalIntegralType).isMinimal() + or + // `signed char` is not considered a canonical type (`char` is), but `char` is not a MISRA numeric + // type, so we need to reintroduce `signed char` here. + this instanceof SignedCharType + } + } + + predicate isAssignment(Expr source, Type targetType, string context) { + exists(Expr preConversionAssignment | + isPreConversionAssignment(preConversionAssignment, targetType, context) and + preConversionAssignment.getExplicitlyConverted() = source + ) + } + + predicate isPreConversionAssignment(Expr source, Type targetType, string context) { + if isAssignedToBitfield(source, _) + then + // For the MISRA type rules we treat bit fields as a special case + exists(BitField bf | + isAssignedToBitfield(source, bf) and + targetType = getBitFieldType(bf) and + context = "assignment to bitfield" + ) + else ( + // Assignment expression (which excludes compound assignments) + exists(AssignExpr assign | + assign.getRValue() = source and + context = "assignment" + | + exists(Type t | t = assign.getLValue().getType() | + // Unwrap PointerToMemberType e.g `l1.*l2 = x;` + if t instanceof PointerToMemberType + then targetType = t.(PointerToMemberType).getBaseType() + else targetType = t + ) + ) + or + // Variable initialization + exists(Variable v, Initializer init | + init.getExpr() = source and + v.getInitializer() = init and + context = "initialization" + | + targetType = v.getType() + ) + or + exists(ConstructorFieldInit fi | + fi.getExpr() = source and + context = "constructor field initialization" + | + targetType = fi.getTarget().getType() + ) + or + // Passing a function parameter by value + exists(Call call, int i | + call.getArgument(i) = source and + not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and + context = "function argument" + | + // A regular function call + targetType = call.getTarget().getParameter(i).getType() + or + // A function call where the argument is passed as varargs + call.getTarget().getNumberOfParameters() <= i and + // The rule states that the type should match the "adjusted" type of the argument + targetType = source.getFullyConverted().getType() + or + // An expression call - get the function type, then the parameter type + targetType = getExprCallFunctionType(call).getParameterType(i) + ) + or + // Return statement + exists(ReturnStmt ret, Function f | + ret.getExpr() = source and + ret.getEnclosingFunction() = f and + targetType = f.getType() and + not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and + context = "return" + ) + or + // Switch case + exists(SwitchCase case, SwitchStmt switch | + case.getExpr() = source and + case.getSwitchStmt() = switch and + context = "switch case" + | + // Get the type of the switch expression, which is the type of the case expression + targetType = switch.getExpr().getFullyConverted().getType() + ) + or + // Class aggregate literal initialization + exists(ClassAggregateLiteral al, Field f | + source = al.getAFieldExpr(f) and + context = "class aggregate literal" + | + targetType = f.getType() + ) + or + // Array or vector aggregate literal initialization + exists(ArrayOrVectorAggregateLiteral vl | + source = vl.getAnElementExpr(_) and + targetType = vl.getElementType() and + context = "array or vector aggregate literal" + ) + ) + } + + /** + * Gets the smallest integral type that can hold the value of a bit field. + * + * The type is determined by the signedness of the bit field and the number of bits. + */ + CanonicalIntegerNumericType getBitFieldType(BitField bf) { + exists(NumericType bitfieldActualType | + bitfieldActualType = bf.getType() and + // Integral type with the same signedness as the bit field, and big enough to hold the bit field value + result.getSignedness() = bitfieldActualType.getSignedness() and + result.getBuiltInSize() * 8 >= bf.getNumBits() and + // No smaller integral type can hold the bit field value + not exists(CanonicalIntegerNumericType other | + other.getBuiltInSize() * 8 >= bf.getNumBits() and + other.getSignedness() = result.getSignedness() + | + other.getBuiltInSize() < result.getBuiltInSize() + ) + ) + } + + /** + * Holds if the `source` expression is "assigned" to a bit field per MISRA C++ 2023. + */ + predicate isAssignedToBitfield(Expr source, BitField bf) { + source = bf.getAnAssignedValue().getExplicitlyConverted() + or + exists(SwitchStmt switch, SwitchCase case | + bf = switch.getExpr().(FieldAccess).getTarget() and + source = case.getExpr() + ) + } +} diff --git a/cpp/misra/src/codingstandards/cpp/misra/Customizations.qll b/cpp/misra/src/codingstandards/cpp/misra/Customizations.qll new file mode 100644 index 0000000000..b95d1bb3b3 --- /dev/null +++ b/cpp/misra/src/codingstandards/cpp/misra/Customizations.qll @@ -0,0 +1,8 @@ +/** + * Contains customizations to the MISRA C++ query rules. + * + * This module is imported by `misra.qll`, so any customizations defined here + * automatically apply to all MISRA C++ queries. + */ + +import cpp diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index 11cca34ca9..89bb103b09 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,8 +1,8 @@ name: codeql/misra-cpp-coding-standards -version: 2.32.0-dev -description: MISRA C++ 2008 -suites: codeql-suites +version: 2.52.0-dev +description: MISRA C++ 2023 +default-suite: codeql-suites/misra-cpp-default.qls license: MIT dependencies: codeql/common-cpp-coding-standards: '*' - codeql/cpp-all: 0.9.3 + codeql/cpp-all: 4.0.3 diff --git a/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql b/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql new file mode 100644 index 0000000000..0e3363137e --- /dev/null +++ b/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/possible-misuse-of-infinite-floating-point-value + * @name DIR-0-3-1: Possible misuse of a generate infinite floating point value + * @description Possible misuse of a generate infinite floating point value. + * @kind path-problem + * @precision medium + * @problem.severity warning + * @tags external/misra/id/dir-0-3-1 + * correctness + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.misuseofinfinitefloatingpointvalue.MisuseOfInfiniteFloatingPointValue + +class PossibleMisuseOfInfiniteFloatingPointValueQuery extends MisuseOfInfiniteFloatingPointValueSharedQuery +{ + PossibleMisuseOfInfiniteFloatingPointValueQuery() { + this = FloatingPointPackage::possibleMisuseOfInfiniteFloatingPointValueQuery() + } +} diff --git a/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.ql b/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.ql new file mode 100644 index 0000000000..035edd85b8 --- /dev/null +++ b/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/possible-misuse-of-nan-floating-point-value + * @name DIR-0-3-1: Possible mishandling of an undetected NaN value produced by a floating point operation + * @description Possible mishandling of an undetected NaN value produced by a floating point + * operation. + * @kind path-problem + * @precision low + * @problem.severity warning + * @tags external/misra/id/dir-0-3-1 + * correctness + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.misuseofnanfloatingpointvalue.MisuseOfNaNFloatingPointValue + +class PossibleMisuseOfNaNFloatingPointValueQuery extends MisuseOfNaNFloatingPointValueSharedQuery { + PossibleMisuseOfNaNFloatingPointValueQuery() { + this = FloatingPointPackage::possibleMisuseOfNaNFloatingPointValueQuery() + } +} diff --git a/cpp/misra/src/rules/DIR-15-8-1/CopyAndMoveAssignmentsShallHandleSelfAssignment.ql b/cpp/misra/src/rules/DIR-15-8-1/CopyAndMoveAssignmentsShallHandleSelfAssignment.ql new file mode 100644 index 0000000000..daf6e89530 --- /dev/null +++ b/cpp/misra/src/rules/DIR-15-8-1/CopyAndMoveAssignmentsShallHandleSelfAssignment.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/copy-and-move-assignments-shall-handle-self-assignment + * @name DIR-15-8-1: User-provided copy assignment operators and move assignment operators shall handle self-assignment + * @description User-provided copy assignment operators and move assignment operators shall handle + * self-assignment. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/dir-15-8-1 + * external/misra/allocated-target/implementation + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.copyandmoveassignmentsshallhandleselfassignment.CopyAndMoveAssignmentsShallHandleSelfAssignment + +class CopyAndMoveAssignmentsShallHandleSelfAssignmentQuery extends CopyAndMoveAssignmentsShallHandleSelfAssignmentSharedQuery +{ + CopyAndMoveAssignmentsShallHandleSelfAssignmentQuery() { + this = ImportMisra23Package::copyAndMoveAssignmentsShallHandleSelfAssignmentQuery() + } +} diff --git a/cpp/misra/src/rules/DIR-5-7-2/SectionsOfCodeShouldNotBeCommentedOut.ql b/cpp/misra/src/rules/DIR-5-7-2/SectionsOfCodeShouldNotBeCommentedOut.ql new file mode 100644 index 0000000000..e51ae39d3d --- /dev/null +++ b/cpp/misra/src/rules/DIR-5-7-2/SectionsOfCodeShouldNotBeCommentedOut.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/sections-of-code-should-not-be-commented-out + * @name DIR-5-7-2: Sections of code should not be “commented out” + * @description Commented out code may become out of date leading to developer confusion. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/dir-5-7-2 + * maintainability + * readability + * correctness + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.sectionsofcodeshallnotbecommentedout.SectionsOfCodeShallNotBeCommentedOut + +class SectionsOfCodeShouldNotBeCommentedOutQuery extends SectionsOfCodeShallNotBeCommentedOutSharedQuery +{ + SectionsOfCodeShouldNotBeCommentedOutQuery() { + this = ImportMisra23Package::sectionsOfCodeShouldNotBeCommentedOutQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-10-0-1/UseSingleGlobalOrMemberDeclarators.ql b/cpp/misra/src/rules/RULE-10-0-1/UseSingleGlobalOrMemberDeclarators.ql new file mode 100644 index 0000000000..ffbc5bacaf --- /dev/null +++ b/cpp/misra/src/rules/RULE-10-0-1/UseSingleGlobalOrMemberDeclarators.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/use-single-global-or-member-declarators + * @name RULE-10-0-1: Multiple declarations in the same global or member declaration sequence + * @description A declaration should not declare more than one variable or member variable. + * @kind problem + * @precision medium + * @problem.severity recommendation + * @tags external/misra/id/rule-10-0-1 + * readability + * maintainability + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.multipleglobalormemberdeclarators.MultipleGlobalOrMemberDeclarators + +class UseSingleGlobalOrMemberDeclaratorsQuery extends MultipleGlobalOrMemberDeclaratorsSharedQuery { + UseSingleGlobalOrMemberDeclaratorsQuery() { + this = ImportMisra23Package::useSingleGlobalOrMemberDeclaratorsQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-10-0-1/UseSingleLocalDeclarators.ql b/cpp/misra/src/rules/RULE-10-0-1/UseSingleLocalDeclarators.ql new file mode 100644 index 0000000000..6d756daa87 --- /dev/null +++ b/cpp/misra/src/rules/RULE-10-0-1/UseSingleLocalDeclarators.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/use-single-local-declarators + * @name RULE-10-0-1: Multiple declarations in the same local statement + * @description A declaration should not declare more than one variable or member variable. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-10-0-1 + * readability + * maintainability + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.multiplelocaldeclarators.MultipleLocalDeclarators + +class UseSingleLocalDeclaratorsQuery extends MultipleLocalDeclaratorsSharedQuery { + UseSingleLocalDeclaratorsQuery() { this = ImportMisra23Package::useSingleLocalDeclaratorsQuery() } +} diff --git a/cpp/misra/src/rules/RULE-10-2-1/EnumerationNotDefinedWithAnExplicitUnderlyingType.ql b/cpp/misra/src/rules/RULE-10-2-1/EnumerationNotDefinedWithAnExplicitUnderlyingType.ql new file mode 100644 index 0000000000..ab4b6a19a1 --- /dev/null +++ b/cpp/misra/src/rules/RULE-10-2-1/EnumerationNotDefinedWithAnExplicitUnderlyingType.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/enumeration-not-defined-with-an-explicit-underlying-type + * @name RULE-10-2-1: An enumeration shall be defined with an explicit underlying type + * @description An enumeration shall be defined with an explicit underlying type. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-10-2-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.enumerationnotdefinedwithanexplicitunderlyingtype.EnumerationNotDefinedWithAnExplicitUnderlyingType + +class EnumerationNotDefinedWithAnExplicitUnderlyingTypeQuery extends EnumerationNotDefinedWithAnExplicitUnderlyingTypeSharedQuery +{ + EnumerationNotDefinedWithAnExplicitUnderlyingTypeQuery() { + this = ImportMisra23Package::enumerationNotDefinedWithAnExplicitUnderlyingTypeQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-10-4-1/AsmDeclarationShallNotBeUsed.ql b/cpp/misra/src/rules/RULE-10-4-1/AsmDeclarationShallNotBeUsed.ql new file mode 100644 index 0000000000..5a2f4c4265 --- /dev/null +++ b/cpp/misra/src/rules/RULE-10-4-1/AsmDeclarationShallNotBeUsed.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/asm-declaration-shall-not-be-used + * @name RULE-10-4-1: The asm declaration shall not be used + * @description The asm declaration shall not be used. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-10-4-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.asmdeclarationused.AsmDeclarationUsed + +class AsmDeclarationShallNotBeUsedQuery extends AsmDeclarationUsedSharedQuery { + AsmDeclarationShallNotBeUsedQuery() { + this = ImportMisra23Package::asmDeclarationShallNotBeUsedQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-11-3-2/DeclarationOfAnObjectIndirectionsLevel.ql b/cpp/misra/src/rules/RULE-11-3-2/DeclarationOfAnObjectIndirectionsLevel.ql new file mode 100644 index 0000000000..ddbe4a3db0 --- /dev/null +++ b/cpp/misra/src/rules/RULE-11-3-2/DeclarationOfAnObjectIndirectionsLevel.ql @@ -0,0 +1,26 @@ +/** + * @id cpp/misra/declaration-of-an-object-indirections-level + * @name RULE-11-3-2: The declaration of an object should contain no more than two levels of pointer indirection + * @description Declarations with more than two levels of pointer nesting can result in code that is + * difficult to read and understand. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-11-3-2 + * readability + * maintainability + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.donotusemorethantwolevelsofpointerindirection.DoNotUseMoreThanTwoLevelsOfPointerIndirection + +class DeclarationOfAnObjectIndirectionsLevelQuery extends DoNotUseMoreThanTwoLevelsOfPointerIndirectionSharedQuery +{ + DeclarationOfAnObjectIndirectionsLevelQuery() { + this = ImportMisra23Package::declarationOfAnObjectIndirectionsLevelQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-11-6-3/NonUniqueEnumerationConstant.ql b/cpp/misra/src/rules/RULE-11-6-3/NonUniqueEnumerationConstant.ql new file mode 100644 index 0000000000..faa0880a75 --- /dev/null +++ b/cpp/misra/src/rules/RULE-11-6-3/NonUniqueEnumerationConstant.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/non-unique-enumeration-constant + * @name RULE-11-6-3: Within an enumerator list, the value of an implicitly-specified enumeration constant shall be unique + * @description Within an enumerator list, the value of an implicitly-specified enumeration constant + * shall be unique. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-11-6-3 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.nonuniqueenumerationconstant.NonUniqueEnumerationConstant + +class NonUniqueEnumerationConstantQuery extends NonUniqueEnumerationConstantSharedQuery { + NonUniqueEnumerationConstantQuery() { + this = ImportMisra23Package::nonUniqueEnumerationConstantQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-12-2-2/BitFieldShallHaveAnAppropriateType.ql b/cpp/misra/src/rules/RULE-12-2-2/BitFieldShallHaveAnAppropriateType.ql new file mode 100644 index 0000000000..f5041252f9 --- /dev/null +++ b/cpp/misra/src/rules/RULE-12-2-2/BitFieldShallHaveAnAppropriateType.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/bit-field-shall-have-an-appropriate-type + * @name RULE-12-2-2: A bit-field shall have an appropriate type + * @description A bit-field shall have an appropriate type. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-12-2-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.bitfieldshallhaveanappropriatetype.BitFieldShallHaveAnAppropriateType + +class BitFieldShallHaveAnAppropriateTypeQuery extends BitFieldShallHaveAnAppropriateTypeSharedQuery { + BitFieldShallHaveAnAppropriateTypeQuery() { + this = ImportMisra23Package::bitFieldShallHaveAnAppropriateTypeQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-12-2-3/SignedIntegerNamedBitFieldHaveALengthOfOneBit.ql b/cpp/misra/src/rules/RULE-12-2-3/SignedIntegerNamedBitFieldHaveALengthOfOneBit.ql new file mode 100644 index 0000000000..df547bbec8 --- /dev/null +++ b/cpp/misra/src/rules/RULE-12-2-3/SignedIntegerNamedBitFieldHaveALengthOfOneBit.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/signed-integer-named-bit-field-have-a-length-of-one-bit + * @name RULE-12-2-3: A named bit-field with signed integer type shall not have a length of one bit + * @description A named bit-field with signed integer type shall not have a length of one bit. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-12-2-3 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.namedbitfieldswithsignedintegertype.NamedBitFieldsWithSignedIntegerType + +class SignedIntegerNamedBitFieldHaveALengthOfOneBitQuery extends NamedBitFieldsWithSignedIntegerTypeSharedQuery +{ + SignedIntegerNamedBitFieldHaveALengthOfOneBitQuery() { + this = ImportMisra23Package::signedIntegerNamedBitFieldHaveALengthOfOneBitQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-13-1-2/VirtualAndNonVirtualClassInTheHierarchy.ql b/cpp/misra/src/rules/RULE-13-1-2/VirtualAndNonVirtualClassInTheHierarchy.ql new file mode 100644 index 0000000000..75030afbfb --- /dev/null +++ b/cpp/misra/src/rules/RULE-13-1-2/VirtualAndNonVirtualClassInTheHierarchy.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/virtual-and-non-virtual-class-in-the-hierarchy + * @name RULE-13-1-2: An accessible base class shall not be both virtual and non-virtual in the same hierarchy + * @description An accessible base class shall not be both virtual and non-virtual in the same + * hierarchy. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-13-1-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.virtualandnonvirtualclassinthehierarchy.VirtualAndNonVirtualClassInTheHierarchy + +class VirtualAndNonVirtualClassInTheHierarchyQuery extends VirtualAndNonVirtualClassInTheHierarchySharedQuery +{ + VirtualAndNonVirtualClassInTheHierarchyQuery() { + this = ImportMisra23Package::virtualAndNonVirtualClassInTheHierarchyQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-13-3-2/OverridingShallSpecifyDifferentDefaultArguments.ql b/cpp/misra/src/rules/RULE-13-3-2/OverridingShallSpecifyDifferentDefaultArguments.ql new file mode 100644 index 0000000000..519589984e --- /dev/null +++ b/cpp/misra/src/rules/RULE-13-3-2/OverridingShallSpecifyDifferentDefaultArguments.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/overriding-shall-specify-different-default-arguments + * @name RULE-13-3-2: Parameters in an overriding virtual function shall not specify different default arguments + * @description Parameters in an overriding virtual function shall not specify different default + * arguments. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-13-3-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.overridingshallspecifydifferentdefaultarguments.OverridingShallSpecifyDifferentDefaultArguments + +class OverridingShallSpecifyDifferentDefaultArgumentsQuery extends OverridingShallSpecifyDifferentDefaultArgumentsSharedQuery +{ + OverridingShallSpecifyDifferentDefaultArgumentsQuery() { + this = ImportMisra23Package::overridingShallSpecifyDifferentDefaultArgumentsQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-13-3-4/PotentiallyVirtualPointerOnlyComparesToNullptr.ql b/cpp/misra/src/rules/RULE-13-3-4/PotentiallyVirtualPointerOnlyComparesToNullptr.ql new file mode 100644 index 0000000000..1c528396e0 --- /dev/null +++ b/cpp/misra/src/rules/RULE-13-3-4/PotentiallyVirtualPointerOnlyComparesToNullptr.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/potentially-virtual-pointer-only-compares-to-nullptr + * @name RULE-13-3-4: A comparison of a potentially virtual pointer to member function shall only be with nullptr + * @description A comparison of a potentially virtual pointer to member function shall only be with + * nullptr. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-13-3-4 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.potentiallyvirtualpointeronlycomparestonullptr.PotentiallyVirtualPointerOnlyComparesToNullptr + +class PotentiallyVirtualPointerOnlyComparesToNullptrQuery extends PotentiallyVirtualPointerOnlyComparesToNullptrSharedQuery +{ + PotentiallyVirtualPointerOnlyComparesToNullptrQuery() { + this = ImportMisra23Package::potentiallyVirtualPointerOnlyComparesToNullptrQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-15-1-1/ObjectsDynamicTypeUsedFromConstructorOrDestructor.ql b/cpp/misra/src/rules/RULE-15-1-1/ObjectsDynamicTypeUsedFromConstructorOrDestructor.ql new file mode 100644 index 0000000000..f23c1afab8 --- /dev/null +++ b/cpp/misra/src/rules/RULE-15-1-1/ObjectsDynamicTypeUsedFromConstructorOrDestructor.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/objects-dynamic-type-used-from-constructor-or-destructor + * @name RULE-15-1-1: An object’s dynamic type shall not be used from within its constructor or destructor + * @description An object’s dynamic type shall not be used from within its constructor or + * destructor. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-15-1-1 + * scope/system + * external/misra/enforcement/undecidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.objectsdynamictypeusedfromconstructorordestructor.ObjectsDynamicTypeUsedFromConstructorOrDestructor + +class ObjectsDynamicTypeUsedFromConstructorOrDestructorQuery extends ObjectsDynamicTypeUsedFromConstructorOrDestructorSharedQuery +{ + ObjectsDynamicTypeUsedFromConstructorOrDestructorQuery() { + this = ImportMisra23Package::objectsDynamicTypeUsedFromConstructorOrDestructorQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-15-1-2/InitializeAllVirtualBaseClasses.ql b/cpp/misra/src/rules/RULE-15-1-2/InitializeAllVirtualBaseClasses.ql new file mode 100644 index 0000000000..3dd7b7e3e2 --- /dev/null +++ b/cpp/misra/src/rules/RULE-15-1-2/InitializeAllVirtualBaseClasses.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/initialize-all-virtual-base-classes + * @name RULE-15-1-2: All constructors of a class should explicitly initialize all of its virtual base classes and + * @description All constructors of a class should explicitly initialize all of its virtual base + * classes and immediate base classes. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-15-1-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.initializeallvirtualbaseclasses.InitializeAllVirtualBaseClasses + +class InitializeAllVirtualBaseClassesQuery extends InitializeAllVirtualBaseClassesSharedQuery { + InitializeAllVirtualBaseClassesQuery() { + this = ImportMisra23Package::initializeAllVirtualBaseClassesQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-15-1-5/InitializerListConstructorIsTheOnlyConstructor.ql b/cpp/misra/src/rules/RULE-15-1-5/InitializerListConstructorIsTheOnlyConstructor.ql new file mode 100644 index 0000000000..c7cf1856cd --- /dev/null +++ b/cpp/misra/src/rules/RULE-15-1-5/InitializerListConstructorIsTheOnlyConstructor.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/initializer-list-constructor-is-the-only-constructor + * @name RULE-15-1-5: A class shall only define an initializer-list constructor when it is the only constructor + * @description A class shall only define an initializer-list constructor when it is the only + * constructor. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-15-1-5 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.initializerlistconstructoristheonlyconstructor.InitializerListConstructorIsTheOnlyConstructor + +class InitializerListConstructorIsTheOnlyConstructorQuery extends InitializerListConstructorIsTheOnlyConstructorSharedQuery +{ + InitializerListConstructorIsTheOnlyConstructorQuery() { + this = ImportMisra23Package::initializerListConstructorIsTheOnlyConstructorQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-16-5-2/AddressOfOperatorOverloaded.ql b/cpp/misra/src/rules/RULE-16-5-2/AddressOfOperatorOverloaded.ql new file mode 100644 index 0000000000..937ec4e9e3 --- /dev/null +++ b/cpp/misra/src/rules/RULE-16-5-2/AddressOfOperatorOverloaded.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/address-of-operator-overloaded + * @name RULE-16-5-2: The address-of operator shall not be overloaded + * @description The address-of operator shall not be overloaded. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-16-5-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.addressofoperatoroverloaded.AddressOfOperatorOverloaded + +class AddressOfOperatorOverloadedQuery extends AddressOfOperatorOverloadedSharedQuery { + AddressOfOperatorOverloadedQuery() { + this = ImportMisra23Package::addressOfOperatorOverloadedQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-17-8-1/FunctionTemplatesExplicitlySpecialized.ql b/cpp/misra/src/rules/RULE-17-8-1/FunctionTemplatesExplicitlySpecialized.ql new file mode 100644 index 0000000000..c7b306946b --- /dev/null +++ b/cpp/misra/src/rules/RULE-17-8-1/FunctionTemplatesExplicitlySpecialized.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/function-templates-explicitly-specialized + * @name RULE-17-8-1: Function templates shall not be explicitly specialized + * @description Function templates shall not be explicitly specialized. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-17-8-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.functiontemplatesexplicitlyspecialized.FunctionTemplatesExplicitlySpecialized + +class FunctionTemplatesExplicitlySpecializedQuery extends FunctionTemplatesExplicitlySpecializedSharedQuery +{ + FunctionTemplatesExplicitlySpecializedQuery() { + this = ImportMisra23Package::functionTemplatesExplicitlySpecializedQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-18-1-1/ExceptionObjectHavePointerType.ql b/cpp/misra/src/rules/RULE-18-1-1/ExceptionObjectHavePointerType.ql new file mode 100644 index 0000000000..cbae5c1da4 --- /dev/null +++ b/cpp/misra/src/rules/RULE-18-1-1/ExceptionObjectHavePointerType.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/exception-object-have-pointer-type + * @name RULE-18-1-1: An exception object shall not have pointer type + * @description An exception object shall not have pointer type. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-18-1-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.exceptionobjecthavepointertype.ExceptionObjectHavePointerType + +class ExceptionObjectHavePointerTypeQuery extends ExceptionObjectHavePointerTypeSharedQuery { + ExceptionObjectHavePointerTypeQuery() { + this = ImportMisra23Package::exceptionObjectHavePointerTypeQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-18-1-2/EmptyThrowOnlyWithinACatchHandler.ql b/cpp/misra/src/rules/RULE-18-1-2/EmptyThrowOnlyWithinACatchHandler.ql new file mode 100644 index 0000000000..15ca773943 --- /dev/null +++ b/cpp/misra/src/rules/RULE-18-1-2/EmptyThrowOnlyWithinACatchHandler.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/empty-throw-only-within-a-catch-handler + * @name RULE-18-1-2: An empty throw shall only occur within the compound-statement of a catch handler + * @description An empty throw shall only occur within the compound-statement of a catch handler. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-18-1-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.emptythrowonlywithinacatchhandler.EmptyThrowOnlyWithinACatchHandler + +class EmptyThrowOnlyWithinACatchHandlerQuery extends EmptyThrowOnlyWithinACatchHandlerSharedQuery { + EmptyThrowOnlyWithinACatchHandlerQuery() { + this = ImportMisra23Package::emptyThrowOnlyWithinACatchHandlerQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-18-3-3/HandlersReferToNonStaticMembersFromTheirClass.ql b/cpp/misra/src/rules/RULE-18-3-3/HandlersReferToNonStaticMembersFromTheirClass.ql new file mode 100644 index 0000000000..b5db9095b1 --- /dev/null +++ b/cpp/misra/src/rules/RULE-18-3-3/HandlersReferToNonStaticMembersFromTheirClass.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/handlers-refer-to-non-static-members-from-their-class + * @name RULE-18-3-3: Handlers for a function-try-block of a constructor or destructor shall not refer to non-static + * @description Handlers for a function-try-block of a constructor or destructor shall not refer to + * non-static members from their class or its bases. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-18-3-3 + * correctness + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.destroyedvaluereferencedindestructorcatchblock.DestroyedValueReferencedInDestructorCatchBlock + +class HandlersReferToNonStaticMembersFromTheirClassQuery extends DestroyedValueReferencedInDestructorCatchBlockSharedQuery +{ + HandlersReferToNonStaticMembersFromTheirClassQuery() { + this = ImportMisra23Package::handlersReferToNonStaticMembersFromTheirClassQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-18-5-1/NoexceptFunctionShouldNotPropagateToTheCaller.ql b/cpp/misra/src/rules/RULE-18-5-1/NoexceptFunctionShouldNotPropagateToTheCaller.ql new file mode 100644 index 0000000000..61d8a0ebd4 --- /dev/null +++ b/cpp/misra/src/rules/RULE-18-5-1/NoexceptFunctionShouldNotPropagateToTheCaller.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/noexcept-function-should-not-propagate-to-the-caller + * @name RULE-18-5-1: A noexcept function should not attempt to propagate an exception to the calling function + * @description A noexcept function should not attempt to propagate an exception to the calling + * function. + * @kind path-problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-18-5-1 + * scope/system + * external/misra/enforcement/undecidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.noexceptfunctionshouldnotpropagatetothecaller.NoexceptFunctionShouldNotPropagateToTheCaller + +class NoexceptFunctionShouldNotPropagateToTheCallerQuery extends NoexceptFunctionShouldNotPropagateToTheCallerSharedQuery +{ + NoexceptFunctionShouldNotPropagateToTheCallerQuery() { + this = ImportMisra23Package::noexceptFunctionShouldNotPropagateToTheCallerQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql b/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql new file mode 100644 index 0000000000..7d507bc4d1 --- /dev/null +++ b/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql @@ -0,0 +1,45 @@ +/** + * @id cpp/misra/avoid-program-terminating-functions + * @name RULE-18-5-2: Program-terminating functions should not be used + * @description Using program-terminating functions like abort, exit, _Exit, quick_exit or terminate + * causes the stack to not be unwound and object destructors to not be called, + * potentially leaving the environment in an undesirable state. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-18-5-2 + * scope/single-translation-unit + * maintainability + * correctness + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.AlertReporting +import codingstandards.cpp.BannedFunctions + +class TerminatingFunction extends Function { + TerminatingFunction() { + this.hasQualifiedName(["", "std"], ["abort", "exit", "_Exit", "quick_exit"]) + or + // std::terminate does not occur in the global namespace. + this.hasQualifiedName("std", "terminate") + } +} + +predicate isInAssertMacroInvocation(BannedFunctions::UseExpr use) { + exists(MacroInvocation mi | + mi.getMacroName() = "assert" and + mi.getAnExpandedElement() = use + ) +} + +from BannedFunctions::UseExpr use +where + not isExcluded(use, BannedAPIsPackage::avoidProgramTerminatingFunctionsQuery()) and + // Exclude the uses in the assert macro + not isInAssertMacroInvocation(use) +select use.getPrimaryElement(), + use.getAction() + " program-terminating function '" + use.getFunctionName() + "'." diff --git a/cpp/misra/src/rules/RULE-19-0-2/FunctionLikeMacrosDefined.ql b/cpp/misra/src/rules/RULE-19-0-2/FunctionLikeMacrosDefined.ql new file mode 100644 index 0000000000..d9e4d5a810 --- /dev/null +++ b/cpp/misra/src/rules/RULE-19-0-2/FunctionLikeMacrosDefined.ql @@ -0,0 +1,20 @@ +/** + * @id cpp/misra/function-like-macros-defined + * @name RULE-19-0-2: Function-like macros shall not be defined + * @description Function-like macros shall not be defined. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-19-0-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.functionlikemacrosdefined.FunctionLikeMacrosDefined + +class FunctionLikeMacrosDefinedQuery extends FunctionLikeMacrosDefinedSharedQuery { + FunctionLikeMacrosDefinedQuery() { this = ImportMisra23Package::functionLikeMacrosDefinedQuery() } +} diff --git a/cpp/misra/src/rules/RULE-19-0-3/IncludeDirectivesPrecededByPreprocessorDirectives.ql b/cpp/misra/src/rules/RULE-19-0-3/IncludeDirectivesPrecededByPreprocessorDirectives.ql new file mode 100644 index 0000000000..7068c7bea0 --- /dev/null +++ b/cpp/misra/src/rules/RULE-19-0-3/IncludeDirectivesPrecededByPreprocessorDirectives.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/include-directives-preceded-by-preprocessor-directives + * @name RULE-19-0-3: #include directives should only be preceded by preprocessor directives or comments + * @description Using anything other than other pre-processor directives or comments before an + * '#include' directive makes the code more difficult to read. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-19-0-3 + * readability + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.preprocessorincludespreceded.PreprocessorIncludesPreceded + +class IncludeDirectivesPrecededByPreprocessorDirectivesQuery extends PreprocessorIncludesPrecededSharedQuery +{ + IncludeDirectivesPrecededByPreprocessorDirectivesQuery() { + this = ImportMisra23Package::includeDirectivesPrecededByPreprocessorDirectivesQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-19-1-3/IdentifiersUsedInTheControllingExpressionOf.ql b/cpp/misra/src/rules/RULE-19-1-3/IdentifiersUsedInTheControllingExpressionOf.ql new file mode 100644 index 0000000000..c30be08109 --- /dev/null +++ b/cpp/misra/src/rules/RULE-19-1-3/IdentifiersUsedInTheControllingExpressionOf.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/identifiers-used-in-the-controlling-expression-of + * @name RULE-19-1-3: All identifiers used in the controlling expression of #if or #elif preprocessing directives shall be + * @description All identifiers used in the controlling expression of #if or #elif preprocessing + * directives shall be defined prior to evaluation. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-19-1-3 + * correctness + * readability + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.undefinedmacroidentifiers.UndefinedMacroIdentifiers + +class IdentifiersUsedInTheControllingExpressionOfQuery extends UndefinedMacroIdentifiersSharedQuery { + IdentifiersUsedInTheControllingExpressionOfQuery() { + this = ImportMisra23Package::identifiersUsedInTheControllingExpressionOfQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-19-2-3/CharsThatShouldNotOccurInHeaderFileName.ql b/cpp/misra/src/rules/RULE-19-2-3/CharsThatShouldNotOccurInHeaderFileName.ql new file mode 100644 index 0000000000..30c6c50662 --- /dev/null +++ b/cpp/misra/src/rules/RULE-19-2-3/CharsThatShouldNotOccurInHeaderFileName.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/chars-that-should-not-occur-in-header-file-name + * @name RULE-19-2-3: The ' or " or \ characters and the /* or // character sequences shall not occur in a header file + * @description The ' or " or \ characters and the /* or // character sequences shall not occur in a + * header file name. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-19-2-3 + * scope/single-translation-unit + * correctness + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.preprocessorincludesforbiddenheadernames.PreprocessorIncludesForbiddenHeaderNames + +class CharsThatShouldNotOccurInHeaderFileNameQuery extends PreprocessorIncludesForbiddenHeaderNamesSharedQuery +{ + CharsThatShouldNotOccurInHeaderFileNameQuery() { + this = ImportMisra23Package::charsThatShouldNotOccurInHeaderFileNameQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-19-3-1/AndPreprocessorOperatorsShouldNotBeUsed.ql b/cpp/misra/src/rules/RULE-19-3-1/AndPreprocessorOperatorsShouldNotBeUsed.ql new file mode 100644 index 0000000000..bc423a0051 --- /dev/null +++ b/cpp/misra/src/rules/RULE-19-3-1/AndPreprocessorOperatorsShouldNotBeUsed.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/and-preprocessor-operators-should-not-be-used + * @name RULE-19-3-1: The # and ## preprocessor operators should not be used + * @description The order of evaluation for the '#' and '##' operators may differ between compilers, + * which can cause unexpected behaviour. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-19-3-1 + * correctness + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.hashoperatorsused.HashOperatorsUsed + +class AndPreprocessorOperatorsShouldNotBeUsedQuery extends HashOperatorsUsedSharedQuery { + AndPreprocessorOperatorsShouldNotBeUsedQuery() { + this = ImportMisra23Package::andPreprocessorOperatorsShouldNotBeUsedQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-19-3-2/MacroParameterFollowingHash.ql b/cpp/misra/src/rules/RULE-19-3-2/MacroParameterFollowingHash.ql new file mode 100644 index 0000000000..12e95ced04 --- /dev/null +++ b/cpp/misra/src/rules/RULE-19-3-2/MacroParameterFollowingHash.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/macro-parameter-following-hash + * @name RULE-19-3-2: A macro parameter immediately following a # operator shall not be immediately followed by a ## + * @description A macro parameter immediately following a # operator shall not be immediately + * followed by a ## operator. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-19-3-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.macroparameterfollowinghash.MacroParameterFollowingHash + +class MacroParameterFollowingHashQuery extends MacroParameterFollowingHashSharedQuery { + MacroParameterFollowingHashQuery() { + this = ImportMisra23Package::macroParameterFollowingHashQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-19-3-3/AMixedUseMacroArgumentSubjectToExpansion.ql b/cpp/misra/src/rules/RULE-19-3-3/AMixedUseMacroArgumentSubjectToExpansion.ql new file mode 100644 index 0000000000..9cb0a7e9c5 --- /dev/null +++ b/cpp/misra/src/rules/RULE-19-3-3/AMixedUseMacroArgumentSubjectToExpansion.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/a-mixed-use-macro-argument-subject-to-expansion + * @name RULE-19-3-3: The argument to a mixed-use macro parameter shall not be subject to further expansion + * @description The argument to a mixed-use macro parameter shall not be subject to further + * expansion. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-19-3-3 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.amixedusemacroargumentsubjecttoexpansion.AMixedUseMacroArgumentSubjectToExpansion + +class AMixedUseMacroArgumentSubjectToExpansionQuery extends AMixedUseMacroArgumentSubjectToExpansionSharedQuery +{ + AMixedUseMacroArgumentSubjectToExpansionQuery() { + this = ImportMisra23Package::aMixedUseMacroArgumentSubjectToExpansionQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-19-3-5/TokensThatLookLikeDirectivesInAMacroArgument.ql b/cpp/misra/src/rules/RULE-19-3-5/TokensThatLookLikeDirectivesInAMacroArgument.ql new file mode 100644 index 0000000000..2fa672e644 --- /dev/null +++ b/cpp/misra/src/rules/RULE-19-3-5/TokensThatLookLikeDirectivesInAMacroArgument.ql @@ -0,0 +1,26 @@ +/** + * @id cpp/misra/tokens-that-look-like-directives-in-a-macro-argument + * @name RULE-19-3-5: Tokens that look like a preprocessing directive shall not occur within a macro argument + * @description Arguments to a function-like macro shall not contain tokens that look like + * pre-processing directives or else behaviour after macro expansion is unpredictable. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-19-3-5 + * readability + * correctness + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.preprocessingdirectivewithinmacroargument.PreprocessingDirectiveWithinMacroArgument + +class TokensThatLookLikeDirectivesInAMacroArgumentQuery extends PreprocessingDirectiveWithinMacroArgumentSharedQuery +{ + TokensThatLookLikeDirectivesInAMacroArgumentQuery() { + this = ImportMisra23Package::tokensThatLookLikeDirectivesInAMacroArgumentQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql b/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql new file mode 100644 index 0000000000..37dfa2422b --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql @@ -0,0 +1,65 @@ +/** + * @id cpp/misra/no-variadic-function-macros + * @name RULE-21-10-1: The features of shall not be used + * @description Using features like va_list, va_arg, va_start, va_end and va_copy bypasses + * compiler type checking and leads to undefined behavior when used incorrectly. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-10-1 + * scope/single-translation-unit + * correctness + * maintainability + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.types.Uses + +class VaListType extends Type { + VaListType() { + this.getName() = "va_list" or + this.(SpecifiedType).getBaseType() instanceof VaListType or + this.(TypedefType).getBaseType() instanceof VaListType + } +} + +from Element element, string message +where + not isExcluded(element, BannedAPIsPackage::noVariadicFunctionMacrosQuery()) and + ( + element = getATypeUse(any(VaListType vlt)) and + ( + if element instanceof Parameter + then + message = + "Declaration of parameter '" + element.(Parameter).getName() + "' of type 'va_list'." + else + if element instanceof Variable + then + message = + "Declaration of variable '" + element.(Variable).getName() + "' of type 'va_list'." + else + if element instanceof TypedefType + then + message = + "Declaration of typedef '" + element.(TypedefType).getName() + + "' aliasing 'va_list' type." + else message = "Use of 'va_list' type in an unsupported context." + ) + or + element instanceof BuiltInVarArgsStart and + message = "Call to 'va_start'." + or + element instanceof BuiltInVarArgsEnd and + message = "Call to 'va_end'." + or + element instanceof BuiltInVarArg and + message = "Call to 'va_arg'." + or + element instanceof BuiltInVarArgCopy and + message = "Call to 'va_copy'." + ) +select element, message diff --git a/cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql b/cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql new file mode 100644 index 0000000000..85607a5c8b --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql @@ -0,0 +1,62 @@ +/** + * @id cpp/misra/no-csetjmp-header + * @name RULE-21-10-2: The standard header file shall not be used + * @description Using facilities from the header causes undefined behavior by bypassing + * normal function return mechanisms and may result in non-trivial object destruction + * being omitted. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-10-2 + * scope/single-translation-unit + * correctness + * maintainability + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.BannedFunctions +import codingstandards.cpp.types.Uses + +class CSetJmpHeader extends Include { + CSetJmpHeader() { this.getIncludeText().regexpMatch("[<\\\"](csetjmp|setjmp.h)[>\\\"]") } +} + +class JmpBufType extends UserType { + JmpBufType() { this.hasGlobalOrStdName("jmp_buf") } +} + +class LongjmpFunction extends Function { + LongjmpFunction() { this.hasGlobalOrStdName("longjmp") } +} + +class SetjmpMacroInvocation extends MacroInvocation { + SetjmpMacroInvocation() { this.getMacroName() = "setjmp" } +} + +from Element element, string message +where + not isExcluded(element, BannedAPIsPackage::noCsetjmpHeaderQuery()) and + ( + message = "Use of banned header " + element.(CSetJmpHeader).getIncludeText() + "." + or + ( + element = getATypeUse(any(JmpBufType jbt)) and + if element instanceof Variable + then + message = + "Declaration of variable '" + element.(Variable).getName() + + "' with banned type 'jmp_buf'." + else message = "Use of banned type 'jmp_buf'." + ) + or + message = + element.(BannedFunctions::Use).getAction() + " banned function '" + + element.(BannedFunctions::Use).getFunctionName() + "'." + or + element instanceof SetjmpMacroInvocation and + message = "Use of banned macro 'setjmp'." + ) +select element, message diff --git a/cpp/misra/src/rules/RULE-21-10-3/CsignalFacilitiesUsed.ql b/cpp/misra/src/rules/RULE-21-10-3/CsignalFacilitiesUsed.ql new file mode 100644 index 0000000000..3e8c58a8da --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-10-3/CsignalFacilitiesUsed.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/csignal-facilities-used + * @name RULE-21-10-3: The facilities provided by the standard header file shall not be used + * @description Signal handling contains implementation-defined and undefined behaviour. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-21-10-3 + * maintainability + * correctness + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.csignalfunctionsused.CsignalFunctionsUsed + +class CsignalFacilitiesUsedQuery extends CsignalFunctionsUsedSharedQuery { + CsignalFacilitiesUsedQuery() { this = ImportMisra23Package::csignalFacilitiesUsedQuery() } +} diff --git a/cpp/misra/src/rules/RULE-21-10-3/CsignalTypesShallNotBeUsed.ql b/cpp/misra/src/rules/RULE-21-10-3/CsignalTypesShallNotBeUsed.ql new file mode 100644 index 0000000000..0fe1b1dfba --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-10-3/CsignalTypesShallNotBeUsed.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/csignal-types-shall-not-be-used + * @name RULE-21-10-3: The signal-handling types of shall not be used + * @description The types provided by the standard header file shall not be used. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-21-10-3 + * maintainability + * correctness + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.csignaltypesused.CsignalTypesUsed + +class CsignalTypesShallNotBeUsedQuery extends CsignalTypesUsedSharedQuery { + CsignalTypesShallNotBeUsedQuery() { + this = ImportMisra23Package::csignalTypesShallNotBeUsedQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-21-2-1/AtofAtoiAtolAndAtollUsed.ql b/cpp/misra/src/rules/RULE-21-2-1/AtofAtoiAtolAndAtollUsed.ql new file mode 100644 index 0000000000..e5b48d55a7 --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-2-1/AtofAtoiAtolAndAtollUsed.ql @@ -0,0 +1,20 @@ +/** + * @id cpp/misra/atof-atoi-atol-and-atoll-used + * @name RULE-21-2-1: The library functions atof, atoi, atol and atoll from shall not be used + * @description The library functions atof, atoi, atol and atoll from shall not be used. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-2-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.atofatoiatolandatollused.AtofAtoiAtolAndAtollUsed + +class AtofAtoiAtolAndAtollUsedQuery extends AtofAtoiAtolAndAtollUsedSharedQuery { + AtofAtoiAtolAndAtollUsedQuery() { this = ImportMisra23Package::atofAtoiAtolAndAtollUsedQuery() } +} diff --git a/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql b/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql new file mode 100644 index 0000000000..c654ac4771 --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql @@ -0,0 +1,35 @@ +/** + * @id cpp/misra/unsafe-string-handling-functions + * @name RULE-21-2-2: The string handling functions from , , and shall not be used + * @description Using string handling functions from , , and + * headers may result in buffer overflows or unreliable error detection through errno. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-2-2 + * scope/single-translation-unit + * correctness + * maintainability + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.BannedFunctions + +class StringFunction extends Function { + StringFunction() { + this.hasGlobalName([ + "strcat", "strchr", "strcmp", "strcoll", "strcpy", "strcspn", "strerror", "strlen", + "strncat", "strncmp", "strncpy", "strpbrk", "strrchr", "strspn", "strstr", "strtok", + "strxfrm", "strtol", "strtoll", "strtoul", "strtoull", "strtod", "strtof", "strtold", + "fgetwc", "fputwc", "wcstol", "wcstoll", "wcstoul", "wcstoull", "wcstod", "wcstof", + "wcstold", "strtoumax", "strtoimax", "wcstoumax", "wcstoimax" + ]) + } +} + +from BannedFunctions::Use use +where not isExcluded(use, BannedAPIsPackage::unsafeStringHandlingFunctionsQuery()) +select use, use.getAction() + " banned string handling function '" + use.getFunctionName() + "'." diff --git a/cpp/misra/src/rules/RULE-21-2-3/BannedSystemFunction.ql b/cpp/misra/src/rules/RULE-21-2-3/BannedSystemFunction.ql new file mode 100644 index 0000000000..95900e605b --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-2-3/BannedSystemFunction.ql @@ -0,0 +1,39 @@ +/** + * @id cpp/misra/banned-system-function + * @name RULE-21-2-3: The library function system from shall not be used + * @description Using the system() function from cstdlib or stdlib.h causes undefined behavior and + * potential security vulnerabilities. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-2-3 + * scope/single-translation-unit + * correctness + * maintainability + * security + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.BannedFunctions + +class SystemFunction extends Function { + SystemFunction() { this.hasGlobalName("system") or this.hasQualifiedName("std", "system") } +} + +from Element element, string message +where + not isExcluded(element, BannedAPIsPackage::bannedSystemFunctionQuery()) and + ( + element instanceof BannedFunctions::Use and + message = + element.(BannedFunctions::Use).getAction() + " banned function '" + + element.(BannedFunctions::Use).getFunctionName() + "'." + or + element instanceof MacroInvocation and + element.(MacroInvocation).getMacroName() = "system" and + message = "Use of banned macro 'system'." + ) +select element, message diff --git a/cpp/misra/src/rules/RULE-21-2-4/MacroOffsetofShallNotBeUsed.ql b/cpp/misra/src/rules/RULE-21-2-4/MacroOffsetofShallNotBeUsed.ql new file mode 100644 index 0000000000..fa6df051ca --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-2-4/MacroOffsetofShallNotBeUsed.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/macro-offsetof-shall-not-be-used + * @name RULE-21-2-4: The macro offsetof shall not be used + * @description The macro offsetof shall not be used. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-2-4 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.macrooffsetofused.MacroOffsetofUsed + +class MacroOffsetofShallNotBeUsedQuery extends MacroOffsetofUsedSharedQuery { + MacroOffsetofShallNotBeUsedQuery() { + this = ImportMisra23Package::macroOffsetofShallNotBeUsedQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-21-6-4/GlobalSizedOperatorDeleteShallBeDefined.ql b/cpp/misra/src/rules/RULE-21-6-4/GlobalSizedOperatorDeleteShallBeDefined.ql new file mode 100644 index 0000000000..eb9be3af15 --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-6-4/GlobalSizedOperatorDeleteShallBeDefined.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/global-sized-operator-delete-shall-be-defined + * @name RULE-21-6-4: Sized 'operator delete' must be defined globally if unsized 'operator delete' is defined globally + * @description If a project defines the unsized version of a global operator delete, then the sized + * version shall be defined. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-6-4 + * maintainability + * scope/system + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.globalsizedoperatordeletenotdefined.GlobalSizedOperatorDeleteNotDefined + +class GlobalSizedOperatorDeleteShallBeDefinedQuery extends GlobalSizedOperatorDeleteNotDefinedSharedQuery +{ + GlobalSizedOperatorDeleteShallBeDefinedQuery() { + this = ImportMisra23Package::globalSizedOperatorDeleteShallBeDefinedQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-21-6-4/GlobalUnsizedOperatorDeleteShallBeDefined.ql b/cpp/misra/src/rules/RULE-21-6-4/GlobalUnsizedOperatorDeleteShallBeDefined.ql new file mode 100644 index 0000000000..8a80b36e3f --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-6-4/GlobalUnsizedOperatorDeleteShallBeDefined.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/global-unsized-operator-delete-shall-be-defined + * @name RULE-21-6-4: Unsized 'operator delete' must be defined globally if sized 'operator delete' is defined globally + * @description If a project defines the sized version of a global operator delete, then the unsized + * version shall be defined. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-6-4 + * maintainability + * scope/system + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.globalunsizedoperatordeletenotdefined.GlobalUnsizedOperatorDeleteNotDefined + +class GlobalUnsizedOperatorDeleteShallBeDefinedQuery extends GlobalUnsizedOperatorDeleteNotDefinedSharedQuery +{ + GlobalUnsizedOperatorDeleteShallBeDefinedQuery() { + this = ImportMisra23Package::globalUnsizedOperatorDeleteShallBeDefinedQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-21-6-5/PointerToAnIncompleteClassTypeDeleted.ql b/cpp/misra/src/rules/RULE-21-6-5/PointerToAnIncompleteClassTypeDeleted.ql new file mode 100644 index 0000000000..29d20d5d07 --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-6-5/PointerToAnIncompleteClassTypeDeleted.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/pointer-to-an-incomplete-class-type-deleted + * @name RULE-21-6-5: A pointer to an incomplete class type shall not be deleted + * @description Do not delete pointers to incomplete classes to prevent undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-6-5 + * correctness + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.deleteofpointertoincompleteclass.DeleteOfPointerToIncompleteClass + +class PointerToAnIncompleteClassTypeDeletedQuery extends DeleteOfPointerToIncompleteClassSharedQuery +{ + PointerToAnIncompleteClassTypeDeletedQuery() { + this = ImportMisra23Package::pointerToAnIncompleteClassTypeDeletedQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql b/cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql new file mode 100644 index 0000000000..9f2cf6f038 --- /dev/null +++ b/cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql @@ -0,0 +1,33 @@ +/** + * @id cpp/misra/use-smart-ptr-factory-functions + * @name RULE-23-11-1: The raw pointer constructors of std::shared_ptr and std::unique_ptr should not be used + * @description Using raw pointer constructors of std::shared_ptr and std::unique_ptr instead of + * make_shared/make_unique can lead to memory leaks if exceptions occur during + * construction. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-23-11-1 + * scope/single-translation-unit + * correctness + * maintainability + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra + +from ConstructorCall call, Class smartPtrClass +where + not isExcluded(call, BannedAPIsPackage::useSmartPtrFactoryFunctionsQuery()) and + smartPtrClass = call.getTarget().getDeclaringType() and + ( + smartPtrClass.hasQualifiedName("std", "shared_ptr") or + smartPtrClass.hasQualifiedName("std", "unique_ptr") + ) and + // The rule only applies to constructors that take a raw pointer as the first argument + // This includes the (*p, deleter) and (*p, deleter, alloc) constructors + // and excludes e.g. the move or aliasing constructors. + call.getArgument(0).getType().getUnspecifiedType() instanceof PointerType +select call, "Use of raw pointer constructor for 'std::" + smartPtrClass.getSimpleName() + "'." diff --git a/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql b/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql new file mode 100644 index 0000000000..a50b535d1a --- /dev/null +++ b/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql @@ -0,0 +1,46 @@ +/** + * @id cpp/misra/character-handling-function-restrictions + * @name RULE-24-5-1: The character handling functions from and shall not be used + * @description Using character classification and case mapping functions from and + * causes undefined behavior when arguments are not representable as unsigned + * char or not equal to EOF. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-24-5-1 + * scope/single-translation-unit + * correctness + * maintainability + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.BannedFunctions + +class BannedCharacterHandlingFunction extends Function { + BannedCharacterHandlingFunction() { + this.hasGlobalOrStdName([ + "isalnum", "isalpha", "isblank", "iscntrl", "isdigit", "isgraph", "islower", "isprint", + "ispunct", "isspace", "isupper", "isxdigit", "tolower", "toupper", "iswalnum", "iswalpha", + "iswblank", "iswcntrl", "iswctype", "iswdigit", "iswgraph", "iswlower", "iswprint", + "iswpunct", "iswspace", "iswupper", "iswxdigit", "towctrans", "towlower", "towupper", + "wctrans", "wctype" + ]) and + // Exclude the functions which pass a reference to a std::locale as the second parameter + not this.getParameter(1) + .getType() + .getUnspecifiedType() + .(ReferenceType) + .getBaseType() + .(UserType) + .hasQualifiedName("std", "locale") + } +} + +from BannedFunctions::Use use +where not isExcluded(use, BannedAPIsPackage::characterHandlingFunctionRestrictionsQuery()) +select use, + use.getAction() + " banned character handling function '" + use.getFunctionName() + + "' from or ." diff --git a/cpp/misra/src/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.ql b/cpp/misra/src/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.ql new file mode 100644 index 0000000000..3352b99455 --- /dev/null +++ b/cpp/misra/src/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.ql @@ -0,0 +1,28 @@ +/** + * @id cpp/misra/no-memory-functions-from-c-string + * @name RULE-24-5-2: The C++ Standard Library functions memcpy, memmove and memcmp from shall not be used + * @description Using memcpy, memmove or memcmp from can result in undefined behavior due + * to overlapping memory, non-trivially copyable objects, or unequal comparison of + * logically equal objects. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-24-5-2 + * scope/single-translation-unit + * correctness + * maintainability + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.BannedFunctions + +class BannedMemoryFunction extends Function { + BannedMemoryFunction() { this.hasGlobalOrStdName(["memcpy", "memmove", "memcmp"]) } +} + +from BannedFunctions::Use use +where not isExcluded(use, BannedAPIsPackage::noMemoryFunctionsFromCStringQuery()) +select use, use.getAction() + " banned function '" + use.getFunctionName() + "' from ." diff --git a/cpp/misra/src/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.ql b/cpp/misra/src/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.ql new file mode 100644 index 0000000000..2040f998ca --- /dev/null +++ b/cpp/misra/src/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.ql @@ -0,0 +1,31 @@ +/** + * @id cpp/misra/locale-global-function-not-allowed + * @name RULE-25-5-1: The setlocale and std::locale::global functions shall not be called + * @description Calling setlocale or std::locale::global functions can introduce data races with + * functions that use the locale, leading to undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-25-5-1 + * scope/single-translation-unit + * correctness + * maintainability + * concurrency + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.BannedFunctions + +class BannedLocaleFunction extends Function { + BannedLocaleFunction() { + this.hasGlobalOrStdName("setlocale") or + this.hasQualifiedName("std", "locale", "global") + } +} + +from BannedFunctions::Use use +where not isExcluded(use, BannedAPIsPackage::localeGlobalFunctionNotAllowedQuery()) +select use, use.getAction() + " banned function '" + use.getFunctionName() + "' from ." diff --git a/cpp/misra/src/rules/RULE-25-5-2/PointersReturnedByLocaleFunctionsMustBeUsedAsConst.ql b/cpp/misra/src/rules/RULE-25-5-2/PointersReturnedByLocaleFunctionsMustBeUsedAsConst.ql new file mode 100644 index 0000000000..1feebdc67c --- /dev/null +++ b/cpp/misra/src/rules/RULE-25-5-2/PointersReturnedByLocaleFunctionsMustBeUsedAsConst.ql @@ -0,0 +1,26 @@ +/** + * @id cpp/misra/pointers-returned-by-locale-functions-must-be-used-as-const + * @name RULE-25-5-2: The pointers returned by environment functions should be treated as const + * @description The pointers returned by the C++ Standard Library functions localeconv, getenv, + * setlocale or strerror must only be used as if they have pointer to const-qualified + * type. + * @kind path-problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-25-5-2 + * correctness + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.constlikereturnvalue.ConstLikeReturnValue + +class PointersReturnedByLocaleFunctionsMustBeUsedAsConstQuery extends ConstLikeReturnValueSharedQuery +{ + PointersReturnedByLocaleFunctionsMustBeUsedAsConstQuery() { + this = ImportMisra23Package::pointersReturnedByLocaleFunctionsMustBeUsedAsConstQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-25-5-3/CallToSetlocaleInvalidatesOldPointersMisra.ql b/cpp/misra/src/rules/RULE-25-5-3/CallToSetlocaleInvalidatesOldPointersMisra.ql new file mode 100644 index 0000000000..a38ce60039 --- /dev/null +++ b/cpp/misra/src/rules/RULE-25-5-3/CallToSetlocaleInvalidatesOldPointersMisra.ql @@ -0,0 +1,26 @@ +/** + * @id cpp/misra/call-to-setlocale-invalidates-old-pointers-misra + * @name RULE-25-5-3: The pointer returned by the Standard Library env functions is invalid + * @description The pointer returned by the Standard Library functions asctime, ctime, gmtime, + * localtime, localeconv, getenv, setlocale or strerror may be invalid following a + * subsequent call to the same function. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-25-5-3 + * correctness + * scope/system + * external/misra/enforcement/undecidable + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.invalidatedenvstringpointers.InvalidatedEnvStringPointers + +class CallToSetlocaleInvalidatesOldPointersMisraQuery extends InvalidatedEnvStringPointersSharedQuery +{ + CallToSetlocaleInvalidatesOldPointersMisraQuery() { + this = ImportMisra23Package::callToSetlocaleInvalidatesOldPointersMisraQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-25-5-3/CallToSetlocaleInvalidatesOldPointersWarnMisra.ql b/cpp/misra/src/rules/RULE-25-5-3/CallToSetlocaleInvalidatesOldPointersWarnMisra.ql new file mode 100644 index 0000000000..d0b4179412 --- /dev/null +++ b/cpp/misra/src/rules/RULE-25-5-3/CallToSetlocaleInvalidatesOldPointersWarnMisra.ql @@ -0,0 +1,26 @@ +/** + * @id cpp/misra/call-to-setlocale-invalidates-old-pointers-warn-misra + * @name RULE-25-5-3: The pointer returned by the Standard Library env functions is invalid warning + * @description The pointer returned by the Standard Library functions asctime, ctime, gmtime, + * localtime, localeconv, getenv, setlocale or strerror may be invalid following a + * subsequent call to the same function. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-25-5-3 + * correctness + * scope/system + * external/misra/enforcement/undecidable + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.invalidatedenvstringpointerswarn.InvalidatedEnvStringPointersWarn + +class CallToSetlocaleInvalidatesOldPointersWarnMisraQuery extends InvalidatedEnvStringPointersWarnSharedQuery +{ + CallToSetlocaleInvalidatesOldPointersWarnMisraQuery() { + this = ImportMisra23Package::callToSetlocaleInvalidatesOldPointersWarnMisraQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-26-3-1/VectorShouldNotBeSpecializedWithBool.ql b/cpp/misra/src/rules/RULE-26-3-1/VectorShouldNotBeSpecializedWithBool.ql new file mode 100644 index 0000000000..90037b5f29 --- /dev/null +++ b/cpp/misra/src/rules/RULE-26-3-1/VectorShouldNotBeSpecializedWithBool.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/vector-should-not-be-specialized-with-bool + * @name RULE-26-3-1: std::vector should not be specialized with bool + * @description std::vector should not be specialized with bool. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-26-3-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.vectorshouldnotbespecializedwithbool.VectorShouldNotBeSpecializedWithBool + +class VectorShouldNotBeSpecializedWithBoolQuery extends VectorShouldNotBeSpecializedWithBoolSharedQuery +{ + VectorShouldNotBeSpecializedWithBoolQuery() { + this = ImportMisra23Package::vectorShouldNotBeSpecializedWithBoolQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-28-6-2/ForwardingReferencesAndForwardNotUsedTogether.ql b/cpp/misra/src/rules/RULE-28-6-2/ForwardingReferencesAndForwardNotUsedTogether.ql new file mode 100644 index 0000000000..dc407512cc --- /dev/null +++ b/cpp/misra/src/rules/RULE-28-6-2/ForwardingReferencesAndForwardNotUsedTogether.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/forwarding-references-and-forward-not-used-together + * @name RULE-28-6-2: Forwarding references and std::forward shall be used together + * @description Forwarding references and std::forward shall be used together. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-28-6-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.forwardingreferencesandforwardnotusedtogether.ForwardingReferencesAndForwardNotUsedTogether + +class ForwardingReferencesAndForwardNotUsedTogetherQuery extends ForwardingReferencesAndForwardNotUsedTogetherSharedQuery +{ + ForwardingReferencesAndForwardNotUsedTogetherQuery() { + this = ImportMisra23Package::forwardingReferencesAndForwardNotUsedTogetherQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-28-6-3/ObjectUsedWhileInPotentiallyMovedFromState.ql b/cpp/misra/src/rules/RULE-28-6-3/ObjectUsedWhileInPotentiallyMovedFromState.ql new file mode 100644 index 0000000000..db3bbbb700 --- /dev/null +++ b/cpp/misra/src/rules/RULE-28-6-3/ObjectUsedWhileInPotentiallyMovedFromState.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/object-used-while-in-potentially-moved-from-state + * @name RULE-28-6-3: An object shall not be used while in a potentially moved-from state + * @description Moved-from object shall not be read-accessed. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-28-6-3 + * correctness + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.movedfromobjectsunspecifiedstate.MovedFromObjectsUnspecifiedState + +class ObjectUsedWhileInPotentiallyMovedFromStateQuery extends MovedFromObjectsUnspecifiedStateSharedQuery +{ + ObjectUsedWhileInPotentiallyMovedFromStateQuery() { + this = ImportMisra23Package::objectUsedWhileInPotentiallyMovedFromStateQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-30-0-1/CstdioFunctionsShallNotBeUsed.ql b/cpp/misra/src/rules/RULE-30-0-1/CstdioFunctionsShallNotBeUsed.ql new file mode 100644 index 0000000000..58c8a500f4 --- /dev/null +++ b/cpp/misra/src/rules/RULE-30-0-1/CstdioFunctionsShallNotBeUsed.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/cstdio-functions-shall-not-be-used + * @name RULE-30-0-1: The stream input/output library functions shall not be used + * @description The C Library input/output functions shall not be used. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-30-0-1 + * maintainability + * correctness + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.cstdiofunctionsused.CstdioFunctionsUsed + +class CstdioFunctionsShallNotBeUsedQuery extends CstdioFunctionsUsedSharedQuery { + CstdioFunctionsShallNotBeUsedQuery() { + this = ImportMisra23Package::cstdioFunctionsShallNotBeUsedQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-30-0-1/CstdioMacrosShallNotBeUsed.ql b/cpp/misra/src/rules/RULE-30-0-1/CstdioMacrosShallNotBeUsed.ql new file mode 100644 index 0000000000..8f0b9438e3 --- /dev/null +++ b/cpp/misra/src/rules/RULE-30-0-1/CstdioMacrosShallNotBeUsed.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/cstdio-macros-shall-not-be-used + * @name RULE-30-0-1: The stream input/output library macros shall not be used + * @description The C Library input/output functions shall not be used. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-30-0-1 + * maintainability + * correctness + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.cstdiomacrosused.CstdioMacrosUsed + +class CstdioMacrosShallNotBeUsedQuery extends CstdioMacrosUsedSharedQuery { + CstdioMacrosShallNotBeUsedQuery() { + this = ImportMisra23Package::cstdioMacrosShallNotBeUsedQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-30-0-1/CstdioTypesShallNotBeUsed.ql b/cpp/misra/src/rules/RULE-30-0-1/CstdioTypesShallNotBeUsed.ql new file mode 100644 index 0000000000..6966c85068 --- /dev/null +++ b/cpp/misra/src/rules/RULE-30-0-1/CstdioTypesShallNotBeUsed.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/cstdio-types-shall-not-be-used + * @name RULE-30-0-1: The stream input/output library types shall not be used + * @description The C Library input/output functions shall not be used. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-30-0-1 + * maintainability + * correctness + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.cstdiotypesused.CstdioTypesUsed + +class CstdioTypesShallNotBeUsedQuery extends CstdioTypesUsedSharedQuery { + CstdioTypesShallNotBeUsedQuery() { this = ImportMisra23Package::cstdioTypesShallNotBeUsedQuery() } +} diff --git a/cpp/misra/src/rules/RULE-30-0-2/ReadsAndWritesOnStreamNotSeparatedByPositioning.ql b/cpp/misra/src/rules/RULE-30-0-2/ReadsAndWritesOnStreamNotSeparatedByPositioning.ql new file mode 100644 index 0000000000..a5304c6708 --- /dev/null +++ b/cpp/misra/src/rules/RULE-30-0-2/ReadsAndWritesOnStreamNotSeparatedByPositioning.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/reads-and-writes-on-stream-not-separated-by-positioning + * @name RULE-30-0-2: Reads and writes on the same file stream shall be separated by a positioning operation + * @description Alternate input and output operations on a file stream shall not be used without an + * intervening flush or positioning call. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-30-0-2 + * correctness + * scope/system + * external/misra/enforcement/undecidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.iofstreammissingpositioning.IOFstreamMissingPositioning + +class ReadsAndWritesOnStreamNotSeparatedByPositioningQuery extends IOFstreamMissingPositioningSharedQuery +{ + ReadsAndWritesOnStreamNotSeparatedByPositioningQuery() { + this = ImportMisra23Package::readsAndWritesOnStreamNotSeparatedByPositioningQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-5-13-1/BackslashCharacterMisuse.ql b/cpp/misra/src/rules/RULE-5-13-1/BackslashCharacterMisuse.ql new file mode 100644 index 0000000000..fde97e062c --- /dev/null +++ b/cpp/misra/src/rules/RULE-5-13-1/BackslashCharacterMisuse.ql @@ -0,0 +1,21 @@ +/** + * @id cpp/misra/backslash-character-misuse + * @name RULE-5-13-1: In character literals and non-raw string literals, \ shall only be used to form a defined escape + * @description In character literals and non-raw string literals, \ shall only be used to form a + * defined escape sequence or universal character name. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-5-13-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.backslashcharactermisuse.BackslashCharacterMisuse + +class BackslashCharacterMisuseQuery extends BackslashCharacterMisuseSharedQuery { + BackslashCharacterMisuseQuery() { this = ImportMisra23Package::backslashCharacterMisuseQuery() } +} diff --git a/cpp/misra/src/rules/RULE-5-13-2/NonTerminatedEscapeSequences.ql b/cpp/misra/src/rules/RULE-5-13-2/NonTerminatedEscapeSequences.ql new file mode 100644 index 0000000000..d21f1ef1f9 --- /dev/null +++ b/cpp/misra/src/rules/RULE-5-13-2/NonTerminatedEscapeSequences.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/non-terminated-escape-sequences + * @name RULE-5-13-2: Octal escape sequences, hexadecimal escape sequences, and universal character names shall be + * @description Octal escape sequences, hexadecimal escape sequences, and universal character names + * shall be terminated. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-5-13-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.nonterminatedescapesequences.NonTerminatedEscapeSequences + +class NonTerminatedEscapeSequencesQuery extends NonTerminatedEscapeSequencesSharedQuery { + NonTerminatedEscapeSequencesQuery() { + this = ImportMisra23Package::nonTerminatedEscapeSequencesQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-5-13-3/OctalConstantsUsed.ql b/cpp/misra/src/rules/RULE-5-13-3/OctalConstantsUsed.ql new file mode 100644 index 0000000000..38bb96faac --- /dev/null +++ b/cpp/misra/src/rules/RULE-5-13-3/OctalConstantsUsed.ql @@ -0,0 +1,20 @@ +/** + * @id cpp/misra/octal-constants-used + * @name RULE-5-13-3: Octal constants shall not be used + * @description Octal constants shall not be used. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-5-13-3 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.useofnonzerooctalliteral.UseOfNonZeroOctalLiteral + +class OctalConstantsUsedQuery extends UseOfNonZeroOctalLiteralSharedQuery { + OctalConstantsUsedQuery() { this = ImportMisra23Package::octalConstantsUsedQuery() } +} diff --git a/cpp/misra/src/rules/RULE-5-13-4/UnsignedIntegerLiteralsNotAppropriatelySuffixed.ql b/cpp/misra/src/rules/RULE-5-13-4/UnsignedIntegerLiteralsNotAppropriatelySuffixed.ql new file mode 100644 index 0000000000..b3802cf0be --- /dev/null +++ b/cpp/misra/src/rules/RULE-5-13-4/UnsignedIntegerLiteralsNotAppropriatelySuffixed.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/unsigned-integer-literals-not-appropriately-suffixed + * @name RULE-5-13-4: Unsigned integer literals shall be appropriately suffixed + * @description Unsigned integer literals shall be appropriately suffixed. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-5-13-4 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.unsignedintegerliteralsnotappropriatelysuffixed.UnsignedIntegerLiteralsNotAppropriatelySuffixed + +class UnsignedIntegerLiteralsNotAppropriatelySuffixedQuery extends UnsignedIntegerLiteralsNotAppropriatelySuffixedSharedQuery +{ + UnsignedIntegerLiteralsNotAppropriatelySuffixedQuery() { + this = ImportMisra23Package::unsignedIntegerLiteralsNotAppropriatelySuffixedQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-5-13-5/LowercaseLStartsInLiteralSuffix.ql b/cpp/misra/src/rules/RULE-5-13-5/LowercaseLStartsInLiteralSuffix.ql new file mode 100644 index 0000000000..a47c0ded0c --- /dev/null +++ b/cpp/misra/src/rules/RULE-5-13-5/LowercaseLStartsInLiteralSuffix.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/lowercase-l-starts-in-literal-suffix + * @name RULE-5-13-5: The lowercase form of L shall not be used as the first character in a literal suffix + * @description The lowercase form of L shall not be used as the first character in a literal + * suffix. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-5-13-5 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.lowercaselstartsinliteralsuffix.LowercaseLStartsInLiteralSuffix + +class LowercaseLStartsInLiteralSuffixQuery extends LowercaseLStartsInLiteralSuffixSharedQuery { + LowercaseLStartsInLiteralSuffixQuery() { + this = ImportMisra23Package::lowercaseLStartsInLiteralSuffixQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-5-7-1/CharacterSequenceUsedWithinACStyleComment.ql b/cpp/misra/src/rules/RULE-5-7-1/CharacterSequenceUsedWithinACStyleComment.ql new file mode 100644 index 0000000000..1bdb42de77 --- /dev/null +++ b/cpp/misra/src/rules/RULE-5-7-1/CharacterSequenceUsedWithinACStyleComment.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/character-sequence-used-within-ac-style-comment + * @name RULE-5-7-1: The character sequence /* shall not be used within a C-style comment + * @description The character sequence /* shall not be used within a C-style comment. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-5-7-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.charactersequenceusedwithinacstylecomment.CharacterSequenceUsedWithinACStyleComment + +class CharacterSequenceUsedWithinACStyleCommentQuery extends CharacterSequenceUsedWithinACStyleCommentSharedQuery +{ + CharacterSequenceUsedWithinACStyleCommentQuery() { + this = ImportMisra23Package::characterSequenceUsedWithinACStyleCommentQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-5-7-3/LineSplicingUsedInComments.ql b/cpp/misra/src/rules/RULE-5-7-3/LineSplicingUsedInComments.ql new file mode 100644 index 0000000000..ae58fdcda9 --- /dev/null +++ b/cpp/misra/src/rules/RULE-5-7-3/LineSplicingUsedInComments.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/line-splicing-used-in-comments + * @name RULE-5-7-3: Line-splicing shall not be used in // comments + * @description Line-splicing shall not be used in // comments. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-5-7-3 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.linesplicingusedincomments.LineSplicingUsedInComments + +class LineSplicingUsedInCommentsQuery extends LineSplicingUsedInCommentsSharedQuery { + LineSplicingUsedInCommentsQuery() { + this = ImportMisra23Package::lineSplicingUsedInCommentsQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-6-0-3/GlobalNamespaceDeclarations.ql b/cpp/misra/src/rules/RULE-6-0-3/GlobalNamespaceDeclarations.ql new file mode 100644 index 0000000000..addd8f2eab --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-0-3/GlobalNamespaceDeclarations.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/global-namespace-declarations + * @name RULE-6-0-3: The only declarations in the global namespace should be main, namespace declarations and extern "C" + * @description The only declarations in the global namespace should be main, namespace declarations + * and extern "C" declarations. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-6-0-3 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.globalnamespacedeclarations.GlobalNamespaceDeclarations + +class GlobalNamespaceDeclarationsQuery extends GlobalNamespaceDeclarationsSharedQuery { + GlobalNamespaceDeclarationsQuery() { + this = ImportMisra23Package::globalNamespaceDeclarationsQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-6-0-4/NonGlobalFunctionMain.ql b/cpp/misra/src/rules/RULE-6-0-4/NonGlobalFunctionMain.ql new file mode 100644 index 0000000000..f9eb9e1d44 --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-0-4/NonGlobalFunctionMain.ql @@ -0,0 +1,21 @@ +/** + * @id cpp/misra/non-global-function-main + * @name RULE-6-0-4: The identifier main shall not be used for a function other than the global function main + * @description The identifier main shall not be used for a function other than the global function + * main. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-6-0-4 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.nonglobalfunctionmain.NonGlobalFunctionMain + +class NonGlobalFunctionMainQuery extends NonGlobalFunctionMainSharedQuery { + NonGlobalFunctionMainQuery() { this = ImportMisra23Package::nonGlobalFunctionMainQuery() } +} diff --git a/cpp/misra/src/rules/RULE-6-2-1/OneDefinitionRuleViolated.ql b/cpp/misra/src/rules/RULE-6-2-1/OneDefinitionRuleViolated.ql new file mode 100644 index 0000000000..dbef1e4d54 --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-2-1/OneDefinitionRuleViolated.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/one-definition-rule-violated + * @name RULE-6-2-1: The one-definition rule shall not be violated + * @description The one-definition rule specifies when there should be a single definition of an + * element and a violation of that rule leads to undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-6-2-1 + * correctness + * scope/system + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.onedefinitionruleviolation.OneDefinitionRuleViolation + +class OneDefinitionRuleViolatedQuery extends OneDefinitionRuleViolationSharedQuery { + OneDefinitionRuleViolatedQuery() { this = ImportMisra23Package::oneDefinitionRuleViolatedQuery() } +} diff --git a/cpp/misra/src/rules/RULE-6-4-1/VariableDeclaredInInnerScopeHidesOuterScope.ql b/cpp/misra/src/rules/RULE-6-4-1/VariableDeclaredInInnerScopeHidesOuterScope.ql new file mode 100644 index 0000000000..85ece40dc8 --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-4-1/VariableDeclaredInInnerScopeHidesOuterScope.ql @@ -0,0 +1,26 @@ +/** + * @id cpp/misra/variable-declared-in-inner-scope-hides-outer-scope + * @name RULE-6-4-1: A variable declared in an inner scope shall not hide a variable declared in an outer scope + * @description Use of an identifier declared in an inner scope with an identical name to an + * identifier in an outer scope can lead to inadvertent errors if the incorrect + * identifier is modified. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-6-4-1 + * readability + * maintainability + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.identifierhidden.IdentifierHidden + +class VariableDeclaredInInnerScopeHidesOuterScopeQuery extends IdentifierHiddenSharedQuery { + VariableDeclaredInInnerScopeHidesOuterScopeQuery() { + this = ImportMisra23Package::variableDeclaredInInnerScopeHidesOuterScopeQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-6-4-2/DefinitionShallBeConsideredForUnqualifiedLookup.ql b/cpp/misra/src/rules/RULE-6-4-2/DefinitionShallBeConsideredForUnqualifiedLookup.ql new file mode 100644 index 0000000000..faa0857d62 --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-4-2/DefinitionShallBeConsideredForUnqualifiedLookup.ql @@ -0,0 +1,26 @@ +/** + * @id cpp/misra/definition-shall-be-considered-for-unqualified-lookup + * @name RULE-6-4-2: Using declaration followed by new definition + * @description A using declaration that makes a symbol available for unqualified lookup does not + * included definitions defined after the using declaration which can result in + * unexpected behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-6-4-2 + * correctness + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.definitionnotconsideredforunqualifiedlookup.DefinitionNotConsideredForUnqualifiedLookup + +class DefinitionShallBeConsideredForUnqualifiedLookupQuery extends DefinitionNotConsideredForUnqualifiedLookupSharedQuery +{ + DefinitionShallBeConsideredForUnqualifiedLookupQuery() { + this = ImportMisra23Package::definitionShallBeConsideredForUnqualifiedLookupQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-6-4-2/InheritedNonOverridableMemberFunction.ql b/cpp/misra/src/rules/RULE-6-4-2/InheritedNonOverridableMemberFunction.ql new file mode 100644 index 0000000000..b81f2a2c4f --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-4-2/InheritedNonOverridableMemberFunction.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/inherited-non-overridable-member-function + * @name RULE-6-4-2: Member function hides inherited member function + * @description A non-overriding member function definition that hides an inherited member function + * can result in unexpected behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-6-4-2 + * correctness + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.hiddeninheritednonoverridablememberfunction.HiddenInheritedNonOverridableMemberFunction + +class InheritedNonOverridableMemberFunctionQuery extends HiddenInheritedNonOverridableMemberFunctionSharedQuery +{ + InheritedNonOverridableMemberFunctionQuery() { + this = ImportMisra23Package::inheritedNonOverridableMemberFunctionQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-6-4-2/InheritedOverridableMemberFunction.ql b/cpp/misra/src/rules/RULE-6-4-2/InheritedOverridableMemberFunction.ql new file mode 100644 index 0000000000..9fa94560f4 --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-4-2/InheritedOverridableMemberFunction.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/inherited-overridable-member-function + * @name RULE-6-4-2: Member function hides inherited member function + * @description An overriding member function definition thats hides an overload of the overridden + * inherited member function can result in unexpected behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-6-4-2 + * correctness + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.hiddeninheritedoverridablememberfunction.HiddenInheritedOverridableMemberFunction + +class InheritedOverridableMemberFunctionQuery extends HiddenInheritedOverridableMemberFunctionSharedQuery +{ + InheritedOverridableMemberFunctionQuery() { + this = ImportMisra23Package::inheritedOverridableMemberFunctionQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-6-4-3/NameShallBeReferredUsingAQualifiedIdOrThis.ql b/cpp/misra/src/rules/RULE-6-4-3/NameShallBeReferredUsingAQualifiedIdOrThis.ql new file mode 100644 index 0000000000..3d43b4134a --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-4-3/NameShallBeReferredUsingAQualifiedIdOrThis.ql @@ -0,0 +1,26 @@ +/** + * @id cpp/misra/name-shall-be-referred-using-a-qualified-id-or-this + * @name RULE-6-4-3: In a class template with a dependent base, any name that may be found in that dependent base shall shall be referred to using a qualified-id or this-> + * @description Not using a qualified-id or `this->` syntax for identifiers used in a class template + * makes the code more difficult to understand. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-6-4-3 + * maintainability + * readability + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.namenotreferredusingaqualifiedidorthis.NameNotReferredUsingAQualifiedIdOrThis + +class NameShallBeReferredUsingAQualifiedIdOrThisQuery extends NameNotReferredUsingAQualifiedIdOrThisSharedQuery +{ + NameShallBeReferredUsingAQualifiedIdOrThisQuery() { + this = ImportMisra23Package::nameShallBeReferredUsingAQualifiedIdOrThisQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-6-4-3/NameShallBeReferredUsingAQualifiedIdOrThisAudit.ql b/cpp/misra/src/rules/RULE-6-4-3/NameShallBeReferredUsingAQualifiedIdOrThisAudit.ql new file mode 100644 index 0000000000..df2180fc7b --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-4-3/NameShallBeReferredUsingAQualifiedIdOrThisAudit.ql @@ -0,0 +1,26 @@ +/** + * @id cpp/misra/name-shall-be-referred-using-a-qualified-id-or-this-audit + * @name RULE-6-4-3: (Audit) In a class template with a dependent base, any name that may be found in that dependent base shall shall be referred to using a qualified-id or this-> + * @description Not using a qualified-id or `this->` syntax for identifiers used in a class template + * makes the code more difficult to understand. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-6-4-3 + * maintainability + * readability + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.namenotreferredusingaqualifiedidorthisaudit.NameNotReferredUsingAQualifiedIdOrThisAudit + +class NameShallBeReferredUsingAQualifiedIdOrThisAuditQuery extends NameNotReferredUsingAQualifiedIdOrThisAuditSharedQuery +{ + NameShallBeReferredUsingAQualifiedIdOrThisAuditQuery() { + this = ImportMisra23Package::nameShallBeReferredUsingAQualifiedIdOrThisAuditQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-6-8-1/ObjectAccessedAfterLifetimeMisra.ql b/cpp/misra/src/rules/RULE-6-8-1/ObjectAccessedAfterLifetimeMisra.ql new file mode 100644 index 0000000000..77483fdedb --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-8-1/ObjectAccessedAfterLifetimeMisra.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/object-accessed-after-lifetime-misra + * @name RULE-6-8-1: Access of object after lifetime (use-after-free) + * @description Accessing an object after its lifetime results in undefined behavior. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-6-8-1 + * correctness + * security + * external/misra/enforcement/undecidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.objectaccessedafterlifetime.ObjectAccessedAfterLifetime + +class ObjectAccessedAfterLifetimeMisraQuery extends ObjectAccessedAfterLifetimeSharedQuery { + ObjectAccessedAfterLifetimeMisraQuery() { + this = ImportMisra23Package::objectAccessedAfterLifetimeMisraQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-6-8-1/ObjectAccessedBeforeLifetimeMisra.ql b/cpp/misra/src/rules/RULE-6-8-1/ObjectAccessedBeforeLifetimeMisra.ql new file mode 100644 index 0000000000..e0e82f2396 --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-8-1/ObjectAccessedBeforeLifetimeMisra.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/object-accessed-before-lifetime-misra + * @name RULE-6-8-1: Access of uninitialized object + * @description Accessing an object before its lifetime can result in undefined behavior. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-6-8-1 + * correctness + * security + * external/misra/enforcement/undecidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.objectaccessedbeforelifetime.ObjectAccessedBeforeLifetime + +class ObjectAccessedBeforeLifetimeMisraQuery extends ObjectAccessedBeforeLifetimeSharedQuery { + ObjectAccessedBeforeLifetimeMisraQuery() { + this = ImportMisra23Package::objectAccessedBeforeLifetimeMisraQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-6-8-2/ReturnReferenceOrPointerToAutomaticLocalVariable.ql b/cpp/misra/src/rules/RULE-6-8-2/ReturnReferenceOrPointerToAutomaticLocalVariable.ql new file mode 100644 index 0000000000..bcf026cbba --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-8-2/ReturnReferenceOrPointerToAutomaticLocalVariable.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/return-reference-or-pointer-to-automatic-local-variable + * @name RULE-6-8-2: A function must not return a reference or a pointer to a local variable with automatic storage + * @description A function must not return a reference or a pointer to a local variable with + * automatic storage duration. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-6-8-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.returnreferenceorpointertoautomaticlocalvariable.ReturnReferenceOrPointerToAutomaticLocalVariable + +class ReturnReferenceOrPointerToAutomaticLocalVariableQuery extends ReturnReferenceOrPointerToAutomaticLocalVariableSharedQuery +{ + ReturnReferenceOrPointerToAutomaticLocalVariableQuery() { + this = ImportMisra23Package::returnReferenceOrPointerToAutomaticLocalVariableQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.ql b/cpp/misra/src/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.ql new file mode 100644 index 0000000000..ff1d6f1d98 --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/avoid-standard-integer-type-names + * @name RULE-6-9-2: The names of the standard signed integer types and standard unsigned integer types should not be + * @description Using standard signed and unsigned integer type names instead of specified width + * types makes storage requirements unclear and implementation-dependent. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-6-9-2 + * scope/single-translation-unit + * correctness + * maintainability + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.variablewidthintegertypesused.VariableWidthIntegerTypesUsed + +class AvoidStandardIntegerTypeNamesQuery extends VariableWidthIntegerTypesUsedSharedQuery { + AvoidStandardIntegerTypeNamesQuery() { + this = BannedAPIsPackage::avoidStandardIntegerTypeNamesQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql b/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql new file mode 100644 index 0000000000..6baa1ed648 --- /dev/null +++ b/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql @@ -0,0 +1,40 @@ +/** + * @id cpp/misra/no-conversion-from-bool + * @name RULE-7-0-1: There shall be no conversion from type bool + * @description Converting a bool type (implicitly or explicitly) to another type can lead to + * unintended behavior and code obfuscation, particularly when using bitwise operators + * instead of logical operators. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-0-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.misra.BuiltInTypeRules + +from Expr e, Conversion conv +where + not isExcluded(e, ConversionsPackage::noConversionFromBoolQuery()) and + conv = e.getConversion() and + conv.getExpr().getType().stripTopLevelSpecifiers() instanceof BoolType and + not conv.getType().stripTopLevelSpecifiers() instanceof BoolType and + // Exclude cases that are explicitly allowed + not ( + // Exception: equality operators with both bool operands + exists(EqualityOperation eq | + eq.getAnOperand() = e and + eq.getLeftOperand().getType().stripTopLevelSpecifiers() instanceof BoolType and + eq.getRightOperand().getType().stripTopLevelSpecifiers() instanceof BoolType + ) + or + // Exception: assignment to bit-field of length 1 + MisraCpp23BuiltInTypes::isAssignedToBitfield(e, _) + // Note: conversions that result in a constructor call are not represented as `Conversion`s + // in our model, so do not need to be excluded here. + ) +select e, "Conversion from 'bool' to '" + conv.getType() + "'." diff --git a/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql b/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql new file mode 100644 index 0000000000..ae70b20259 --- /dev/null +++ b/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql @@ -0,0 +1,101 @@ +/** + * @id cpp/misra/no-implicit-bool-conversion + * @name RULE-7-0-2: There shall be no conversion to type bool + * @description Implicit and contextual conversions to bool from fundamental types, unscoped enums, + * or pointers may lead to unintended behavior, except for specific cases like pointer + * checks and explicit operator bool conversions. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-0-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +predicate isInContextualBoolContext(Expr expr) { + exists(IfStmt ifStmt | ifStmt.getCondition() = expr) or + exists(WhileStmt whileStmt | whileStmt.getCondition() = expr) or + exists(ForStmt forStmt | forStmt.getCondition() = expr) or + exists(DoStmt doStmt | doStmt.getCondition() = expr) or + exists(ConditionalExpr condExpr | condExpr.getCondition() = expr) or + exists(LogicalAndExpr logicalAnd | logicalAnd.getAnOperand() = expr) or + exists(LogicalOrExpr logicalOr | logicalOr.getAnOperand() = expr) or + exists(NotExpr notExpr | notExpr.getOperand() = expr) +} + +predicate isInWhileConditionDeclaration(Expr expr) { + exists(WhileStmt whileStmt, ConditionDeclExpr condDecl | + whileStmt.getCondition() = condDecl and + condDecl.getExpr() = expr + ) +} + +predicate isBitFieldOfSizeOne(Expr expr) { + exists(BitField bf | + expr = bf.getAnAccess() and + bf.getNumBits() = 1 + ) +} + +predicate isPointerType(Type t) { + t.getUnspecifiedType() instanceof PointerType or + t.getUnspecifiedType() instanceof PointerToMemberType or + t.getUnspecifiedType() instanceof NullPointerType +} + +from Element e, string reason +where + not isExcluded(e, ConversionsPackage::noImplicitBoolConversionQuery()) and + ( + // Conversions to bool + exists(Conversion conv | + e = conv and + conv.getType().getUnspecifiedType() instanceof BoolType and + not conv.getExpr().getType().getUnspecifiedType() instanceof BoolType and + // Exception 2: Contextual conversion from pointer + not ( + isPointerType(conv.getExpr().getType()) and + // Checks if the unconverted expression for this conversion is in a contextual bool context + // This handles the cases where we have multiple stacked conversions, e.g. when converting + // an array to a pointer, then the pointer to bool + isInContextualBoolContext(conv.getUnconverted()) + ) and + // Exception 3: Unconverted expression is a bit-field of size 1 + not isBitFieldOfSizeOne(conv.getUnconverted()) and + // Exception 4: Unconverted expression is in a while condition declaration + not isInWhileConditionDeclaration(conv.getUnconverted()) and + reason = "Conversion from '" + conv.getExpr().getType().toString() + "' to 'bool'" + ) + or + // Calls to conversion operators to bool + // + // Note: we flag these separately because: + // 1. If the conversion via the operator is implicit, there is no `Conversion` - only a call to + // the `ConversionOperator`. + // 2. If the conversion is explicit, the `Conversion` is from `bool` to `bool`, which is not + // flagged in the previous `Conversion` case above. + exists(Call conversionCall, ConversionOperator op | + e = conversionCall and + conversionCall.getTarget() = op and + op.getType().getUnspecifiedType() instanceof BoolType and + // Exception 1: Static cast to bool from class with explicit operator bool + not exists(StaticCast conv | + op.isExplicit() and + conv.getExpr() = conversionCall and + conv.getType().getUnspecifiedType() instanceof BoolType + ) and + // Exception 2: Contextual conversion from class with explicit operator bool is allowed + not ( + op.isExplicit() and + isInContextualBoolContext(conversionCall.getUnconverted()) + ) and + reason = + "Conversion operator call from '" + conversionCall.getQualifier().getType().toString() + + "' to 'bool'" + ) + ) +select e, reason + "." diff --git a/cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql b/cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql new file mode 100644 index 0000000000..7ecbd8959f --- /dev/null +++ b/cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql @@ -0,0 +1,47 @@ +/** + * @id cpp/misra/no-character-numerical-value + * @name RULE-7-0-3: The numerical value of a character shall not be used + * @description Using the numerical value of a character type may lead to inconsistent behavior due + * to encoding dependencies and should be avoided in favor of safer C++ Standard + * Library functions. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-0-3 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra.BuiltInTypeRules + +from Conversion c, Expr expr, Type sourceType, Type targetType +where + expr = c.getExpr() and + sourceType = expr.getType() and + targetType = c.getType() and + ( + // Conversion from character type to non-character type + sourceType instanceof MisraCpp23BuiltInTypes::CharacterType and + not targetType instanceof MisraCpp23BuiltInTypes::CharacterType + or + // Conversion from non-character type to character type + not sourceType instanceof MisraCpp23BuiltInTypes::CharacterType and + targetType instanceof MisraCpp23BuiltInTypes::CharacterType + ) and + // Exclude conversions where both operands have the same character type in equality operations + not exists( + EqualityOperation eq, MisraCpp23BuiltInTypes::CharacterType leftType, + MisraCpp23BuiltInTypes::CharacterType rightType + | + eq.getAnOperand() = expr and + leftType = eq.getLeftOperand().getType() and + rightType = eq.getRightOperand().getType() and + leftType.isSameType(rightType) + ) and + // Exclude unevaluated operands + not expr.isUnevaluated() +select expr, + "Conversion of character type '" + sourceType.getName() + "' to '" + targetType.getName() + + "' uses numerical value of character." diff --git a/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql b/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql new file mode 100644 index 0000000000..e1f1e21069 --- /dev/null +++ b/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql @@ -0,0 +1,120 @@ +/** + * @id cpp/misra/inappropriate-bitwise-or-shift-operands + * @name RULE-7-0-4: The operands of bitwise operators and shift operators shall be appropriate + * @description Bitwise and shift operators should only be applied to operands of appropriate types + * and values to avoid implementation-defined or undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-0-4 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.misra.BuiltInTypeRules +import codingstandards.cpp.BinaryOperations + +predicate isConstantExpression(Expr e) { + e instanceof Literal or + e.isConstant() +} + +predicate isValidShiftConstantRange(Expr right, Type leftType) { + exists(int value | + value = right.getValue().toInt() and + value >= 0 and + value < leftType.getSize() * 8 + ) +} + +predicate isSignedConstantLeftShiftException(LShiftExpr shift) { + exists( + Expr left, Expr right, MisraCpp23BuiltInTypes::NumericType leftType, QlBuiltins::BigInt leftVal, + int rightVal, int maxBit + | + left = shift.getLeftOperand() and + right = shift.getRightOperand() and + leftType = left.getType() and + isConstantExpression(left) and + isConstantExpression(right) and + MisraCpp23BuiltInTypes::isSignedType(leftType) and + isValidShiftConstantRange(right, leftType) and + leftVal = left.getValue().toBigInt() and + rightVal = right.getValue().toInt() and + leftVal >= 0.toBigInt() and + maxBit = leftType.getBuiltInSize() * 8 - 1 and + // Check that no set bit is shifted into or beyond the sign bit + leftVal * 2.toBigInt().pow(rightVal) < 2.toBigInt().pow(maxBit) + ) +} + +from Expr x, string message +where + not isExcluded(x, ConversionsPackage::inappropriateBitwiseOrShiftOperandsQuery()) and + ( + // Binary bitwise operators (excluding shift operations) - both operands must be unsigned + exists(BinaryBitwiseOpOrAssignOp op, Type operandType | + not op instanceof BinaryShiftOpOrAssignOp + | + x = op.getLeftOperand() and + operandType = op.getLeftOperand().getExplicitlyConverted().getType() and + not MisraCpp23BuiltInTypes::isUnsignedType(operandType) and + message = + "Bitwise operator '" + op.getOperator() + + "' requires unsigned numeric operands, but the left operand has type '" + operandType + + "'." + or + x = op.getRightOperand() and + operandType = op.getRightOperand().getExplicitlyConverted().getType() and + not MisraCpp23BuiltInTypes::isUnsignedType(operandType) and + message = + "Bitwise operator '" + op.getOperator() + + "' requires unsigned numeric operands, but the right operand has type '" + operandType + + "'." + ) + or + // Bit complement operator - operand must be unsigned + exists(ComplementExpr comp, Type opType | + x = comp.getOperand() and + opType = comp.getOperand().getExplicitlyConverted().getType() and + not MisraCpp23BuiltInTypes::isUnsignedType(opType) and + message = + "Bit complement operator '~' requires unsigned operand, but has type '" + opType + "'." + ) + or + // Shift operators - left operand must be unsigned + exists(BinaryShiftOpOrAssignOp shift, Type leftType | + x = shift.getLeftOperand() and + leftType = shift.getLeftOperand().getExplicitlyConverted().getType() and + not MisraCpp23BuiltInTypes::isUnsignedType(leftType) and + not isSignedConstantLeftShiftException(shift) and + message = + "Shift operator '" + shift.getOperator() + + "' requires unsigned left operand, but has type '" + leftType + "'." + ) + or + // Shift operators - right operand must be unsigned or constant in valid range + exists(BinaryShiftOpOrAssignOp shift, Expr right, Type rightType, Type leftType | + right = shift.getRightOperand() and + x = right and + rightType = right.getExplicitlyConverted().getType() and + leftType = shift.getLeftOperand().getExplicitlyConverted().getType() + | + if exists(right.getValue().toInt()) + then + not isValidShiftConstantRange(right, leftType) and + message = + "Shift operator '" + shift.getOperator() + "' shifts by " + right.getValue().toInt() + + " which is not within the valid range 0.." + ((leftType.getSize() * 8) - 1) + "." + else ( + not MisraCpp23BuiltInTypes::isUnsignedType(rightType) and + message = + "Shift operator '" + shift.getOperator() + + "' requires unsigned right operand, but has type '" + rightType + "'." + ) + ) + ) +select x, message diff --git a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql new file mode 100644 index 0000000000..05261d6f6c --- /dev/null +++ b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql @@ -0,0 +1,51 @@ +/** + * @id cpp/misra/no-signedness-change-from-promotion + * @name RULE-7-0-5: Integral promotion and the usual arithmetic conversions shall not change the signedness or the type + * @description Integral promotion and usual arithmetic conversions that change operand signedness + * or type category may cause unexpected behavior or undefined behavior when operations + * overflow. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-0-5 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.misra.ArithmeticConversions +import codingstandards.cpp.misra.BuiltInTypeRules + +from + Expr e, IntegerPromotionOrUsualArithmeticConversion c, + MisraCpp23BuiltInTypes::NumericType fromType, MisraCpp23BuiltInTypes::NumericType toType, + string changeType +where + not isExcluded(e, ConversionsPackage::noSignednessChangeFromPromotionQuery()) and + c.getConvertedExpr() = e and + fromType = c.getFromType() and + toType = c.getToType() and + ( + fromType.getSignedness() != toType.getSignedness() and changeType = "signedness" + or + fromType.getTypeCategory() != toType.getTypeCategory() and changeType = "type category" + ) and + // Ignore crement operations + not exists(CrementOperation cop | cop.getAnOperand() = e) and + // Exception 1: allow safe constant conversions + not ( + e.getValue().toInt() >= 0 and + fromType.(IntegralType).isSigned() and + toType.(IntegralType).isUnsigned() + ) and + // Exception 2: allow safe conversions from integral to floating-point types + not ( + e.isConstant() and + fromType.getTypeCategory() = MisraCpp23BuiltInTypes::IntegralTypeCategory() and + toType.getTypeCategory() = MisraCpp23BuiltInTypes::FloatingPointTypeCategory() + ) +select e, + c.getKindOfConversion() + " from '" + fromType.getName() + "' to '" + toType.getName() + + "' changes " + changeType + "." diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql new file mode 100644 index 0000000000..972f151f9d --- /dev/null +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -0,0 +1,233 @@ +/** + * @id cpp/misra/numeric-assignment-type-mismatch + * @name RULE-7-0-6: Assignment between numeric types shall be appropriate + * @description Assignment between numeric types with different sizes, signedness, or type + * categories can lead to unexpected information loss, undefined behavior, or silent + * overload resolution changes. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-7-0-6 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.ConstantExpressions +import codingstandards.cpp.misra.BuiltInTypeRules +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis + +predicate isValidConstantAssignment( + IntegerConstantExpr source, MisraCpp23BuiltInTypes::NumericType targetType +) { + MisraCpp23BuiltInTypes::isAssignment(source, targetType, _) and + exists(QlBuiltins::BigInt val | val = source.getConstantValue() | + // Bit field assignment: check if the value fits in the bit field + exists(BitField bf, int numBits | + MisraCpp23BuiltInTypes::isAssignedToBitfield(source, bf) and + numBits = bf.getNumBits() and + if targetType.getSignedness() = MisraCpp23BuiltInTypes::Signed() + then + // Signed bit field: value must be in the range of signed bit field + val >= -2.toBigInt().pow(numBits - 1) and + val < 2.toBigInt().pow(numBits - 1) + else ( + // Unsigned bit field: value must be in the range of unsigned bit field + val >= 0.toBigInt() and + val < 2.toBigInt().pow(numBits) + ) + ) + or + // Regular assignment: check if the value fits in the target type range + not MisraCpp23BuiltInTypes::isAssignedToBitfield(source, _) and + ( + // Integer types: check if the value fits in the target type range + targetType.getIntegralLowerBound() <= val and + val <= targetType.getIntegralUpperBound() + or + // All floating point types can represent all integer values + targetType.getTypeCategory() = MisraCpp23BuiltInTypes::FloatingPointTypeCategory() + ) + ) +} + +bindingset[sourceType, targetType] +pragma[inline_late] +predicate isValidTypeMatch( + MisraCpp23BuiltInTypes::NumericType sourceType, MisraCpp23BuiltInTypes::NumericType targetType +) { + // Same type category, signedness and size + sourceType.getTypeCategory() = targetType.getTypeCategory() and + sourceType.getSignedness() = targetType.getSignedness() and + sourceType.getBuiltInSize() = targetType.getBuiltInSize() +} + +/** + * A constructor that can be called with a single argument + */ +private class CallableWithASingleArgumentConstructor extends Constructor { + CallableWithASingleArgumentConstructor() { + // Either a constructor with a single parameter + this.getNumberOfParameters() = 1 + or + // Or the second (and later parameters) all have defaults + exists(this.getParameter(1).getInitializer()) + } +} + +predicate hasConstructorException(FunctionCall call) { + exists(CallableWithASingleArgumentConstructor ctor, Class c | + call.getTarget() = ctor and + c = ctor.getDeclaringType() and + // Constructor callable with single numeric argument + ctor.getParameter(0).getType() instanceof MisraCpp23BuiltInTypes::NumericType and + // No other single-argument constructors except copy/move + not exists(CallableWithASingleArgumentConstructor other | + other.getDeclaringType() = c and + other != ctor and + not other instanceof CopyConstructor and + not other instanceof MoveConstructor + ) + ) +} + +/** + * An id-expression that has a numeric type. + * + * This is restricted to variable accesses, that are not explicitly qualified in any way. + */ +class IdExpression extends VariableAccess { + IdExpression() { + // Not a member variable access (no dot or arrow) + ( + not exists(this.getQualifier()) + or + // Member variable, but the qualifier is not explicit + this.getQualifier().isCompilerGenerated() + ) and + // Not an id-expression if it's an explicit conversion + not this.hasExplicitConversion() + } +} + +predicate isValidWidening( + Expr source, MisraCpp23BuiltInTypes::NumericType sourceType, + MisraCpp23BuiltInTypes::NumericType targetType +) { + MisraCpp23BuiltInTypes::isAssignment(source, targetType, _) and + source.getType() = sourceType and + // Same type category and signedness, source size smaller, source is id-expression or has constructor exception + ( + source instanceof IdExpression or + hasConstructorException(any(Call call | call.getAnArgument().getExplicitlyConverted() = source)) + ) and + sourceType.getTypeCategory() = targetType.getTypeCategory() and + sourceType.getSignedness() = targetType.getSignedness() and + sourceType.getBuiltInSize() < targetType.getBuiltInSize() +} + +/** + * A non-extensible call is a call that cannot be extended by adding new overloads. + */ +predicate isNonExtensible(Call c) { + exists(NameQualifier qual | qual.getExpr() = c and c.getTarget() instanceof MemberFunction) + or + exists(c.getQualifier()) and not c.getQualifier().isCompilerGenerated() + or + c.getTarget() instanceof Operator +} + +int getMinimumNumberOfParameters(Function f) { + result = count(Parameter p | p = f.getAParameter() and not p.hasInitializer() | p) +} + +/** Get an overload of the function f, excluding deleted overloads. */ +Function getAnOverload(Function f) { + ( + result = f.getAnOverload() + or + // Instantiated function templates don't directly participate in overload resolution + // so check the templates overloads + result = f.(FunctionTemplateInstantiation).getTemplate().getAnOverload() + ) and + // Exclude deleted overloads + not result.isDeleted() +} + +predicate isOverloadIndependent(Call call, Expr arg) { + exists(int i | arg = call.getArgument(i) | + // Call through function pointer + call instanceof ExprCall + or + isNonExtensible(call) and + exists(Function target | target = call.getTarget() | + forall(Function overload | + overload = getAnOverload(target) and + // Check that the overload accepts the number of arguments provided by this call, + // considering parameters with default values may be omitted in the call + overload.getNumberOfParameters() >= call.getNumberOfArguments() and + getMinimumNumberOfParameters(overload) <= call.getNumberOfArguments() + | + // Check that the parameter types match + overload.getParameter(i).getType().getUnspecifiedType() = + target.getParameter(i).getType().getUnspecifiedType() + ) + ) + ) +} + +/** + * Check if the source expression should have the same type as the target type. + */ +predicate shouldHaveSameType(Expr source) { + exists(Call call | + call.getAnArgument().getExplicitlyConverted() = source and + MisraCpp23BuiltInTypes::isAssignment(source, _, _) and + not hasConstructorException(call) + | + not isOverloadIndependent(call, source) + or + // Passed as a varargs parameter + exists(int i | + call.getTarget().isVarargs() and + call.getArgument(i).getExplicitlyConverted() = source and + // Argument is greater than the number of parameters + call.getTarget().getNumberOfParameters() <= i + ) + ) +} + +predicate isValidAssignment( + Expr source, MisraCpp23BuiltInTypes::NumericType targetType, string context +) { + MisraCpp23BuiltInTypes::isAssignment(source, targetType, context) and + exists(MisraCpp23BuiltInTypes::NumericType sourceType | sourceType = source.getType() | + if shouldHaveSameType(source) + then sourceType.isSameType(targetType) + else ( + // Valid type match + isValidTypeMatch(sourceType, targetType) + or + // Valid widening assignment + isValidWidening(source, sourceType, targetType) + or + // Valid constant assignment (integer constants) + isValidConstantAssignment(source, targetType) + ) + ) +} + +from + Expr source, MisraCpp23BuiltInTypes::NumericType sourceType, + MisraCpp23BuiltInTypes::NumericType targetType, string context +where + not isExcluded(source, ConversionsPackage::numericAssignmentTypeMismatchQuery()) and + MisraCpp23BuiltInTypes::isAssignment(source, targetType, context) and + // The assignment must be between numeric types + sourceType = source.getType() and + not isValidAssignment(source, targetType, context) +select source, + "Assignment between incompatible numeric types from '" + sourceType.getName() + "' to '" + + targetType.getName() + "'." diff --git a/cpp/misra/src/rules/RULE-7-11-1/NullptrNotTheOnlyFormOfTheNullPointerConstant.ql b/cpp/misra/src/rules/RULE-7-11-1/NullptrNotTheOnlyFormOfTheNullPointerConstant.ql new file mode 100644 index 0000000000..a0dfc63799 --- /dev/null +++ b/cpp/misra/src/rules/RULE-7-11-1/NullptrNotTheOnlyFormOfTheNullPointerConstant.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/nullptr-not-the-only-form-of-the-null-pointer-constant + * @name RULE-7-11-1: nullptr shall be the only form of the null-pointer-constant + * @description nullptr shall be the only form of the null-pointer-constant. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-11-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.nullptrnottheonlyformofthenullpointerconstant.NullptrNotTheOnlyFormOfTheNullPointerConstant + +class NullptrNotTheOnlyFormOfTheNullPointerConstantQuery extends NullptrNotTheOnlyFormOfTheNullPointerConstantSharedQuery +{ + NullptrNotTheOnlyFormOfTheNullPointerConstantQuery() { + this = ImportMisra23Package::nullptrNotTheOnlyFormOfTheNullPointerConstantQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-7-11-2/ArrayPassedAsFunctionArgumentDecayToAPointer.ql b/cpp/misra/src/rules/RULE-7-11-2/ArrayPassedAsFunctionArgumentDecayToAPointer.ql new file mode 100644 index 0000000000..fed33c33de --- /dev/null +++ b/cpp/misra/src/rules/RULE-7-11-2/ArrayPassedAsFunctionArgumentDecayToAPointer.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/array-passed-as-function-argument-decay-to-a-pointer + * @name RULE-7-11-2: An array passed as a function argument shall not decay to a pointer + * @description An array passed as a function argument shall not decay to a pointer. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-11-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.arraypassedasfunctionargumentdecaytoapointer.ArrayPassedAsFunctionArgumentDecayToAPointer + +class ArrayPassedAsFunctionArgumentDecayToAPointerQuery extends ArrayPassedAsFunctionArgumentDecayToAPointerSharedQuery +{ + ArrayPassedAsFunctionArgumentDecayToAPointerQuery() { + this = ImportMisra23Package::arrayPassedAsFunctionArgumentDecayToAPointerQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-7-11-3/FunctionPointerConversionContext.ql b/cpp/misra/src/rules/RULE-7-11-3/FunctionPointerConversionContext.ql new file mode 100644 index 0000000000..f58629f536 --- /dev/null +++ b/cpp/misra/src/rules/RULE-7-11-3/FunctionPointerConversionContext.ql @@ -0,0 +1,65 @@ +/** + * @id cpp/misra/function-pointer-conversion-context + * @name RULE-7-11-3: A conversion from function type to pointer-to-function type shall only occur in appropriate contexts + * @description Converting a function type to a pointer-to-function type outside of static_cast or + * assignment to a pointer-to-function object creates ambiguous behavior and potential + * unintended effects. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-11-3 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.misra.BuiltInTypeRules +import codingstandards.cpp.Type + +/** + * An `Expr` representing an implicit conversion from a function type to a pointer-to-function type. + * + * Despite the name, these are not `Conversion`s in our model. Instead, they are expressions + * representing functions that have been implicilty converted to function pointers. + */ +abstract class FunctionToFunctionPointerConversion extends Expr { } + +/** + * A `FunctionAccess` that has been implicitly converted to a function pointer type. + */ +class FunctionAccessConversionToFunctionPointer extends FunctionAccess, + FunctionToFunctionPointerConversion +{ + FunctionAccessConversionToFunctionPointer() { + this.getType().getUnspecifiedType() instanceof FunctionPointerIshType + } +} + +/** + * A `Call` to a `ConversionOperator` that converts a lambda to a function pointer type. + */ +class LambdaFunctionPointerConversion extends Call, FunctionToFunctionPointerConversion { + LambdaFunctionPointerConversion() { + this.getTarget().(ConversionOperator).getDestType() instanceof FunctionPointerIshType and + this.getQualifier().getType().getUnspecifiedType() instanceof Closure + } +} + +from FunctionToFunctionPointerConversion f +where + not isExcluded(f, ConversionsPackage::functionPointerConversionContextQuery()) and + // Not converted by an explicit static cast + not exists(Conversion c | + c.getExpr() = f and + not c.isImplicit() and + c.getType().getUnspecifiedType() instanceof FunctionPointerIshType + ) and + // Not a MISRA compliant assignment to a function pointer type + not exists(FunctionPointerIshType targetType | + MisraCpp23BuiltInTypes::isAssignment(f, targetType, _) + ) +select f, + "Inappropriate conversion from function type to pointer-to-function type in '" + f.toString() + + "'." diff --git a/cpp/misra/src/rules/RULE-8-18-2/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql b/cpp/misra/src/rules/RULE-8-18-2/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql new file mode 100644 index 0000000000..6c4b1a82ad --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-18-2/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/result-of-an-assignment-operator-should-not-be-used + * @name RULE-8-18-2: The result of an assignment operator should not be used + * @description The result of an assignment operator should not be used. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-18-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.resultofanassignmentoperatorshouldnotbeused.ResultOfAnAssignmentOperatorShouldNotBeUsed + +class ResultOfAnAssignmentOperatorShouldNotBeUsedQuery extends ResultOfAnAssignmentOperatorShouldNotBeUsedSharedQuery +{ + ResultOfAnAssignmentOperatorShouldNotBeUsedQuery() { + this = ImportMisra23Package::resultOfAnAssignmentOperatorShouldNotBeUsedQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-8-19-1/CommaOperatorShouldNotBeUsed.ql b/cpp/misra/src/rules/RULE-8-19-1/CommaOperatorShouldNotBeUsed.ql new file mode 100644 index 0000000000..df5be50dc0 --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-19-1/CommaOperatorShouldNotBeUsed.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/comma-operator-should-not-be-used + * @name RULE-8-19-1: The comma operator should not be used + * @description The comma operator should not be used. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-19-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.commaoperatorused.CommaOperatorUsed + +class CommaOperatorShouldNotBeUsedQuery extends CommaOperatorUsedSharedQuery { + CommaOperatorShouldNotBeUsedQuery() { + this = ImportMisra23Package::commaOperatorShouldNotBeUsedQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.ql b/cpp/misra/src/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.ql new file mode 100644 index 0000000000..858aaec42c --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/virtual-base-class-cast-to-derived + * @name RULE-8-2-1: A virtual base class shall only be cast to a derived class by means of dynamic_cast + * @description Casting from a virtual base class to a derived class using anything other than + * dynamic_cast causes undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-2-1 + * scope/single-translation-unit + * correctness + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.pointertoavirtualbaseclasscasttoapointer.PointerToAVirtualBaseClassCastToAPointer + +class VirtualBaseClassCastToDerivedQuery extends PointerToAVirtualBaseClassCastToAPointerSharedQuery +{ + VirtualBaseClassCastToDerivedQuery() { + this = Conversions2Package::virtualBaseClassCastToDerivedQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-8-2-10/FunctionsCallThemselvesEitherDirectlyOrIndirectly.ql b/cpp/misra/src/rules/RULE-8-2-10/FunctionsCallThemselvesEitherDirectlyOrIndirectly.ql new file mode 100644 index 0000000000..ff0f397572 --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-2-10/FunctionsCallThemselvesEitherDirectlyOrIndirectly.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/functions-call-themselves-either-directly-or-indirectly + * @name RULE-8-2-10: Functions shall not call themselves, either directly or indirectly + * @description Functions shall not call themselves, either directly or indirectly. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-2-10 + * scope/system + * external/misra/enforcement/undecidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.functionscallthemselveseitherdirectlyorindirectly.FunctionsCallThemselvesEitherDirectlyOrIndirectly + +class FunctionsCallThemselvesEitherDirectlyOrIndirectlyQuery extends FunctionsCallThemselvesEitherDirectlyOrIndirectlySharedQuery +{ + FunctionsCallThemselvesEitherDirectlyOrIndirectlyQuery() { + this = ImportMisra23Package::functionsCallThemselvesEitherDirectlyOrIndirectlyQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.ql b/cpp/misra/src/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.ql new file mode 100644 index 0000000000..441720c5e4 --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.ql @@ -0,0 +1,35 @@ +/** + * @id cpp/misra/no-c-style-or-functional-casts + * @name RULE-8-2-2: C-style casts and functional notation casts shall not be used + * @description Using C-style casts or functional notation casts allows unsafe type conversions and + * makes code harder to maintain compared to using named casts like const_cast, + * dynamic_cast, static_cast and reinterpret_cast. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-2-2 + * scope/single-translation-unit + * readability + * correctness + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.CStyleCasts +import codingstandards.cpp.AlertReporting + +class MISRACPPProhibitedCStyleCasts extends ExplicitUserDefinedCStyleCast { + MISRACPPProhibitedCStyleCasts() { + // MISRA C++ permits casts to void types + not getType() instanceof VoidType + } +} + +from Element reportingElement, MISRACPPProhibitedCStyleCasts c +where + not isExcluded(c, Conversions2Package::noCStyleOrFunctionalCastsQuery()) and + reportingElement = MacroUnwrapper::unwrapElement(c) and + exists(reportingElement.getFile().getRelativePath()) // within user code - validated during testing +select reportingElement, "Use of explicit c-style cast to " + c.getType().getName() + "." diff --git a/cpp/misra/src/rules/RULE-8-2-3/CastRemovesConstOrVolatileFromPointerOrReference.ql b/cpp/misra/src/rules/RULE-8-2-3/CastRemovesConstOrVolatileFromPointerOrReference.ql new file mode 100644 index 0000000000..935050fdd9 --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-2-3/CastRemovesConstOrVolatileFromPointerOrReference.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/cast-removes-const-or-volatile-from-pointer-or-reference + * @name RULE-8-2-3: A cast shall not remove any const or volatile qualification from the type accessed via a pointer or + * @description A cast shall not remove any const or volatile qualification from the type accessed + * via a pointer or by reference. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-2-3 + * correctness + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.removeconstorvolatilequalification.RemoveConstOrVolatileQualification + +class CastRemovesConstOrVolatileFromPointerOrReferenceQuery extends RemoveConstOrVolatileQualificationSharedQuery +{ + CastRemovesConstOrVolatileFromPointerOrReferenceQuery() { + this = ImportMisra23Package::castRemovesConstOrVolatileFromPointerOrReferenceQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-8-2-4/CastsBetweenAPointerToFunctionAndAnyOtherType.ql b/cpp/misra/src/rules/RULE-8-2-4/CastsBetweenAPointerToFunctionAndAnyOtherType.ql new file mode 100644 index 0000000000..37c258b722 --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-2-4/CastsBetweenAPointerToFunctionAndAnyOtherType.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/casts-between-a-pointer-to-function-and-any-other-type + * @name RULE-8-2-4: Casts shall not be performed between a pointer to function and any other type + * @description Casts shall not be performed between a pointer to function and any other type. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-2-4 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.castsbetweenapointertofunctionandanyothertype.CastsBetweenAPointerToFunctionAndAnyOtherType + +class CastsBetweenAPointerToFunctionAndAnyOtherTypeQuery extends CastsBetweenAPointerToFunctionAndAnyOtherTypeSharedQuery +{ + CastsBetweenAPointerToFunctionAndAnyOtherTypeQuery() { + this = ImportMisra23Package::castsBetweenAPointerToFunctionAndAnyOtherTypeQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-8-2-5/ReinterpretCastShallNotBeUsed.ql b/cpp/misra/src/rules/RULE-8-2-5/ReinterpretCastShallNotBeUsed.ql new file mode 100644 index 0000000000..685ebb7efd --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-2-5/ReinterpretCastShallNotBeUsed.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/reinterpret-cast-shall-not-be-used + * @name RULE-8-2-5: reinterpret_cast shall not be used + * @description reinterpret_cast shall not be used. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-2-5 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.reinterpretcastused.ReinterpretCastUsed + +class ReinterpretCastShallNotBeUsedQuery extends ReinterpretCastUsedSharedQuery { + ReinterpretCastShallNotBeUsedQuery() { + this = ImportMisra23Package::reinterpretCastShallNotBeUsedQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-8-2-6/IntToPointerCastProhibited.ql b/cpp/misra/src/rules/RULE-8-2-6/IntToPointerCastProhibited.ql new file mode 100644 index 0000000000..0a97dc5359 --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-2-6/IntToPointerCastProhibited.ql @@ -0,0 +1,42 @@ +/** + * @id cpp/misra/int-to-pointer-cast-prohibited + * @name RULE-8-2-6: An object with integral, enumerated, or pointer to void type shall not be cast to a pointer type + * @description Casting from an integral type, enumerated type, or pointer to void type to a pointer + * type leads to unspecified behavior and is error prone. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-2-6 + * scope/single-translation-unit + * correctness + * maintainability + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +from Cast cast, Type sourceType, PointerType targetType, string typeKind +where + not isExcluded(cast, Conversions2Package::intToPointerCastProhibitedQuery()) and + sourceType = cast.getExpr().getType().getUnspecifiedType() and + targetType = cast.getType().getUnspecifiedType() and + ( + // Integral types + sourceType instanceof IntegralType and + typeKind = "integral" + or + // Enumerated types + sourceType instanceof Enum and + typeKind = "enumerated" + or + // Pointer to void type + sourceType.(PointerType).getBaseType() instanceof VoidType and + typeKind = "pointer to void" and + // Exception: casts between void pointers are allowed + not targetType.getBaseType() instanceof VoidType + ) +select cast, + "Cast from " + typeKind + " type '" + cast.getExpr().getType() + "' to pointer type '" + + cast.getType() + "'." diff --git a/cpp/misra/src/rules/RULE-8-2-7/NoPointerToIntegralCast.ql b/cpp/misra/src/rules/RULE-8-2-7/NoPointerToIntegralCast.ql new file mode 100644 index 0000000000..dde10b0e40 --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-2-7/NoPointerToIntegralCast.ql @@ -0,0 +1,26 @@ +/** + * @id cpp/misra/no-pointer-to-integral-cast + * @name RULE-8-2-7: A cast should not convert a pointer type to an integral type + * @description Casting between pointer types and integral types makes code behavior harder to + * understand and may cause pointer tracking tools to become unreliable. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-2-7 + * scope/single-translation-unit + * correctness + * maintainability + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra + +from Cast cast, Type sourceType, IntegralType targetType +where + not isExcluded(cast, Conversions2Package::noPointerToIntegralCastQuery()) and + sourceType = cast.getExpr().getType().getUnspecifiedType() and + targetType = cast.getType().getUnspecifiedType() and + (sourceType instanceof PointerType or sourceType instanceof FunctionPointerType) +select cast, "Cast converts pointer type to integral type '" + targetType + "'." diff --git a/cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql b/cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql new file mode 100644 index 0000000000..357513305b --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql @@ -0,0 +1,72 @@ +/** + * @id cpp/misra/pointer-to-integral-cast + * @name RULE-8-2-8: An object pointer type shall not be cast to an integral type other than std::uintptr_t or + * @description Casting object pointers to integral types other than std::uintptr_t or std::intptr_t + * can lead to implementation-defined behavior and potential loss of pointer + * information. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-2-8 + * scope/single-translation-unit + * correctness + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.types.Type + +class InvalidReinterpretCast extends ReinterpretCast { + InvalidReinterpretCast() { + this.getExpr().getType().stripTopLevelSpecifiers() instanceof PointerType and + this.getType().getUnspecifiedType() instanceof IntegralType and + not stripSpecifiers(this.getType()).(UserType).hasGlobalOrStdName(["uintptr_t", "intptr_t"]) + } +} + +from + InvalidReinterpretCast cast, string message, Element optionalTemplateUseSite, + string optionalTemplateUseSiteString +where + not isExcluded(cast, Conversions2Package::pointerToIntegralCastQuery()) and + // Where a result occurs in both the instantiated and uninstantiated template, + // prefer the uninstantiated version. + not exists(InvalidReinterpretCast otherCast | + otherCast.getLocation() = cast.getLocation() and + not otherCast = cast and + otherCast.isFromUninstantiatedTemplate(_) + ) and + if not cast.isFromTemplateInstantiation(_) + then + // Either not in a template, or appears in the uninstantiated template and is + // therefore not argument dependent. + message = + "Cast of object pointer type to integral type '" + cast.getType() + + "' instead of 'std::uintptr_t' or 'std::intptr_t'." and + optionalTemplateUseSite = cast and + optionalTemplateUseSiteString = "" + else + // This is from a template instantiation and is dependent on a template argument, + // so attempt to identify the locations which instantiate the template. + exists(Element instantiation | + cast.isFromTemplateInstantiation(instantiation) and + message = "Cast of object pointer type to integral type inside $@." + | + optionalTemplateUseSite = instantiation.(ClassTemplateInstantiation).getATypeNameUse() and + optionalTemplateUseSiteString = + "instantiation of class " + instantiation.(ClassTemplateInstantiation).getName() + or + optionalTemplateUseSite = + instantiation.(FunctionTemplateInstantiation).getACallToThisFunction() and + optionalTemplateUseSiteString = + "call to instantiated template f of " + + instantiation.(FunctionTemplateInstantiation).getName() + or + optionalTemplateUseSite = instantiation.(VariableTemplateInstantiation).getAnAccess() and + optionalTemplateUseSiteString = + "reference to instantiated template variable " + + instantiation.(VariableTemplateInstantiation).getName() + ) +select cast, message, optionalTemplateUseSite, optionalTemplateUseSiteString diff --git a/cpp/misra/src/rules/RULE-8-20-1/UnsignedOperationWithConstantOperandsWraps.ql b/cpp/misra/src/rules/RULE-8-20-1/UnsignedOperationWithConstantOperandsWraps.ql new file mode 100644 index 0000000000..e62acb8257 --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-20-1/UnsignedOperationWithConstantOperandsWraps.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/unsigned-operation-with-constant-operands-wraps + * @name RULE-8-20-1: An unsigned arithmetic operation with constant operands should not wrap + * @description An unsigned arithmetic operation with constant operands should not wrap. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-20-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.unsignedoperationwithconstantoperandswraps.UnsignedOperationWithConstantOperandsWraps + +class UnsignedOperationWithConstantOperandsWrapsQuery extends UnsignedOperationWithConstantOperandsWrapsSharedQuery +{ + UnsignedOperationWithConstantOperandsWrapsQuery() { + this = ImportMisra23Package::unsignedOperationWithConstantOperandsWrapsQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-8-3-1/BuiltInUnaryOperatorAppliedToUnsignedExpression.ql b/cpp/misra/src/rules/RULE-8-3-1/BuiltInUnaryOperatorAppliedToUnsignedExpression.ql new file mode 100644 index 0000000000..c847348d1c --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-3-1/BuiltInUnaryOperatorAppliedToUnsignedExpression.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/built-in-unary-operator-applied-to-unsigned-expression + * @name RULE-8-3-1: The built-in unary - operator should not be applied to an expression of unsigned type + * @description The built-in unary - operator should not be applied to an expression of unsigned + * type. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-3-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.builtinunaryoperatorappliedtounsignedexpression.BuiltInUnaryOperatorAppliedToUnsignedExpression + +class BuiltInUnaryOperatorAppliedToUnsignedExpressionQuery extends BuiltInUnaryOperatorAppliedToUnsignedExpressionSharedQuery +{ + BuiltInUnaryOperatorAppliedToUnsignedExpressionQuery() { + this = ImportMisra23Package::builtInUnaryOperatorAppliedToUnsignedExpressionQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.ql b/cpp/misra/src/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.ql new file mode 100644 index 0000000000..e3be797b9d --- /dev/null +++ b/cpp/misra/src/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.ql @@ -0,0 +1,37 @@ +/** + * @id cpp/misra/no-standalone-type-cast-expression + * @name RULE-9-2-1: An explicit type conversion shall not be an expression statement + * @description Using an explicit type conversion as an expression statement creates a temporary + * object that is immediately discarded, which can lead to unintended premature + * resource cleanup. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-9-2-1 + * scope/single-translation-unit + * correctness + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +from ExprStmt stmt, Expr expr +where + not isExcluded(stmt, Conversions2Package::noStandaloneTypeCastExpressionQuery()) and + expr = stmt.getExpr() and + ( + // Explicit conversions which call a constructor + expr instanceof ConstructorCall + or + // Cast expressions using functional notation + expr instanceof Cast + ) and + // Exclude init-statements in if/for statements + // This is because the extractor has a bug as of 2.20.7 which means it does not parse + // these two cases separately. We choose to ignore if statements, which can cause false + // negatives, but will prevent false positives + not exists(IfStmt ifStmt | ifStmt.getInitialization() = stmt) +select stmt, + "Explicit type conversion used as expression statement creates temporary object that is immediately discarded." diff --git a/cpp/misra/src/rules/RULE-9-3-1/LoopBodyCompoundCondition.ql b/cpp/misra/src/rules/RULE-9-3-1/LoopBodyCompoundCondition.ql new file mode 100644 index 0000000000..b87009d8c1 --- /dev/null +++ b/cpp/misra/src/rules/RULE-9-3-1/LoopBodyCompoundCondition.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/loop-body-compound-condition + * @name RULE-9-3-1: The statement forming the body of a loop shall be a compound statement + * @description If the body of a loop is not enclosed in braces, then this can lead to incorrect + * execution, and hard for developers to maintain. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-9-3-1 + * maintainability + * readability + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.loopcompoundcondition.LoopCompoundCondition + +class LoopBodyCompoundConditionQuery extends LoopCompoundConditionSharedQuery { + LoopBodyCompoundConditionQuery() { this = ImportMisra23Package::loopBodyCompoundConditionQuery() } +} diff --git a/cpp/misra/src/rules/RULE-9-3-1/SwitchBodyCompoundCondition.ql b/cpp/misra/src/rules/RULE-9-3-1/SwitchBodyCompoundCondition.ql new file mode 100644 index 0000000000..7bee3c027e --- /dev/null +++ b/cpp/misra/src/rules/RULE-9-3-1/SwitchBodyCompoundCondition.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/switch-body-compound-condition + * @name RULE-9-3-1: The statement forming the body of a switch shall be a compound statement + * @description If the body of a switch is not enclosed in braces, then this can lead to incorrect + * execution, and hard for developers to maintain. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-9-3-1 + * maintainability + * readability + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.switchcompoundcondition.SwitchCompoundCondition + +class SwitchBodyCompoundConditionQuery extends SwitchCompoundConditionSharedQuery { + SwitchBodyCompoundConditionQuery() { + this = ImportMisra23Package::switchBodyCompoundConditionQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-9-4-1/IfElseIfEndCondition.ql b/cpp/misra/src/rules/RULE-9-4-1/IfElseIfEndCondition.ql new file mode 100644 index 0000000000..5ce6ab6487 --- /dev/null +++ b/cpp/misra/src/rules/RULE-9-4-1/IfElseIfEndCondition.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/if-else-if-end-condition + * @name RULE-9-4-1: All if ... else if constructs shall be terminated with an else statement + * @description All if ... else if constructs shall be terminated with an else statement. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-9-4-1 + * readability + * maintainability + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.ifelseterminationconstruct.IfElseTerminationConstruct + +class IfElseIfEndConditionQuery extends IfElseTerminationConstructSharedQuery { + IfElseIfEndConditionQuery() { this = ImportMisra23Package::ifElseIfEndConditionQuery() } +} diff --git a/cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql b/cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql new file mode 100644 index 0000000000..893ebfe735 --- /dev/null +++ b/cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql @@ -0,0 +1,92 @@ +/** + * @id cpp/misra/appropriate-structure-of-switch-statement + * @name RULE-9-4-2: The structure of a switch statement shall be appropriate + * @description A switch statement should have an appropriate structure with proper cases, default + * labels, and break statements to ensure clear control flow and prevent unintended + * fall-through behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-9-4-2 + * correctness + * maintainability + * readability + * external/misra/allocated-target/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.SwitchStatement +import codingstandards.cpp.Noreturn + +from SwitchStmt switch, string message +where + not isExcluded(switch, StatementsPackage::appropriateStructureOfSwitchStatementQuery()) and + /* 1. There is a statement that appears as an initializer and is not a declaration statement. */ + exists(Stmt initializer | initializer = switch.getInitialization() | + not initializer instanceof DeclStmt + ) and + message = "contains a statement that is not a simple declaration" + or + /* 2. There is a switch case label that does not lead a branch (i.e. a switch case label is nested). */ + exists(SwitchCase case | case = switch.getASwitchCase() | case instanceof NestedSwitchCase) and + message = "contains a switch label that is not directly within the switch body" + or + /* 3. There is a non-case label in a label group. */ + exists(SwitchCase case | case = switch.getASwitchCase() | + case.getAStmt().getChildStmt*() instanceof LabelStmt + ) and + message = "contains a statement label that is not a case label" + or + /* 4. There is a statement before the first case label. */ + exists(Stmt switchBody | switchBody = switch.getStmt() | + not switchBody.getChild(0) instanceof SwitchCase + ) and + message = "has a statement that is not a case label as its first element" + or + /* 5. There is a switch case whose terminator is not one of the allowed kinds. */ + exists(SwitchCase case, Stmt lastStmt | + case = switch.getASwitchCase() and lastStmt = case.getLastStmt() + | + not ( + lastStmt instanceof BreakStmt or + lastStmt instanceof ReturnStmt or + lastStmt instanceof GotoStmt or + lastStmt instanceof ContinueStmt or + lastStmt.(ExprStmt).getExpr() instanceof ThrowExpr or + lastStmt.(ExprStmt).getExpr().(Call).getTarget() instanceof NoreturnFunction or + lastStmt.getAnAttribute().getName().matches("%fallthrough") // We'd like to consider compiler variants such as `clang::fallthrough`. + ) + ) and + message = "is missing a terminator that moves the control out of its body" + or + /* 6. The switch statement does not have more than two unique branches. */ + count(SwitchCase case | + case = switch.getASwitchCase() and + /* + * If the next switch case is the following statement of this switch case, then the two + * switch cases are consecutive and should be considered as constituting one branch + * together. + */ + + not case.getNextSwitchCase() = case.getFollowingStmt() + | + case + ) < 2 and + message = "contains less than two branches" + or + /* 7-1. The switch statement is not an enum switch statement and is missing a default case. */ + not switch instanceof EnumSwitch and + not switch.hasDefaultCase() and + message = "lacks a default case" + or + /* + * 7-2. The switch statement is an enum switch statement and is missing a branch for a + * variant. + */ + + exists(switch.(EnumSwitch).getAMissingCase()) and + message = "lacks a case for one of its variants" +select switch, "Switch statement " + message + "." diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql new file mode 100644 index 0000000000..9525d1f5f8 --- /dev/null +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -0,0 +1,516 @@ +/** + * @id cpp/misra/legacy-for-statements-should-be-simple + * @name RULE-9-5-1: Legacy for statements should be simple + * @description Legacy for statements with complex initialization, condition, and increment + * expressions can be difficult to understand and maintain. Simple for loops are more + * readable. + * @kind problem + * @precision high + * @problem.severity recommendation + * @tags external/misra/id/rule-9-5-1 + * maintainability + * readability + * external/misra/allocated-target/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import semmle.code.cpp.dataflow.internal.AddressFlow +import codingstandards.cpp.misra +import codingstandards.cpp.Call +import codingstandards.cpp.Loops +import codingstandards.cpp.ast.Increment +import codingstandards.cpp.misra.BuiltInTypeRules::MisraCpp23BuiltInTypes + +Variable getDeclaredVariableInForLoop(ForStmt forLoop) { + result = forLoop.getADeclaration().getADeclarationEntry().(VariableDeclarationEntry).getVariable() +} + +/** + * Holds if the given expression may mutate the variable. + */ +predicate variableModifiedInExpression(Expr expr, VariableAccess va) { + /* + * 1. Direct modification (assignment, increment, etc.) or a function call. + */ + + expr.getAChild+() = va and + va.isModified() + or + /* + * 2. Address taken for non-const access that can potentially lead to modification. + * This overlaps with the former example on cases where `expr` is a function call. + */ + + valueToUpdate(va, _, expr) +} + +/** + * Gets the loop step of a legacy for loop. + * + * This predicate assumes the update expression of the given for loop is an add-and-assign + * (`+=`) or sub-and-assign (`-=`) expression, so the update expression that is an increment + * (`++`) or a decrement (`--`) operation should be handled using different means than this + * predicate. + */ +Expr getLoopStepOfForStmt(ForStmt forLoop) { + /* + * NOTE: We compute the transitive closure of `getAChild` on the update expression, + * since the update expression may be a compound one that embeds the four aforementioned + * expression types, such as a comma expression (e.g. `i += 1, E` where `E` is an + * arbitrary expression). + * + * This may be detrimental to performance, but we keep it for soundness. A possible + * alternative is an IR-based solution. + */ + + /* 1. Get the expression `E` when the update expression is `i += E` or `i -= E`. */ + result = forLoop.getUpdate().getAChild*().(StepCrementUpdateExpr).getAmountExpr() +} + +/** + * Holds if either of the following holds for the given variable access: + * 1. Another variable access of the same variable as the given variable access is taken an + * address and is assigned to a non-const pointer variable, i.e. initialization, assignment, + * and pass-by-value. + * 2. Another variable access of the same variable as the given variable access is assigned + * to a non-const reference variable (thus constituting a `T` -> `&T` conversion.), i.e. + * initialization and assignment. + * + * Note that pass-by-reference is dealt with in a different predicate named + * `loopVariablePassedAsArgumentToNonConstReferenceParameter`, due to implementation + * limitations. + */ +predicate loopVariableAssignedToNonConstPointerOrReferenceType( + ForStmt forLoop, VariableAccess loopVariableAccessInCondition, Expr assignmentRhs +) { + exists(Type targetType, DerivedType strippedType | + isAssignment(assignmentRhs, targetType, _) and + strippedType = targetType.stripTopLevelSpecifiers() and + not strippedType.getBaseType().isConst() and + ( + strippedType instanceof PointerType or + strippedType instanceof ReferenceType + ) + | + assignmentRhs.getEnclosingStmt().getParent*() = forLoop.getStmt() and + ( + /* 1. The address is taken: A loop variable access */ + assignmentRhs.(AddressOfExpr).getOperand() = + loopVariableAccessInCondition.getTarget().getAnAccess() + or + /* 2. A reference is taken: A loop variable access */ + assignmentRhs = loopVariableAccessInCondition.getTarget().getAnAccess() + ) + ) +} + +/** + * Holds if the given variable access has another variable access with the same target + * variable that is passed as reference to a non-const reference parameter of a function, + * constituting a `T` -> `&T` conversion. + * + * This is an adapted part of + * `BuiltinTypeRules::MisraCpp23BuiltInTypes::isPreConversionAssignment` that is only + * relevant to an argument passed to a parameter, seen as an assignment. + * + * This predicate adds two constraints to the target type, as compared to the original + * portion of the predicate: + * + * 1. This predicate adds a type constraint that the target type is a `ReferenceType`. + * 2. This predicate adds the constraint that the target type is not `const`. + * + * Also, this predicate requires that the call is the body of the given for-loop. + */ +predicate loopVariablePassedAsArgumentToNonConstReferenceParameter( + ForStmt forLoop, VariableAccess loopVariableAccessInCondition, Expr loopVariableArgument +) { + exists(Type targetType, ReferenceType strippedReferenceType | + exists(Call call, int i | + loopVariableArgument = call.getArgument(i) and + loopVariableArgument = loopVariableAccessInCondition.getTarget().getAnAccess() and + call.getEnclosingStmt().getParent*() = forLoop.getStmt() and + strippedReferenceType = targetType.stripTopLevelSpecifiers() and + not strippedReferenceType.getBaseType().isConst() + | + /* A regular function call */ + targetType = call.getTarget().getParameter(i).getType() + or + /* A function call where the argument is passed as varargs */ + call.getTarget().getNumberOfParameters() <= i and + /* The rule states that the type should match the "adjusted" type of the argument */ + targetType = loopVariableAccessInCondition.getFullyConverted().getType() + or + /* An expression call - get the function type, then the parameter type */ + targetType = getExprCallFunctionType(call).getParameterType(i) + ) + ) +} + +private newtype TAlertType = + /* 1. There is a counter variable that is not of an integer type. */ + TNonIntegerTypeCounterVariable(ForStmt forLoop, Variable loopCounter) { + loopCounter = getDeclaredVariableInForLoop(forLoop) and + exists(Type type | type = loopCounter.getType() | + not ( + type instanceof IntegralType or + type instanceof FixedWidthIntegralType + ) + ) + } or + /* + * 2. The loop condition checks termination without comparing the counter variable to the + * loop bound using a relational operator. + */ + + TNoRelationalOperatorInLoopCondition(ForStmt forLoop, Expr condition) { + condition = forLoop.getCondition() and + not condition instanceof LegacyForLoopCondition + } or + /* 3-1. The loop counter is mutated somewhere other than its update expression. */ + TLoopCounterMutatedInLoopBody(ForStmt forLoop, Variable loopCounterVariable, Expr mutatingExpr) { + loopCounterVariable = getDeclaredVariableInForLoop(forLoop) and + not mutatingExpr = forLoop.getUpdate().getAChild*() and + variableModifiedInExpression(mutatingExpr, loopCounterVariable.getAnAccess()) + } or + /* 3-2. The loop counter is not updated using either of `++`, `--`, `+=`, or `-=`. */ + TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr( + ForStmt forLoop, Variable loopCounterVariable, Expr updateExpr + ) { + loopCounterVariable = getDeclaredVariableInForLoop(forLoop) and + updateExpr = forLoop.getUpdate() and + variableModifiedInExpression(updateExpr, loopCounterVariable.getAnAccess()) and + not updateExpr instanceof StepCrementUpdateExpr + } or + /* 4. The type size of the loop counter is smaller than that of the loop bound. */ + TLoopCounterSmallerThanLoopBound(ForStmt forLoop, LegacyForLoopCondition forLoopCondition) { + forLoopCondition = forLoop.getCondition() and + exists(Expr loopCounter, Expr loopBound | + loopCounter = forLoopCondition.getLoopCounter() and + loopBound = forLoopCondition.getLoopBound() + | + typeUpperBound(loopCounter.getType()) < upperBound(loopBound.getFullyConverted()) + ) + } or + /* 5-1-1. The loop bound is a variable that is mutated in the for loop. */ + TLoopBoundIsMutatedVariableAccess( + ForStmt forLoop, VariableAccess variableAccess, VariableAccess mutatedVariableAccess + ) { + exists(Expr loopBoundExpr, Expr mutatingExpr | + loopBoundExpr = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() and + ( + /* 1. The mutating expression may be in the loop body. */ + mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() + or + /* 2. The mutating expression may be in the loop updating expression. */ + mutatingExpr = forLoop.getUpdate().getAChild*() + or + /* 3. The mutating expression may be in the loop condition */ + mutatingExpr = forLoop.getCondition().getAChild*() + or + /* 4. The mutating expression may be in the loop initializer */ + mutatingExpr = forLoop.getInitialization().getAChild*() + ) and + variableAccess = loopBoundExpr.getAChild*() and + mutatedVariableAccess = variableAccess.getTarget().getAnAccess() and + variableModifiedInExpression(mutatingExpr, mutatedVariableAccess) + ) + } or + /* 5-1-2. The loop bound is not a variable access nor a constant expression. */ + TLoopBoundIsNonConstExpr(ForStmt forLoop, Expr loopBound) { + loopBound = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() and + (not loopBound instanceof VariableAccess and not loopBound.isConstant()) + } or + /* 5-2-1. The loop step is a variable that is mutated in the for loop. */ + TLoopStepIsMutatedVariableAccess( + ForStmt forLoop, VariableAccess variableAccess, VariableAccess mutatedVariableAccess + ) { + exists(Expr loopStepExpr, Expr mutatingExpr | + loopStepExpr = getLoopStepOfForStmt(forLoop) and + ( + /* 1. The mutating expression may be in the loop body. */ + mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() + or + /* 2. The mutating expression may be in the loop updating expression. */ + mutatingExpr = forLoop.getUpdate().getAChild*() + or + /* 3. The mutating expression may be in the loop condition */ + mutatingExpr = forLoop.getCondition().getAChild*() + or + /* 4. The mutating expression may be in the loop initializer */ + mutatingExpr = forLoop.getInitialization().getAChild*() + ) and + variableAccess = loopStepExpr.getAChild*() and + mutatedVariableAccess = variableAccess.getTarget().getAnAccess() and + variableModifiedInExpression(mutatingExpr, mutatedVariableAccess) + ) + } or + /* 5-2-2. The loop step is not a variable access nor a constant expression. */ + TLoopStepIsNonConstExpr(ForStmt forLoop, Expr loopStep) { + loopStep = getLoopStepOfForStmt(forLoop) and + (not loopStep instanceof VariableAccess and not loopStep.isConstant()) + } or + /* + * 6-1. The loop counter is taken as a mutable reference or its address to a mutable pointer. + */ + + TLoopCounterIsTakenNonConstAddress( + ForStmt forLoop, VariableAccess loopVariableAccessInCondition, + Expr loopVariableAccessInAssignment + ) { + loopVariableAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter() and + ( + loopVariableAssignedToNonConstPointerOrReferenceType(forLoop, loopVariableAccessInCondition, + loopVariableAccessInAssignment) + or + loopVariablePassedAsArgumentToNonConstReferenceParameter(forLoop, + loopVariableAccessInCondition, loopVariableAccessInAssignment) + ) + } or + /* + * 6-2. The loop bound is taken as a mutable reference or its address to a mutable pointer. + */ + + TLoopBoundIsTakenNonConstAddress( + ForStmt forLoop, Expr loopBoundExpr, Expr loopVariableAccessInAssignment + ) { + loopBoundExpr = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() and + exists(VariableAccess variableAccess | + variableAccess = loopBoundExpr.getAChild*() and + ( + loopVariableAssignedToNonConstPointerOrReferenceType(forLoop, variableAccess, + loopVariableAccessInAssignment) + or + loopVariablePassedAsArgumentToNonConstReferenceParameter(forLoop, variableAccess, + loopVariableAccessInAssignment) + ) + ) + } or + /* + * 6-3. The loop step is taken as a mutable reference or its address to a mutable pointer. + */ + + TLoopStepIsTakenNonConstAddress( + ForStmt forLoop, Expr loopVariableAccessInCondition, Expr loopVariableAccessInAssignment + ) { + loopVariableAccessInCondition = getLoopStepOfForStmt(forLoop) and + ( + loopVariableAssignedToNonConstPointerOrReferenceType(forLoop, loopVariableAccessInCondition, + loopVariableAccessInAssignment) + or + loopVariablePassedAsArgumentToNonConstReferenceParameter(forLoop, + loopVariableAccessInCondition, loopVariableAccessInAssignment) + ) + } + +class AlertType extends TAlertType { + /** + * Extract the primary location depending on the case of this instance. + */ + Location getLocation() { result = this.asElement().getLocation() } + + Element asElement() { + this = TNonIntegerTypeCounterVariable(result, _) or + this = TNoRelationalOperatorInLoopCondition(result, _) or + this = TLoopCounterMutatedInLoopBody(result, _, _) or + this = TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(result, _, _) or + this = TLoopCounterSmallerThanLoopBound(result, _) or + this = TLoopBoundIsMutatedVariableAccess(result, _, _) or + this = TLoopBoundIsNonConstExpr(result, _) or + this = TLoopStepIsMutatedVariableAccess(result, _, _) or + this = TLoopStepIsNonConstExpr(result, _) or + this = TLoopCounterIsTakenNonConstAddress(result, _, _) or + this = TLoopBoundIsTakenNonConstAddress(result, _, _) or + this = TLoopStepIsTakenNonConstAddress(result, _, _) + } + + /** + * Gets the target the link leads to depending on the case of this instance. + */ + Locatable getLinkTarget1() { + this = TNonIntegerTypeCounterVariable(_, result) + or + this = TNoRelationalOperatorInLoopCondition(_, result) + or + this = TLoopCounterMutatedInLoopBody(_, result, _) + or + this = TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(_, result, _) + or + exists(LegacyForLoopCondition forLoopCondition | + this = TLoopCounterSmallerThanLoopBound(_, forLoopCondition) and + result = forLoopCondition.getLoopCounter() + ) + or + this = TLoopBoundIsNonConstExpr(_, result) + or + this = TLoopBoundIsMutatedVariableAccess(_, result, _) + or + this = TLoopStepIsNonConstExpr(_, result) + or + this = TLoopStepIsMutatedVariableAccess(_, result, _) + or + this = TLoopCounterIsTakenNonConstAddress(_, result, _) + or + this = TLoopBoundIsTakenNonConstAddress(_, result, _) + or + this = TLoopStepIsTakenNonConstAddress(_, result, _) + } + + /** + * Gets the text of the link depending on the case of this instance. + */ + string getLinkText1() { + this = TNonIntegerTypeCounterVariable(_, _) and + result = "counter variable" + or + this = TNoRelationalOperatorInLoopCondition(_, _) and + result = "loop condition" + or + this = TLoopCounterMutatedInLoopBody(_, _, _) and + result = "counter variable" + or + this = TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(_, _, _) and + result = "counter variable" + or + this = TLoopCounterSmallerThanLoopBound(_, _) and + result = "counter variable" + or + this = TLoopBoundIsMutatedVariableAccess(_, _, _) and + result = "loop bound" + or + this = TLoopBoundIsNonConstExpr(_, _) and + result = "loop bound" + or + this = TLoopStepIsMutatedVariableAccess(_, _, _) and + result = "loop step" + or + this = TLoopStepIsNonConstExpr(_, _) and + result = "loop step" + or + this = TLoopCounterIsTakenNonConstAddress(_, _, _) and + result = "loop counter" + or + this = TLoopBoundIsTakenNonConstAddress(_, _, _) and + result = "loop bound" + or + this = TLoopStepIsTakenNonConstAddress(_, _, _) and + result = "loop step" + } + + /** + * Gets the message with a placeholder, depending on the case of this instance. + */ + string getMessage() { + this = TNonIntegerTypeCounterVariable(_, _) and + result = "The $@ is not of an integer type." + or + this = TNoRelationalOperatorInLoopCondition(_, _) and + result = + "The $@ does not determine termination based only on a comparison against the value of the counter variable." + or + this = TLoopCounterMutatedInLoopBody(_, _, _) and + result = "The $@ may be mutated in $@ other than its update expression." + or + this = TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(_, _, _) and + result = "The $@ is not updated with an $@ other than addition or subtraction." + or + this = TLoopCounterSmallerThanLoopBound(_, _) and + result = "The $@ has a smaller type than that of the $@." + or + this = TLoopBoundIsNonConstExpr(_, _) and + result = "The $@ is a $@." + or + this = TLoopBoundIsMutatedVariableAccess(_, _, _) and + result = "The $@ is a non-const expression, or a variable that may be $@ in the loop." + or + this = TLoopStepIsNonConstExpr(_, _) and + result = "The $@ is a $@." + or + this = TLoopStepIsMutatedVariableAccess(_, _, _) and + result = "The $@ is a non-const expression, or a variable that may be $@ in the loop." + or + this = TLoopCounterIsTakenNonConstAddress(_, _, _) and + result = "The $@ is $@." + or + this = TLoopBoundIsTakenNonConstAddress(_, _, _) and + result = "The $@ is $@." + or + this = TLoopStepIsTakenNonConstAddress(_, _, _) and + result = "The $@ is $@." + } + + Locatable getLinkTarget2() { + this = TNonIntegerTypeCounterVariable(_, result) // Throwaway + or + this = TNoRelationalOperatorInLoopCondition(_, result) // Throwaway + or + this = TLoopCounterMutatedInLoopBody(_, _, result) + or + this = TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(_, _, result) + or + exists(LegacyForLoopCondition forLoopCondition | + this = TLoopCounterSmallerThanLoopBound(_, forLoopCondition) and + result = forLoopCondition.getLoopBound() + ) + or + this = TLoopBoundIsNonConstExpr(_, result) + or + this = TLoopBoundIsMutatedVariableAccess(_, _, result) + or + this = TLoopStepIsNonConstExpr(_, result) + or + this = TLoopStepIsMutatedVariableAccess(_, _, result) + or + this = TLoopCounterIsTakenNonConstAddress(_, _, result) + or + this = TLoopBoundIsTakenNonConstAddress(_, _, result) + or + this = TLoopStepIsTakenNonConstAddress(_, _, result) + } + + string getLinkText2() { + this = TNonIntegerTypeCounterVariable(_, _) and + result = "N/A" // Throwaway + or + this = TNoRelationalOperatorInLoopCondition(_, _) and + result = "N/A" // Throwaway + or + this = TLoopCounterMutatedInLoopBody(_, _, _) and + result = "a location" + or + this = TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(_, _, _) and + result = "expression" + or + this = TLoopCounterSmallerThanLoopBound(_, _) and + result = "loop bound" + or + this = TLoopBoundIsNonConstExpr(_, _) and + result = "non-const expression" + or + this = TLoopBoundIsMutatedVariableAccess(_, _, _) and + result = "mutated" + or + this = TLoopStepIsNonConstExpr(_, _) and + result = "non-const expression" + or + this = TLoopStepIsMutatedVariableAccess(_, _, _) and + result = "mutated" + or + this = TLoopCounterIsTakenNonConstAddress(_, _, _) and + result = "taken as a mutable reference or its address to a mutable pointer" + or + this = TLoopBoundIsTakenNonConstAddress(_, _, _) and + result = "taken as a mutable reference or its address to a mutable pointer" + or + this = TLoopStepIsTakenNonConstAddress(_, _, _) and + result = "taken as a mutable reference or its address to a mutable pointer" + } + + string toString() { result = this.asElement().toString() } +} + +from AlertType alert +where not isExcluded(alert.asElement(), StatementsPackage::legacyForStatementsShouldBeSimpleQuery()) +select alert, alert.getMessage(), alert.getLinkTarget1(), alert.getLinkText1(), + alert.getLinkTarget2(), alert.getLinkText2() diff --git a/cpp/misra/src/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.ql b/cpp/misra/src/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.ql new file mode 100644 index 0000000000..e6b8df9f87 --- /dev/null +++ b/cpp/misra/src/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.ql @@ -0,0 +1,28 @@ +/** + * @id cpp/misra/for-range-initializer-at-most-one-function-call + * @name RULE-9-5-2: A for-range-initializer shall contain at most one function call + * @description Multiple function calls in a for-range-initializer can lead to unclear iteration + * behavior and potential side effects that make the code harder to understand and + * debug. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-9-5-2 + * correctness + * maintainability + * readability + * external/misra/allocated-target/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +from RangeBasedForStmt foreach, Expr initializer +where + not isExcluded(foreach, StatementsPackage::forRangeInitializerAtMostOneFunctionCallQuery()) and + initializer = foreach.getRange() and + count(Call call | call = initializer.getAChild*() | call) >= 2 +select foreach, "Range-based for loop has nested call expression in its $@.", initializer, + "initializer" diff --git a/cpp/misra/src/rules/RULE-9-6-1/GotoStatementShouldNotBeUsed.ql b/cpp/misra/src/rules/RULE-9-6-1/GotoStatementShouldNotBeUsed.ql new file mode 100644 index 0000000000..1751aa3c37 --- /dev/null +++ b/cpp/misra/src/rules/RULE-9-6-1/GotoStatementShouldNotBeUsed.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/goto-statement-should-not-be-used + * @name RULE-9-6-1: The goto statement should not be used + * @description The goto statement should not be used. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-9-6-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.gotostatementshouldnotbeused.GotoStatementShouldNotBeUsed + +class GotoStatementShouldNotBeUsedQuery extends GotoStatementShouldNotBeUsedSharedQuery { + GotoStatementShouldNotBeUsedQuery() { + this = ImportMisra23Package::gotoStatementShouldNotBeUsedQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-9-6-2/GotoReferenceALabelInSurroundingBlock.ql b/cpp/misra/src/rules/RULE-9-6-2/GotoReferenceALabelInSurroundingBlock.ql new file mode 100644 index 0000000000..6e11a73f7f --- /dev/null +++ b/cpp/misra/src/rules/RULE-9-6-2/GotoReferenceALabelInSurroundingBlock.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/goto-reference-a-label-in-surrounding-block + * @name RULE-9-6-2: A goto statement shall reference a label in a surrounding block + * @description A goto statement shall reference a label in a surrounding block. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-9-6-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.gotoreferencealabelinsurroundingblock.GotoReferenceALabelInSurroundingBlock + +class GotoReferenceALabelInSurroundingBlockQuery extends GotoReferenceALabelInSurroundingBlockSharedQuery +{ + GotoReferenceALabelInSurroundingBlockQuery() { + this = ImportMisra23Package::gotoReferenceALabelInSurroundingBlockQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-9-6-3/GotoShallJumpToLabelDeclaredLaterInTheFunction.ql b/cpp/misra/src/rules/RULE-9-6-3/GotoShallJumpToLabelDeclaredLaterInTheFunction.ql new file mode 100644 index 0000000000..5ce80af9e7 --- /dev/null +++ b/cpp/misra/src/rules/RULE-9-6-3/GotoShallJumpToLabelDeclaredLaterInTheFunction.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/goto-shall-jump-to-label-declared-later-in-the-function + * @name RULE-9-6-3: The goto statement shall jump to a label declared later in the function body + * @description Jumping back to an earlier section in the code can lead to accidental iterations. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-9-6-3 + * maintainability + * readability + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.gotostatementcondition.GotoStatementCondition + +class GotoShallJumpToLabelDeclaredLaterInTheFunctionQuery extends GotoStatementConditionSharedQuery { + GotoShallJumpToLabelDeclaredLaterInTheFunctionQuery() { + this = ImportMisra23Package::gotoShallJumpToLabelDeclaredLaterInTheFunctionQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-9-6-4/FunctionDeclaredWithTheNoreturnAttributeReturn.ql b/cpp/misra/src/rules/RULE-9-6-4/FunctionDeclaredWithTheNoreturnAttributeReturn.ql new file mode 100644 index 0000000000..f0ac8dc9bf --- /dev/null +++ b/cpp/misra/src/rules/RULE-9-6-4/FunctionDeclaredWithTheNoreturnAttributeReturn.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/function-declared-with-the-noreturn-attribute-return + * @name RULE-9-6-4: A function declared with the [[noreturn]] attribute shall not return + * @description A function with the [[noreturn]] attribute that returns leads to undefined + * behaviour. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-9-6-4 + * correctness + * scope/system + * external/misra/enforcement/undecidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.functionnoreturnattributecondition.FunctionNoReturnAttributeCondition + +class FunctionDeclaredWithTheNoreturnAttributeReturnQuery extends FunctionNoReturnAttributeConditionSharedQuery +{ + FunctionDeclaredWithTheNoreturnAttributeReturnQuery() { + this = ImportMisra23Package::functionDeclaredWithTheNoreturnAttributeReturnQuery() + } +} diff --git a/cpp/misra/src/rules/RULE-9-6-5/NonVoidFunctionShallReturnAValueOnAllPaths.ql b/cpp/misra/src/rules/RULE-9-6-5/NonVoidFunctionShallReturnAValueOnAllPaths.ql new file mode 100644 index 0000000000..444356350a --- /dev/null +++ b/cpp/misra/src/rules/RULE-9-6-5/NonVoidFunctionShallReturnAValueOnAllPaths.ql @@ -0,0 +1,26 @@ +/** + * @id cpp/misra/non-void-function-shall-return-a-value-on-all-paths + * @name RULE-9-6-5: A function with non-void return type shall return a value on all paths + * @description A function with non-void return type that does not exit via a return statement can + * result in undefined behaviour. An exception to this rule is exiting via exception + * handling. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-9-6-5 + * correctness + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.nonvoidfunctiondoesnotreturn.NonVoidFunctionDoesNotReturn + +class NonVoidFunctionShallReturnAValueOnAllPathsQuery extends NonVoidFunctionDoesNotReturnSharedQuery +{ + NonVoidFunctionShallReturnAValueOnAllPathsQuery() { + this = ImportMisra23Package::nonVoidFunctionShallReturnAValueOnAllPathsQuery() + } +} diff --git a/cpp/misra/test/codeql-pack.lock.yml b/cpp/misra/test/codeql-pack.lock.yml index 514e6963d0..a45ea8f438 100644 --- a/cpp/misra/test/codeql-pack.lock.yml +++ b/cpp/misra/test/codeql-pack.lock.yml @@ -2,13 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.9.3 + version: 4.0.3 codeql/dataflow: - version: 0.0.4 + version: 2.0.3 + codeql/mad: + version: 1.0.19 + codeql/rangeanalysis: + version: 1.0.19 codeql/ssa: - version: 0.1.5 + version: 1.0.19 codeql/tutorial: - version: 0.1.5 + version: 1.0.19 + codeql/typeflow: + version: 1.0.19 + codeql/typetracking: + version: 2.0.3 codeql/util: - version: 0.1.5 + version: 2.0.6 + codeql/xml: + version: 1.0.19 compiled: false diff --git a/cpp/misra/test/options b/cpp/misra/test/options new file mode 100644 index 0000000000..59fc70d386 --- /dev/null +++ b/cpp/misra/test/options @@ -0,0 +1 @@ +semmle-extractor-options:--clang -std=c++17 -nostdinc++ -I../../../../common/test/includes/standard-library -I../../../../common/test/includes/custom-library \ No newline at end of file diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index 0c07a83fe2..7f95987cd1 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.32.0-dev +version: 2.52.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.testref b/cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.testref new file mode 100644 index 0000000000..952d461d00 --- /dev/null +++ b/cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.testref @@ -0,0 +1 @@ +cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.testref b/cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.testref new file mode 100644 index 0000000000..2cd2de067d --- /dev/null +++ b/cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.testref @@ -0,0 +1 @@ +cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/DIR-15-8-1/CopyAndMoveAssignmentsShallHandleSelfAssignment.testref b/cpp/misra/test/rules/DIR-15-8-1/CopyAndMoveAssignmentsShallHandleSelfAssignment.testref new file mode 100644 index 0000000000..65fc614121 --- /dev/null +++ b/cpp/misra/test/rules/DIR-15-8-1/CopyAndMoveAssignmentsShallHandleSelfAssignment.testref @@ -0,0 +1 @@ +cpp/common/test/rules/copyandmoveassignmentsshallhandleselfassignment/CopyAndMoveAssignmentsShallHandleSelfAssignment.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/DIR-5-7-2/SectionsOfCodeShouldNotBeCommentedOut.testref b/cpp/misra/test/rules/DIR-5-7-2/SectionsOfCodeShouldNotBeCommentedOut.testref new file mode 100644 index 0000000000..303a38a19b --- /dev/null +++ b/cpp/misra/test/rules/DIR-5-7-2/SectionsOfCodeShouldNotBeCommentedOut.testref @@ -0,0 +1 @@ +cpp/common/test/rules/sectionsofcodeshallnotbecommentedout/SectionsOfCodeShallNotBeCommentedOut.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-10-0-1/UseSingleGlobalOrMemberDeclarators.testref b/cpp/misra/test/rules/RULE-10-0-1/UseSingleGlobalOrMemberDeclarators.testref new file mode 100644 index 0000000000..434cb47456 --- /dev/null +++ b/cpp/misra/test/rules/RULE-10-0-1/UseSingleGlobalOrMemberDeclarators.testref @@ -0,0 +1 @@ +cpp/common/test/rules/multipleglobalormemberdeclarators/MultipleGlobalOrMemberDeclarators.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-10-0-1/UseSingleLocalDeclarators.testref b/cpp/misra/test/rules/RULE-10-0-1/UseSingleLocalDeclarators.testref new file mode 100644 index 0000000000..be7c9ac352 --- /dev/null +++ b/cpp/misra/test/rules/RULE-10-0-1/UseSingleLocalDeclarators.testref @@ -0,0 +1 @@ +cpp/common/test/rules/multiplelocaldeclarators/MultipleLocalDeclarators.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-10-2-1/EnumerationNotDefinedWithAnExplicitUnderlyingType.testref b/cpp/misra/test/rules/RULE-10-2-1/EnumerationNotDefinedWithAnExplicitUnderlyingType.testref new file mode 100644 index 0000000000..d7a73fd488 --- /dev/null +++ b/cpp/misra/test/rules/RULE-10-2-1/EnumerationNotDefinedWithAnExplicitUnderlyingType.testref @@ -0,0 +1 @@ +cpp/common/test/rules/enumerationnotdefinedwithanexplicitunderlyingtype/EnumerationNotDefinedWithAnExplicitUnderlyingType.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-10-4-1/AsmDeclarationShallNotBeUsed.testref b/cpp/misra/test/rules/RULE-10-4-1/AsmDeclarationShallNotBeUsed.testref new file mode 100644 index 0000000000..f643f6a9c7 --- /dev/null +++ b/cpp/misra/test/rules/RULE-10-4-1/AsmDeclarationShallNotBeUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/asmdeclarationused/AsmDeclarationUsed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-11-3-2/DeclarationOfAnObjectIndirectionsLevel.testref b/cpp/misra/test/rules/RULE-11-3-2/DeclarationOfAnObjectIndirectionsLevel.testref new file mode 100644 index 0000000000..3b46dca736 --- /dev/null +++ b/cpp/misra/test/rules/RULE-11-3-2/DeclarationOfAnObjectIndirectionsLevel.testref @@ -0,0 +1 @@ +cpp/common/test/rules/donotusemorethantwolevelsofpointerindirection/DoNotUseMoreThanTwoLevelsOfPointerIndirection.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-11-6-3/NonUniqueEnumerationConstant.testref b/cpp/misra/test/rules/RULE-11-6-3/NonUniqueEnumerationConstant.testref new file mode 100644 index 0000000000..6606e891ab --- /dev/null +++ b/cpp/misra/test/rules/RULE-11-6-3/NonUniqueEnumerationConstant.testref @@ -0,0 +1 @@ +cpp/common/test/rules/nonuniqueenumerationconstant/NonUniqueEnumerationConstant.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-12-2-2/BitFieldShallHaveAnAppropriateType.testref b/cpp/misra/test/rules/RULE-12-2-2/BitFieldShallHaveAnAppropriateType.testref new file mode 100644 index 0000000000..9e4a9a69c7 --- /dev/null +++ b/cpp/misra/test/rules/RULE-12-2-2/BitFieldShallHaveAnAppropriateType.testref @@ -0,0 +1 @@ +cpp/common/test/rules/bitfieldshallhaveanappropriatetype/BitFieldShallHaveAnAppropriateType.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-12-2-3/SignedIntegerNamedBitFieldHaveALengthOfOneBit.testref b/cpp/misra/test/rules/RULE-12-2-3/SignedIntegerNamedBitFieldHaveALengthOfOneBit.testref new file mode 100644 index 0000000000..5dd7991a37 --- /dev/null +++ b/cpp/misra/test/rules/RULE-12-2-3/SignedIntegerNamedBitFieldHaveALengthOfOneBit.testref @@ -0,0 +1 @@ +cpp/common/test/rules/namedbitfieldswithsignedintegertype/NamedBitFieldsWithSignedIntegerType.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-13-1-2/VirtualAndNonVirtualClassInTheHierarchy.testref b/cpp/misra/test/rules/RULE-13-1-2/VirtualAndNonVirtualClassInTheHierarchy.testref new file mode 100644 index 0000000000..fe57c50fe3 --- /dev/null +++ b/cpp/misra/test/rules/RULE-13-1-2/VirtualAndNonVirtualClassInTheHierarchy.testref @@ -0,0 +1 @@ +cpp/common/test/rules/virtualandnonvirtualclassinthehierarchy/VirtualAndNonVirtualClassInTheHierarchy.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-13-3-2/OverridingShallSpecifyDifferentDefaultArguments.testref b/cpp/misra/test/rules/RULE-13-3-2/OverridingShallSpecifyDifferentDefaultArguments.testref new file mode 100644 index 0000000000..7e06403515 --- /dev/null +++ b/cpp/misra/test/rules/RULE-13-3-2/OverridingShallSpecifyDifferentDefaultArguments.testref @@ -0,0 +1 @@ +cpp/common/test/rules/overridingshallspecifydifferentdefaultarguments/OverridingShallSpecifyDifferentDefaultArguments.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-13-3-4/PotentiallyVirtualPointerOnlyComparesToNullptr.testref b/cpp/misra/test/rules/RULE-13-3-4/PotentiallyVirtualPointerOnlyComparesToNullptr.testref new file mode 100644 index 0000000000..ca8eab9681 --- /dev/null +++ b/cpp/misra/test/rules/RULE-13-3-4/PotentiallyVirtualPointerOnlyComparesToNullptr.testref @@ -0,0 +1 @@ +cpp/common/test/rules/potentiallyvirtualpointeronlycomparestonullptr/PotentiallyVirtualPointerOnlyComparesToNullptr.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-15-1-1/ObjectsDynamicTypeUsedFromConstructorOrDestructor.testref b/cpp/misra/test/rules/RULE-15-1-1/ObjectsDynamicTypeUsedFromConstructorOrDestructor.testref new file mode 100644 index 0000000000..596f74b010 --- /dev/null +++ b/cpp/misra/test/rules/RULE-15-1-1/ObjectsDynamicTypeUsedFromConstructorOrDestructor.testref @@ -0,0 +1 @@ +cpp/common/test/rules/objectsdynamictypeusedfromconstructorordestructor/ObjectsDynamicTypeUsedFromConstructorOrDestructor.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-15-1-2/InitializeAllVirtualBaseClasses.testref b/cpp/misra/test/rules/RULE-15-1-2/InitializeAllVirtualBaseClasses.testref new file mode 100644 index 0000000000..ac8c5e1a83 --- /dev/null +++ b/cpp/misra/test/rules/RULE-15-1-2/InitializeAllVirtualBaseClasses.testref @@ -0,0 +1 @@ +cpp/common/test/rules/initializeallvirtualbaseclasses/InitializeAllVirtualBaseClasses.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-15-1-5/InitializerListConstructorIsTheOnlyConstructor.testref b/cpp/misra/test/rules/RULE-15-1-5/InitializerListConstructorIsTheOnlyConstructor.testref new file mode 100644 index 0000000000..49b73d06a9 --- /dev/null +++ b/cpp/misra/test/rules/RULE-15-1-5/InitializerListConstructorIsTheOnlyConstructor.testref @@ -0,0 +1 @@ +cpp/common/test/rules/initializerlistconstructoristheonlyconstructor/InitializerListConstructorIsTheOnlyConstructor.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-16-5-2/AddressOfOperatorOverloaded.testref b/cpp/misra/test/rules/RULE-16-5-2/AddressOfOperatorOverloaded.testref new file mode 100644 index 0000000000..1f2a126671 --- /dev/null +++ b/cpp/misra/test/rules/RULE-16-5-2/AddressOfOperatorOverloaded.testref @@ -0,0 +1 @@ +cpp/common/test/rules/addressofoperatoroverloaded/AddressOfOperatorOverloaded.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-17-8-1/FunctionTemplatesExplicitlySpecialized.testref b/cpp/misra/test/rules/RULE-17-8-1/FunctionTemplatesExplicitlySpecialized.testref new file mode 100644 index 0000000000..6a284e2cbb --- /dev/null +++ b/cpp/misra/test/rules/RULE-17-8-1/FunctionTemplatesExplicitlySpecialized.testref @@ -0,0 +1 @@ +cpp/common/test/rules/functiontemplatesexplicitlyspecialized/FunctionTemplatesExplicitlySpecialized.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-18-1-1/ExceptionObjectHavePointerType.testref b/cpp/misra/test/rules/RULE-18-1-1/ExceptionObjectHavePointerType.testref new file mode 100644 index 0000000000..24d4229225 --- /dev/null +++ b/cpp/misra/test/rules/RULE-18-1-1/ExceptionObjectHavePointerType.testref @@ -0,0 +1 @@ +cpp/common/test/rules/exceptionobjecthavepointertype/ExceptionObjectHavePointerType.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-18-1-2/EmptyThrowOnlyWithinACatchHandler.testref b/cpp/misra/test/rules/RULE-18-1-2/EmptyThrowOnlyWithinACatchHandler.testref new file mode 100644 index 0000000000..f3c961d8f1 --- /dev/null +++ b/cpp/misra/test/rules/RULE-18-1-2/EmptyThrowOnlyWithinACatchHandler.testref @@ -0,0 +1 @@ +cpp/common/test/rules/emptythrowonlywithinacatchhandler/EmptyThrowOnlyWithinACatchHandler.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-18-3-3/HandlersReferToNonStaticMembersFromTheirClass.testref b/cpp/misra/test/rules/RULE-18-3-3/HandlersReferToNonStaticMembersFromTheirClass.testref new file mode 100644 index 0000000000..7d4f5826b0 --- /dev/null +++ b/cpp/misra/test/rules/RULE-18-3-3/HandlersReferToNonStaticMembersFromTheirClass.testref @@ -0,0 +1 @@ +cpp/common/test/rules/destroyedvaluereferencedindestructorcatchblock/DestroyedValueReferencedInDestructorCatchBlock.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-18-5-1/NoexceptFunctionShouldNotPropagateToTheCaller.testref b/cpp/misra/test/rules/RULE-18-5-1/NoexceptFunctionShouldNotPropagateToTheCaller.testref new file mode 100644 index 0000000000..76dc55827f --- /dev/null +++ b/cpp/misra/test/rules/RULE-18-5-1/NoexceptFunctionShouldNotPropagateToTheCaller.testref @@ -0,0 +1 @@ +cpp/common/test/rules/noexceptfunctionshouldnotpropagatetothecaller/NoexceptFunctionShouldNotPropagateToTheCaller.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected b/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected new file mode 100644 index 0000000000..4f0a79dcb3 --- /dev/null +++ b/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected @@ -0,0 +1,31 @@ +| test.cpp:8:3:8:7 | call to abort | Call to program-terminating function 'abort'. | +| test.cpp:9:3:9:6 | call to exit | Call to program-terminating function 'exit'. | +| test.cpp:10:3:10:7 | call to _Exit | Call to program-terminating function '_Exit'. | +| test.cpp:11:3:11:12 | call to quick_exit | Call to program-terminating function 'quick_exit'. | +| test.cpp:16:3:16:12 | call to abort | Call to program-terminating function 'abort'. | +| test.cpp:17:3:17:11 | call to exit | Call to program-terminating function 'exit'. | +| test.cpp:18:3:18:12 | call to _Exit | Call to program-terminating function '_Exit'. | +| test.cpp:19:3:19:17 | call to quick_exit | Call to program-terminating function 'quick_exit'. | +| test.cpp:20:3:20:16 | call to terminate | Call to program-terminating function 'terminate'. | +| test.cpp:25:14:25:18 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:26:14:26:17 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:27:14:27:18 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:28:14:28:23 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:29:14:29:23 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:30:14:30:22 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:31:14:31:23 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:32:14:32:28 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:33:14:33:27 | terminate | Address taken for program-terminating function 'terminate'. | +| test.cpp:38:18:38:22 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:39:21:39:24 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:40:21:40:25 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:41:21:41:30 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:42:18:42:27 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:43:21:43:29 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:44:21:44:30 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:45:21:45:35 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:46:18:46:31 | terminate | Address taken for program-terminating function 'terminate'. | +| test.cpp:68:1:68:33 | #define CALL_ABORT() std::abort() | Call to program-terminating function 'abort'. | +| test.cpp:69:1:69:33 | #define CALL_EXIT(x) std::exit(x) | Call to program-terminating function 'exit'. | +| test.cpp:70:1:70:41 | #define CALL_TERMINATE() std::terminate() | Call to program-terminating function 'terminate'. | +| test.cpp:77:3:77:17 | call to abort | Call to program-terminating function 'abort'. | diff --git a/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.qlref b/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.qlref new file mode 100644 index 0000000000..afb81410c4 --- /dev/null +++ b/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.qlref @@ -0,0 +1 @@ +rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-18-5-2/test.cpp b/cpp/misra/test/rules/RULE-18-5-2/test.cpp new file mode 100644 index 0000000000..d2e2cca386 --- /dev/null +++ b/cpp/misra/test/rules/RULE-18-5-2/test.cpp @@ -0,0 +1,79 @@ +#include "custom_abort.h" +#include +#include +#include + +void test_direct_calls_to_terminating_functions() { + // Direct calls to program-terminating functions + abort(); // NON_COMPLIANT + exit(0); // NON_COMPLIANT + _Exit(1); // NON_COMPLIANT + quick_exit(2); // NON_COMPLIANT +} + +void test_std_namespace_calls() { + // Calls to functions in std namespace + std::abort(); // NON_COMPLIANT + std::exit(0); // NON_COMPLIANT + std::_Exit(1); // NON_COMPLIANT + std::quick_exit(2); // NON_COMPLIANT + std::terminate(); // NON_COMPLIANT +} + +void test_taking_addresses_of_terminating_functions() { + // Taking addresses of program-terminating functions + auto l1 = &abort; // NON_COMPLIANT + auto l2 = &exit; // NON_COMPLIANT + auto l3 = &_Exit; // NON_COMPLIANT + auto l4 = &quick_exit; // NON_COMPLIANT + auto l5 = &std::abort; // NON_COMPLIANT + auto l6 = &std::exit; // NON_COMPLIANT + auto l7 = &std::_Exit; // NON_COMPLIANT + auto l8 = &std::quick_exit; // NON_COMPLIANT + auto l9 = &std::terminate; // NON_COMPLIANT +} + +void test_function_pointers_to_terminating_functions() { + // Function pointers to program-terminating functions + void (*l1)() = abort; // NON_COMPLIANT + void (*l2)(int) = exit; // NON_COMPLIANT + void (*l3)(int) = _Exit; // NON_COMPLIANT + void (*l4)(int) = quick_exit; // NON_COMPLIANT + void (*l5)() = std::abort; // NON_COMPLIANT + void (*l6)(int) = std::exit; // NON_COMPLIANT + void (*l7)(int) = std::_Exit; // NON_COMPLIANT + void (*l8)(int) = std::quick_exit; // NON_COMPLIANT + void (*l9)() = std::terminate; // NON_COMPLIANT +} + +void test_assert_macro_exception() { + // The call to abort via assert macro is compliant by exception + assert(true); // COMPLIANT + assert(1 == 1); // COMPLIANT +} + +void f1() { + // Valid alternative: normal function return + return; // COMPLIANT +} + +void test_compliant_alternatives() { + // Using normal control flow instead of terminating functions + f1(); // COMPLIANT + + // Using exceptions for error handling + throw std::runtime_error("error"); // COMPLIANT +} + +#define CALL_ABORT() std::abort() // NON_COMPLIANT +#define CALL_EXIT(x) std::exit(x) // NON_COMPLIANT +#define CALL_TERMINATE() std::terminate() // NON_COMPLIANT + +void test_macro_expansion_with_terminating_functions() { + // Macro expansions containing terminating functions + CALL_ABORT(); // reported at the definition site + CALL_EXIT(1); // reported at the definition site + CALL_TERMINATE(); // reported at the definition site + LIBRARY_ABORT(); // NON_COMPLIANT - macro not defined by user, so flagged at + // the call site +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-0-2/FunctionLikeMacrosDefined.testref b/cpp/misra/test/rules/RULE-19-0-2/FunctionLikeMacrosDefined.testref new file mode 100644 index 0000000000..1f07b047a6 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-0-2/FunctionLikeMacrosDefined.testref @@ -0,0 +1 @@ +cpp/common/test/rules/functionlikemacrosdefined/FunctionLikeMacrosDefined.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-0-3/IncludeDirectivesPrecededByPreprocessorDirectives.testref b/cpp/misra/test/rules/RULE-19-0-3/IncludeDirectivesPrecededByPreprocessorDirectives.testref new file mode 100644 index 0000000000..7992898cfc --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-0-3/IncludeDirectivesPrecededByPreprocessorDirectives.testref @@ -0,0 +1 @@ +cpp/common/test/rules/preprocessorincludespreceded/PreprocessorIncludesPreceded.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-1-3/IdentifiersUsedInTheControllingExpressionOf.testref b/cpp/misra/test/rules/RULE-19-1-3/IdentifiersUsedInTheControllingExpressionOf.testref new file mode 100644 index 0000000000..73eb246867 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-1-3/IdentifiersUsedInTheControllingExpressionOf.testref @@ -0,0 +1 @@ +cpp/common/test/rules/undefinedmacroidentifiers/UndefinedMacroIdentifiers.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-2-3/CharsThatShouldNotOccurInHeaderFileName.testref b/cpp/misra/test/rules/RULE-19-2-3/CharsThatShouldNotOccurInHeaderFileName.testref new file mode 100644 index 0000000000..6be2f4f7ba --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-2-3/CharsThatShouldNotOccurInHeaderFileName.testref @@ -0,0 +1 @@ +cpp/common/test/rules/preprocessorincludesforbiddenheadernames/PreprocessorIncludesForbiddenHeaderNames.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-3-1/AndPreprocessorOperatorsShouldNotBeUsed.testref b/cpp/misra/test/rules/RULE-19-3-1/AndPreprocessorOperatorsShouldNotBeUsed.testref new file mode 100644 index 0000000000..eec0b94b11 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-3-1/AndPreprocessorOperatorsShouldNotBeUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/hashoperatorsused/HashOperatorsUsed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-3-2/MacroParameterFollowingHash.testref b/cpp/misra/test/rules/RULE-19-3-2/MacroParameterFollowingHash.testref new file mode 100644 index 0000000000..a5eb010410 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-3-2/MacroParameterFollowingHash.testref @@ -0,0 +1 @@ +cpp/common/test/rules/macroparameterfollowinghash/MacroParameterFollowingHash.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-3-3/AMixedUseMacroArgumentSubjectToExpansion.testref b/cpp/misra/test/rules/RULE-19-3-3/AMixedUseMacroArgumentSubjectToExpansion.testref new file mode 100644 index 0000000000..8061bfd2ec --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-3-3/AMixedUseMacroArgumentSubjectToExpansion.testref @@ -0,0 +1 @@ +cpp/common/test/rules/amixedusemacroargumentsubjecttoexpansion/AMixedUseMacroArgumentSubjectToExpansion.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-3-5/TokensThatLookLikeDirectivesInAMacroArgument.testref b/cpp/misra/test/rules/RULE-19-3-5/TokensThatLookLikeDirectivesInAMacroArgument.testref new file mode 100644 index 0000000000..1e15c636ee --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-3-5/TokensThatLookLikeDirectivesInAMacroArgument.testref @@ -0,0 +1 @@ +cpp/common/test/rules/preprocessingdirectivewithinmacroargument/PreprocessingDirectiveWithinMacroArgument.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected b/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected new file mode 100644 index 0000000000..c57dec9792 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected @@ -0,0 +1,29 @@ +| test.cpp:5:11:5:12 | l1 | Declaration of variable 'l1' of type 'va_list'. | +| test.cpp:9:11:9:12 | l2 | Declaration of variable 'l2' of type 'va_list'. | +| test.cpp:10:3:10:18 | __builtin_va_start | Call to 'va_start'. | +| test.cpp:11:3:11:12 | __builtin_va_end | Call to 'va_end'. | +| test.cpp:15:11:15:12 | l2 | Declaration of variable 'l2' of type 'va_list'. | +| test.cpp:16:3:16:18 | __builtin_va_start | Call to 'va_start'. | +| test.cpp:17:21:17:44 | __builtin_va_arg | Call to 'va_arg'. | +| test.cpp:18:3:18:12 | __builtin_va_end | Call to 'va_end'. | +| test.cpp:22:11:22:12 | l2 | Declaration of variable 'l2' of type 'va_list'. | +| test.cpp:23:3:23:18 | __builtin_va_start | Call to 'va_start'. | +| test.cpp:24:3:24:12 | __builtin_va_end | Call to 'va_end'. | +| test.cpp:28:11:28:12 | l2 | Declaration of variable 'l2' of type 'va_list'. | +| test.cpp:28:15:28:16 | l3 | Declaration of variable 'l3' of type 'va_list'. | +| test.cpp:29:3:29:18 | __builtin_va_start | Call to 'va_start'. | +| test.cpp:30:3:30:17 | __builtin_va_copy | Call to 'va_copy'. | +| test.cpp:31:3:31:12 | __builtin_va_end | Call to 'va_end'. | +| test.cpp:32:3:32:12 | __builtin_va_end | Call to 'va_end'. | +| test.cpp:35:37:35:38 | l1 | Declaration of parameter 'l1' of type 'va_list'. | +| test.cpp:36:15:36:32 | __builtin_va_arg | Call to 'va_arg'. | +| test.cpp:40:11:40:12 | l2 | Declaration of variable 'l2' of type 'va_list'. | +| test.cpp:41:3:41:18 | __builtin_va_start | Call to 'va_start'. | +| test.cpp:42:21:42:44 | __builtin_va_arg | Call to 'va_arg'. | +| test.cpp:43:15:43:32 | __builtin_va_arg | Call to 'va_arg'. | +| test.cpp:44:3:44:12 | __builtin_va_end | Call to 'va_end'. | +| test.cpp:55:17:55:29 | va_list_alias | Declaration of typedef 'va_list_alias' aliasing 'va_list' type. | +| test.cpp:56:17:56:25 | SOME_TYPE | Declaration of typedef 'SOME_TYPE' aliasing 'va_list' type. | +| test.cpp:58:17:58:18 | l1 | Declaration of variable 'l1' of type 'va_list'. | +| test.cpp:59:13:59:14 | l2 | Declaration of variable 'l2' of type 'va_list'. | +| test.cpp:65:12:65:13 | l1 | Declaration of variable 'l1' of type 'va_list'. | diff --git a/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.qlref b/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.qlref new file mode 100644 index 0000000000..7106c2aa2d --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.qlref @@ -0,0 +1 @@ +rules/RULE-21-10-1/NoVariadicFunctionMacros.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-10-1/test.cpp b/cpp/misra/test/rules/RULE-21-10-1/test.cpp new file mode 100644 index 0000000000..14d25c59b7 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-1/test.cpp @@ -0,0 +1,66 @@ +#include +#include + +void test_va_list_declaration() { + va_list l1; // NON_COMPLIANT +} + +void test_va_start_usage(std::int32_t l1, ...) { + va_list l2; // NON_COMPLIANT + va_start(l2, l1); // NON_COMPLIANT + va_end(l2); // NON_COMPLIANT +} + +void test_va_arg_usage(std::int32_t l1, ...) { + va_list l2; // NON_COMPLIANT + va_start(l2, l1); // NON_COMPLIANT + std::int32_t l3 = va_arg(l2, std::int32_t); // NON_COMPLIANT + va_end(l2); // NON_COMPLIANT +} + +void test_va_end_usage(std::int32_t l1, ...) { + va_list l2; // NON_COMPLIANT + va_start(l2, l1); // NON_COMPLIANT + va_end(l2); // NON_COMPLIANT +} + +void test_va_copy_usage(std::int32_t l1, ...) { + va_list l2, l3; // NON_COMPLIANT + va_start(l2, l1); // NON_COMPLIANT + va_copy(l3, l2); // NON_COMPLIANT + va_end(l3); // NON_COMPLIANT + va_end(l2); // NON_COMPLIANT +} + +void test_va_list_parameter(va_list l1) { // NON_COMPLIANT + double l2 = va_arg(l1, double); // NON_COMPLIANT +} + +void test_multiple_va_arg_calls(std::int32_t l1, ...) { + va_list l2; // NON_COMPLIANT + va_start(l2, l1); // NON_COMPLIANT + std::int32_t l3 = va_arg(l2, std::int32_t); // NON_COMPLIANT + double l4 = va_arg(l2, double); // NON_COMPLIANT + va_end(l2); // NON_COMPLIANT +} + +void test_variadic_function_declaration(std::int16_t l1, ...) { + // Function declaration with ellipsis is compliant +} + +void test_variadic_function_call() { + test_variadic_function_declaration(1, 2.0, 3.0); // COMPLIANT +} + +typedef va_list va_list_alias; // NON_COMPLIANT +typedef va_list SOME_TYPE; // NON_COMPLIANT +void test_va_list_alias() { + va_list_alias l1; // NON_COMPLIANT + SOME_TYPE l2; // NON_COMPLIANT +} + +// Note: use of va_list as a return type, or a cast, is not legal + +void test_va_list() { + va_list *l1; // NON_COMPLIANT - pointer to va_list +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.expected b/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.expected new file mode 100644 index 0000000000..4572446b0e --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.expected @@ -0,0 +1,15 @@ +| test.cpp:1:1:1:18 | #include "csetjmp" | Use of banned header "csetjmp". | +| test.cpp:2:1:2:19 | #include "setjmp.h" | Use of banned header "setjmp.h". | +| test.cpp:3:1:3:18 | #include | Use of banned header . | +| test.cpp:4:1:4:19 | #include | Use of banned header . | +| test.cpp:8:9:8:10 | g1 | Declaration of variable 'g1' with banned type 'jmp_buf'. | +| test.cpp:9:14:9:15 | g2 | Declaration of variable 'g2' with banned type 'jmp_buf'. | +| test.cpp:12:11:12:12 | l1 | Declaration of variable 'l1' with banned type 'jmp_buf'. | +| test.cpp:13:7:13:16 | setjmp(env) | Use of banned macro 'setjmp'. | +| test.cpp:14:5:14:11 | call to longjmp | Call to banned function 'longjmp'. | +| test.cpp:19:16:19:17 | l1 | Declaration of variable 'l1' with banned type 'jmp_buf'. | +| test.cpp:20:7:20:16 | setjmp(env) | Use of banned macro 'setjmp'. | +| test.cpp:21:5:21:16 | call to longjmp | Call to banned function 'longjmp'. | +| test.cpp:26:11:26:12 | l1 | Declaration of variable 'l1' with banned type 'jmp_buf'. | +| test.cpp:27:16:27:17 | l2 | Declaration of variable 'l2' with banned type 'jmp_buf'. | +| test.cpp:40:38:40:39 | l1 | Declaration of variable 'l1' with banned type 'jmp_buf'. | diff --git a/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.qlref b/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.qlref new file mode 100644 index 0000000000..8e0712349f --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.qlref @@ -0,0 +1 @@ +rules/RULE-21-10-2/NoCsetjmpHeader.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-10-2/test.cpp b/cpp/misra/test/rules/RULE-21-10-2/test.cpp new file mode 100644 index 0000000000..68b4792da1 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-2/test.cpp @@ -0,0 +1,40 @@ +#include "csetjmp" // NON_COMPLIANT +#include "setjmp.h" // NON_COMPLIANT +#include // NON_COMPLIANT +#include // NON_COMPLIANT +#include + +// Global variables for testing +jmp_buf g1; // NON_COMPLIANT +std::jmp_buf g2; // NON_COMPLIANT + +void test_setjmp_usage() { + jmp_buf l1; // NON_COMPLIANT + if (setjmp(l1) == 0) { // NON_COMPLIANT + longjmp(l1, 1); // NON_COMPLIANT + } +} + +void test_std_setjmp_usage() { + std::jmp_buf l1; // NON_COMPLIANT + if (setjmp(l1) == 0) { // NON_COMPLIANT + std::longjmp(l1, 1); // NON_COMPLIANT + } +} + +void test_jmp_buf_declaration() { + jmp_buf l1; // NON_COMPLIANT + std::jmp_buf l2; // NON_COMPLIANT +} + +void test_compliant_alternative() { + // Using structured exception handling or other alternatives + // instead of setjmp/longjmp + try { + throw std::runtime_error("error"); + } catch (const std::runtime_error &) { // COMPLIANT + // Handle error properly + } +} + +void test_jmp_buf_usage() { jmp_buf *l1; } // NON_COMPLIANT - pointer to jmp_buf \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-10-3/CsignalFacilitiesUsed.testref b/cpp/misra/test/rules/RULE-21-10-3/CsignalFacilitiesUsed.testref new file mode 100644 index 0000000000..2342517408 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-3/CsignalFacilitiesUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/csignalfacilitiesused/CsignalFacilitiesUsed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-10-3/CsignalTypesShallNotBeUsed.testref b/cpp/misra/test/rules/RULE-21-10-3/CsignalTypesShallNotBeUsed.testref new file mode 100644 index 0000000000..3d398d799b --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-3/CsignalTypesShallNotBeUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/csignaltypesused/CsignalTypesUsed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-10-3/CsignalTypesUsed.testref b/cpp/misra/test/rules/RULE-21-10-3/CsignalTypesUsed.testref new file mode 100644 index 0000000000..3d398d799b --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-3/CsignalTypesUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/csignaltypesused/CsignalTypesUsed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-2-1/AtofAtoiAtolAndAtollUsed.testref b/cpp/misra/test/rules/RULE-21-2-1/AtofAtoiAtolAndAtollUsed.testref new file mode 100644 index 0000000000..1b12920284 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-1/AtofAtoiAtolAndAtollUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/atofatoiatolandatollused/AtofAtoiAtolAndAtollUsed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected b/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected new file mode 100644 index 0000000000..fc0efb103b --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected @@ -0,0 +1,222 @@ +| test.cpp:16:3:16:8 | call to strcat | Call to banned string handling function 'strcat'. | +| test.cpp:17:3:17:8 | call to strchr | Call to banned string handling function 'strchr'. | +| test.cpp:18:3:18:8 | call to strcmp | Call to banned string handling function 'strcmp'. | +| test.cpp:19:3:19:9 | call to strcoll | Call to banned string handling function 'strcoll'. | +| test.cpp:20:3:20:8 | call to strcpy | Call to banned string handling function 'strcpy'. | +| test.cpp:21:3:21:9 | call to strcspn | Call to banned string handling function 'strcspn'. | +| test.cpp:22:3:22:10 | call to strerror | Call to banned string handling function 'strerror'. | +| test.cpp:23:3:23:8 | call to strlen | Call to banned string handling function 'strlen'. | +| test.cpp:24:3:24:9 | call to strncat | Call to banned string handling function 'strncat'. | +| test.cpp:25:3:25:9 | call to strncmp | Call to banned string handling function 'strncmp'. | +| test.cpp:26:3:26:9 | call to strncpy | Call to banned string handling function 'strncpy'. | +| test.cpp:27:3:27:9 | call to strpbrk | Call to banned string handling function 'strpbrk'. | +| test.cpp:28:3:28:9 | call to strrchr | Call to banned string handling function 'strrchr'. | +| test.cpp:29:3:29:8 | call to strspn | Call to banned string handling function 'strspn'. | +| test.cpp:30:3:30:8 | call to strstr | Call to banned string handling function 'strstr'. | +| test.cpp:31:3:31:8 | call to strtok | Call to banned string handling function 'strtok'. | +| test.cpp:32:3:32:9 | call to strxfrm | Call to banned string handling function 'strxfrm'. | +| test.cpp:39:3:39:8 | call to strtol | Call to banned string handling function 'strtol'. | +| test.cpp:40:3:40:9 | call to strtoll | Call to banned string handling function 'strtoll'. | +| test.cpp:41:3:41:9 | call to strtoul | Call to banned string handling function 'strtoul'. | +| test.cpp:42:3:42:10 | call to strtoull | Call to banned string handling function 'strtoull'. | +| test.cpp:43:3:43:8 | call to strtod | Call to banned string handling function 'strtod'. | +| test.cpp:44:3:44:8 | call to strtof | Call to banned string handling function 'strtof'. | +| test.cpp:45:3:45:9 | call to strtold | Call to banned string handling function 'strtold'. | +| test.cpp:54:3:54:8 | call to fgetwc | Call to banned string handling function 'fgetwc'. | +| test.cpp:55:3:55:8 | call to fputwc | Call to banned string handling function 'fputwc'. | +| test.cpp:56:3:56:8 | call to wcstol | Call to banned string handling function 'wcstol'. | +| test.cpp:57:3:57:9 | call to wcstoll | Call to banned string handling function 'wcstoll'. | +| test.cpp:58:3:58:9 | call to wcstoul | Call to banned string handling function 'wcstoul'. | +| test.cpp:59:3:59:10 | call to wcstoull | Call to banned string handling function 'wcstoull'. | +| test.cpp:60:3:60:8 | call to wcstod | Call to banned string handling function 'wcstod'. | +| test.cpp:61:3:61:8 | call to wcstof | Call to banned string handling function 'wcstof'. | +| test.cpp:62:3:62:9 | call to wcstold | Call to banned string handling function 'wcstold'. | +| test.cpp:71:3:71:11 | call to strtoumax | Call to banned string handling function 'strtoumax'. | +| test.cpp:72:3:72:11 | call to strtoimax | Call to banned string handling function 'strtoimax'. | +| test.cpp:73:3:73:11 | call to wcstoumax | Call to banned string handling function 'wcstoumax'. | +| test.cpp:74:3:74:11 | call to wcstoimax | Call to banned string handling function 'wcstoimax'. | +| test.cpp:78:40:78:45 | strcat | Address taken for banned string handling function 'strcat'. | +| test.cpp:79:39:79:44 | strcat | Address taken for banned string handling function 'strcat'. | +| test.cpp:80:42:80:48 | strchr | Address taken for banned string handling function 'strchr'. | +| test.cpp:81:42:81:47 | strchr | Address taken for banned string handling function 'strchr'. | +| test.cpp:82:44:82:49 | strcmp | Address taken for banned string handling function 'strcmp'. | +| test.cpp:83:43:83:48 | strcmp | Address taken for banned string handling function 'strcmp'. | +| test.cpp:84:44:84:50 | strcoll | Address taken for banned string handling function 'strcoll'. | +| test.cpp:85:43:85:49 | strcoll | Address taken for banned string handling function 'strcoll'. | +| test.cpp:86:40:86:45 | strcpy | Address taken for banned string handling function 'strcpy'. | +| test.cpp:87:40:87:45 | strcpy | Address taken for banned string handling function 'strcpy'. | +| test.cpp:88:48:88:54 | strcspn | Address taken for banned string handling function 'strcspn'. | +| test.cpp:89:47:89:53 | strcspn | Address taken for banned string handling function 'strcspn'. | +| test.cpp:90:24:90:31 | strerror | Address taken for banned string handling function 'strerror'. | +| test.cpp:91:23:91:30 | strerror | Address taken for banned string handling function 'strerror'. | +| test.cpp:92:34:92:39 | strlen | Address taken for banned string handling function 'strlen'. | +| test.cpp:93:33:93:38 | strlen | Address taken for banned string handling function 'strlen'. | +| test.cpp:94:49:94:55 | strncat | Address taken for banned string handling function 'strncat'. | +| test.cpp:95:48:95:54 | strncat | Address taken for banned string handling function 'strncat'. | +| test.cpp:96:53:96:59 | strncmp | Address taken for banned string handling function 'strncmp'. | +| test.cpp:97:52:97:58 | strncmp | Address taken for banned string handling function 'strncmp'. | +| test.cpp:98:49:98:55 | strncpy | Address taken for banned string handling function 'strncpy'. | +| test.cpp:99:48:99:54 | strncpy | Address taken for banned string handling function 'strncpy'. | +| test.cpp:100:52:100:59 | strpbrk | Address taken for banned string handling function 'strpbrk'. | +| test.cpp:101:52:101:58 | strpbrk | Address taken for banned string handling function 'strpbrk'. | +| test.cpp:102:43:102:50 | strrchr | Address taken for banned string handling function 'strrchr'. | +| test.cpp:103:43:103:49 | strrchr | Address taken for banned string handling function 'strrchr'. | +| test.cpp:104:48:104:53 | strspn | Address taken for banned string handling function 'strspn'. | +| test.cpp:105:47:105:52 | strspn | Address taken for banned string handling function 'strspn'. | +| test.cpp:106:52:106:58 | strstr | Address taken for banned string handling function 'strstr'. | +| test.cpp:107:52:107:57 | strstr | Address taken for banned string handling function 'strstr'. | +| test.cpp:108:41:108:46 | strtok | Address taken for banned string handling function 'strtok'. | +| test.cpp:109:40:109:45 | strtok | Address taken for banned string handling function 'strtok'. | +| test.cpp:110:50:110:56 | strxfrm | Address taken for banned string handling function 'strxfrm'. | +| test.cpp:111:49:111:55 | strxfrm | Address taken for banned string handling function 'strxfrm'. | +| test.cpp:115:45:115:50 | strtol | Address taken for banned string handling function 'strtol'. | +| test.cpp:116:44:116:49 | strtol | Address taken for banned string handling function 'strtol'. | +| test.cpp:117:50:117:56 | strtoll | Address taken for banned string handling function 'strtoll'. | +| test.cpp:118:49:118:55 | strtoll | Address taken for banned string handling function 'strtoll'. | +| test.cpp:119:54:119:60 | strtoul | Address taken for banned string handling function 'strtoul'. | +| test.cpp:120:53:120:59 | strtoul | Address taken for banned string handling function 'strtoul'. | +| test.cpp:122:8:122:15 | strtoull | Address taken for banned string handling function 'strtoull'. | +| test.cpp:124:7:124:14 | strtoull | Address taken for banned string handling function 'strtoull'. | +| test.cpp:125:42:125:47 | strtod | Address taken for banned string handling function 'strtod'. | +| test.cpp:126:42:126:47 | strtod | Address taken for banned string handling function 'strtod'. | +| test.cpp:127:42:127:47 | strtof | Address taken for banned string handling function 'strtof'. | +| test.cpp:128:41:128:46 | strtof | Address taken for banned string handling function 'strtof'. | +| test.cpp:129:48:129:54 | strtold | Address taken for banned string handling function 'strtold'. | +| test.cpp:130:47:130:53 | strtold | Address taken for banned string handling function 'strtold'. | +| test.cpp:134:27:134:32 | fgetwc | Address taken for banned string handling function 'fgetwc'. | +| test.cpp:135:26:135:31 | fgetwc | Address taken for banned string handling function 'fgetwc'. | +| test.cpp:136:36:136:41 | fputwc | Address taken for banned string handling function 'fputwc'. | +| test.cpp:137:35:137:40 | fputwc | Address taken for banned string handling function 'fputwc'. | +| test.cpp:138:51:138:56 | wcstol | Address taken for banned string handling function 'wcstol'. | +| test.cpp:139:50:139:55 | wcstol | Address taken for banned string handling function 'wcstol'. | +| test.cpp:140:56:140:62 | wcstoll | Address taken for banned string handling function 'wcstoll'. | +| test.cpp:141:55:141:61 | wcstoll | Address taken for banned string handling function 'wcstoll'. | +| test.cpp:143:8:143:14 | wcstoul | Address taken for banned string handling function 'wcstoul'. | +| test.cpp:145:7:145:13 | wcstoul | Address taken for banned string handling function 'wcstoul'. | +| test.cpp:147:8:147:15 | wcstoull | Address taken for banned string handling function 'wcstoull'. | +| test.cpp:149:7:149:14 | wcstoull | Address taken for banned string handling function 'wcstoull'. | +| test.cpp:150:49:150:54 | wcstod | Address taken for banned string handling function 'wcstod'. | +| test.cpp:151:48:151:53 | wcstod | Address taken for banned string handling function 'wcstod'. | +| test.cpp:152:48:152:53 | wcstof | Address taken for banned string handling function 'wcstof'. | +| test.cpp:153:47:153:52 | wcstof | Address taken for banned string handling function 'wcstof'. | +| test.cpp:154:54:154:60 | wcstold | Address taken for banned string handling function 'wcstold'. | +| test.cpp:155:53:155:59 | wcstold | Address taken for banned string handling function 'wcstold'. | +| test.cpp:159:50:159:58 | strtoumax | Address taken for banned string handling function 'strtoumax'. | +| test.cpp:160:49:160:57 | strtoumax | Address taken for banned string handling function 'strtoumax'. | +| test.cpp:161:49:161:57 | strtoimax | Address taken for banned string handling function 'strtoimax'. | +| test.cpp:162:48:162:56 | strtoimax | Address taken for banned string handling function 'strtoimax'. | +| test.cpp:164:8:164:16 | wcstoumax | Address taken for banned string handling function 'wcstoumax'. | +| test.cpp:166:7:166:15 | wcstoumax | Address taken for banned string handling function 'wcstoumax'. | +| test.cpp:168:8:168:16 | wcstoimax | Address taken for banned string handling function 'wcstoimax'. | +| test.cpp:169:54:169:62 | wcstoimax | Address taken for banned string handling function 'wcstoimax'. | +| test.cpp:177:3:177:13 | call to strcat | Call to banned string handling function 'strcat'. | +| test.cpp:178:3:178:13 | call to strchr | Call to banned string handling function 'strchr'. | +| test.cpp:179:3:179:13 | call to strcmp | Call to banned string handling function 'strcmp'. | +| test.cpp:180:3:180:14 | call to strcoll | Call to banned string handling function 'strcoll'. | +| test.cpp:181:3:181:13 | call to strcpy | Call to banned string handling function 'strcpy'. | +| test.cpp:182:3:182:14 | call to strcspn | Call to banned string handling function 'strcspn'. | +| test.cpp:183:3:183:15 | call to strerror | Call to banned string handling function 'strerror'. | +| test.cpp:184:3:184:13 | call to strlen | Call to banned string handling function 'strlen'. | +| test.cpp:185:3:185:14 | call to strncat | Call to banned string handling function 'strncat'. | +| test.cpp:186:3:186:14 | call to strncmp | Call to banned string handling function 'strncmp'. | +| test.cpp:187:3:187:14 | call to strncpy | Call to banned string handling function 'strncpy'. | +| test.cpp:188:3:188:14 | call to strpbrk | Call to banned string handling function 'strpbrk'. | +| test.cpp:189:3:189:14 | call to strrchr | Call to banned string handling function 'strrchr'. | +| test.cpp:190:3:190:13 | call to strspn | Call to banned string handling function 'strspn'. | +| test.cpp:191:3:191:13 | call to strstr | Call to banned string handling function 'strstr'. | +| test.cpp:192:3:192:13 | call to strtok | Call to banned string handling function 'strtok'. | +| test.cpp:193:3:193:14 | call to strxfrm | Call to banned string handling function 'strxfrm'. | +| test.cpp:200:3:200:13 | call to strtol | Call to banned string handling function 'strtol'. | +| test.cpp:201:3:201:14 | call to strtoll | Call to banned string handling function 'strtoll'. | +| test.cpp:202:3:202:14 | call to strtoul | Call to banned string handling function 'strtoul'. | +| test.cpp:203:3:203:15 | call to strtoull | Call to banned string handling function 'strtoull'. | +| test.cpp:204:3:204:13 | call to strtod | Call to banned string handling function 'strtod'. | +| test.cpp:205:3:205:13 | call to strtof | Call to banned string handling function 'strtof'. | +| test.cpp:206:3:206:14 | call to strtold | Call to banned string handling function 'strtold'. | +| test.cpp:215:3:215:13 | call to fgetwc | Call to banned string handling function 'fgetwc'. | +| test.cpp:216:3:216:13 | call to fputwc | Call to banned string handling function 'fputwc'. | +| test.cpp:217:3:217:13 | call to wcstol | Call to banned string handling function 'wcstol'. | +| test.cpp:218:3:218:14 | call to wcstoll | Call to banned string handling function 'wcstoll'. | +| test.cpp:219:3:219:14 | call to wcstoul | Call to banned string handling function 'wcstoul'. | +| test.cpp:220:3:220:15 | call to wcstoull | Call to banned string handling function 'wcstoull'. | +| test.cpp:221:3:221:13 | call to wcstod | Call to banned string handling function 'wcstod'. | +| test.cpp:222:3:222:13 | call to wcstof | Call to banned string handling function 'wcstof'. | +| test.cpp:223:3:223:14 | call to wcstold | Call to banned string handling function 'wcstold'. | +| test.cpp:232:3:232:16 | call to strtoumax | Call to banned string handling function 'strtoumax'. | +| test.cpp:233:3:233:16 | call to strtoimax | Call to banned string handling function 'strtoimax'. | +| test.cpp:234:3:234:16 | call to wcstoumax | Call to banned string handling function 'wcstoumax'. | +| test.cpp:235:3:235:16 | call to wcstoimax | Call to banned string handling function 'wcstoimax'. | +| test.cpp:239:40:239:50 | strcat | Address taken for banned string handling function 'strcat'. | +| test.cpp:240:39:240:49 | strcat | Address taken for banned string handling function 'strcat'. | +| test.cpp:241:42:241:53 | strchr | Address taken for banned string handling function 'strchr'. | +| test.cpp:242:42:242:52 | strchr | Address taken for banned string handling function 'strchr'. | +| test.cpp:243:44:243:54 | strcmp | Address taken for banned string handling function 'strcmp'. | +| test.cpp:244:43:244:53 | strcmp | Address taken for banned string handling function 'strcmp'. | +| test.cpp:245:44:245:55 | strcoll | Address taken for banned string handling function 'strcoll'. | +| test.cpp:246:43:246:54 | strcoll | Address taken for banned string handling function 'strcoll'. | +| test.cpp:247:40:247:50 | strcpy | Address taken for banned string handling function 'strcpy'. | +| test.cpp:248:40:248:50 | strcpy | Address taken for banned string handling function 'strcpy'. | +| test.cpp:249:48:249:59 | strcspn | Address taken for banned string handling function 'strcspn'. | +| test.cpp:250:47:250:58 | strcspn | Address taken for banned string handling function 'strcspn'. | +| test.cpp:251:24:251:36 | strerror | Address taken for banned string handling function 'strerror'. | +| test.cpp:252:23:252:35 | strerror | Address taken for banned string handling function 'strerror'. | +| test.cpp:253:34:253:44 | strlen | Address taken for banned string handling function 'strlen'. | +| test.cpp:254:33:254:43 | strlen | Address taken for banned string handling function 'strlen'. | +| test.cpp:255:49:255:60 | strncat | Address taken for banned string handling function 'strncat'. | +| test.cpp:256:48:256:59 | strncat | Address taken for banned string handling function 'strncat'. | +| test.cpp:258:8:258:19 | strncmp | Address taken for banned string handling function 'strncmp'. | +| test.cpp:260:7:260:18 | strncmp | Address taken for banned string handling function 'strncmp'. | +| test.cpp:261:49:261:60 | strncpy | Address taken for banned string handling function 'strncpy'. | +| test.cpp:262:48:262:59 | strncpy | Address taken for banned string handling function 'strncpy'. | +| test.cpp:264:7:264:19 | strpbrk | Address taken for banned string handling function 'strpbrk'. | +| test.cpp:266:7:266:18 | strpbrk | Address taken for banned string handling function 'strpbrk'. | +| test.cpp:267:43:267:55 | strrchr | Address taken for banned string handling function 'strrchr'. | +| test.cpp:268:43:268:54 | strrchr | Address taken for banned string handling function 'strrchr'. | +| test.cpp:269:48:269:58 | strspn | Address taken for banned string handling function 'strspn'. | +| test.cpp:270:47:270:57 | strspn | Address taken for banned string handling function 'strspn'. | +| test.cpp:272:7:272:18 | strstr | Address taken for banned string handling function 'strstr'. | +| test.cpp:273:52:273:62 | strstr | Address taken for banned string handling function 'strstr'. | +| test.cpp:274:41:274:51 | strtok | Address taken for banned string handling function 'strtok'. | +| test.cpp:275:40:275:50 | strtok | Address taken for banned string handling function 'strtok'. | +| test.cpp:276:50:276:61 | strxfrm | Address taken for banned string handling function 'strxfrm'. | +| test.cpp:277:49:277:60 | strxfrm | Address taken for banned string handling function 'strxfrm'. | +| test.cpp:281:45:281:55 | strtol | Address taken for banned string handling function 'strtol'. | +| test.cpp:282:44:282:54 | strtol | Address taken for banned string handling function 'strtol'. | +| test.cpp:283:50:283:61 | strtoll | Address taken for banned string handling function 'strtoll'. | +| test.cpp:284:49:284:60 | strtoll | Address taken for banned string handling function 'strtoll'. | +| test.cpp:286:8:286:19 | strtoul | Address taken for banned string handling function 'strtoul'. | +| test.cpp:288:7:288:18 | strtoul | Address taken for banned string handling function 'strtoul'. | +| test.cpp:290:8:290:20 | strtoull | Address taken for banned string handling function 'strtoull'. | +| test.cpp:292:7:292:19 | strtoull | Address taken for banned string handling function 'strtoull'. | +| test.cpp:293:42:293:52 | strtod | Address taken for banned string handling function 'strtod'. | +| test.cpp:294:42:294:52 | strtod | Address taken for banned string handling function 'strtod'. | +| test.cpp:295:42:295:52 | strtof | Address taken for banned string handling function 'strtof'. | +| test.cpp:296:41:296:51 | strtof | Address taken for banned string handling function 'strtof'. | +| test.cpp:297:48:297:59 | strtold | Address taken for banned string handling function 'strtold'. | +| test.cpp:298:47:298:58 | strtold | Address taken for banned string handling function 'strtold'. | +| test.cpp:302:27:302:37 | fgetwc | Address taken for banned string handling function 'fgetwc'. | +| test.cpp:303:26:303:36 | fgetwc | Address taken for banned string handling function 'fgetwc'. | +| test.cpp:304:36:304:46 | fputwc | Address taken for banned string handling function 'fputwc'. | +| test.cpp:305:35:305:45 | fputwc | Address taken for banned string handling function 'fputwc'. | +| test.cpp:306:51:306:61 | wcstol | Address taken for banned string handling function 'wcstol'. | +| test.cpp:307:50:307:60 | wcstol | Address taken for banned string handling function 'wcstol'. | +| test.cpp:309:8:309:19 | wcstoll | Address taken for banned string handling function 'wcstoll'. | +| test.cpp:311:7:311:18 | wcstoll | Address taken for banned string handling function 'wcstoll'. | +| test.cpp:313:8:313:19 | wcstoul | Address taken for banned string handling function 'wcstoul'. | +| test.cpp:315:7:315:18 | wcstoul | Address taken for banned string handling function 'wcstoul'. | +| test.cpp:317:8:317:20 | wcstoull | Address taken for banned string handling function 'wcstoull'. | +| test.cpp:319:7:319:19 | wcstoull | Address taken for banned string handling function 'wcstoull'. | +| test.cpp:320:49:320:59 | wcstod | Address taken for banned string handling function 'wcstod'. | +| test.cpp:321:48:321:58 | wcstod | Address taken for banned string handling function 'wcstod'. | +| test.cpp:322:48:322:58 | wcstof | Address taken for banned string handling function 'wcstof'. | +| test.cpp:323:47:323:57 | wcstof | Address taken for banned string handling function 'wcstof'. | +| test.cpp:325:8:325:19 | wcstold | Address taken for banned string handling function 'wcstold'. | +| test.cpp:327:7:327:18 | wcstold | Address taken for banned string handling function 'wcstold'. | +| test.cpp:332:8:332:21 | strtoumax | Address taken for banned string handling function 'strtoumax'. | +| test.cpp:333:49:333:62 | strtoumax | Address taken for banned string handling function 'strtoumax'. | +| test.cpp:334:49:334:62 | strtoimax | Address taken for banned string handling function 'strtoimax'. | +| test.cpp:335:48:335:61 | strtoimax | Address taken for banned string handling function 'strtoimax'. | +| test.cpp:337:8:337:21 | wcstoumax | Address taken for banned string handling function 'wcstoumax'. | +| test.cpp:339:7:339:20 | wcstoumax | Address taken for banned string handling function 'wcstoumax'. | +| test.cpp:341:8:341:21 | wcstoimax | Address taken for banned string handling function 'wcstoimax'. | +| test.cpp:343:7:343:20 | wcstoimax | Address taken for banned string handling function 'wcstoimax'. | diff --git a/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.qlref b/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.qlref new file mode 100644 index 0000000000..1b69df818c --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.qlref @@ -0,0 +1 @@ +rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-2-2/test.cpp b/cpp/misra/test/rules/RULE-21-2-2/test.cpp new file mode 100644 index 0000000000..a61639e6a5 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-2/test.cpp @@ -0,0 +1,367 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void test_cstring_functions() { + char l1[100]; + char l2[100]; + const char *l3 = "test"; + + strcat(l1, l2); // NON_COMPLIANT + strchr(l3, 'e'); // NON_COMPLIANT + strcmp(l1, l2); // NON_COMPLIANT + strcoll(l1, l2); // NON_COMPLIANT + strcpy(l1, l3); // NON_COMPLIANT + strcspn(l1, l2); // NON_COMPLIANT + strerror(0); // NON_COMPLIANT + strlen(l3); // NON_COMPLIANT + strncat(l1, l2, 10); // NON_COMPLIANT + strncmp(l1, l2, 10); // NON_COMPLIANT + strncpy(l1, l3, 10); // NON_COMPLIANT + strpbrk(l1, l2); // NON_COMPLIANT + strrchr(l3, 'e'); // NON_COMPLIANT + strspn(l1, l2); // NON_COMPLIANT + strstr(l1, l3); // NON_COMPLIANT + strtok(l1, l2); // NON_COMPLIANT + strxfrm(l1, l2, 50); // NON_COMPLIANT +} + +void test_cstdlib_string_functions() { + const char *l1 = "123"; + char *l2; + + strtol(l1, &l2, 10); // NON_COMPLIANT + strtoll(l1, &l2, 10); // NON_COMPLIANT + strtoul(l1, &l2, 10); // NON_COMPLIANT + strtoull(l1, &l2, 10); // NON_COMPLIANT + strtod(l1, &l2); // NON_COMPLIANT + strtof(l1, &l2); // NON_COMPLIANT + strtold(l1, &l2); // NON_COMPLIANT +} + +void test_cwchar_functions() { + wchar_t l1[100]; + const wchar_t *l2 = L"123"; + wchar_t *l3; + FILE *l4 = nullptr; + + fgetwc(l4); // NON_COMPLIANT + fputwc(L'a', l4); // NON_COMPLIANT + wcstol(l2, &l3, 10); // NON_COMPLIANT + wcstoll(l2, &l3, 10); // NON_COMPLIANT + wcstoul(l2, &l3, 10); // NON_COMPLIANT + wcstoull(l2, &l3, 10); // NON_COMPLIANT + wcstod(l2, &l3); // NON_COMPLIANT + wcstof(l2, &l3); // NON_COMPLIANT + wcstold(l2, &l3); // NON_COMPLIANT +} + +void test_cinttypes_functions() { + const char *l1 = "123"; + char *l2; + const wchar_t *l3 = L"123"; + wchar_t *l4; + + strtoumax(l1, &l2, 10); // NON_COMPLIANT + strtoimax(l1, &l2, 10); // NON_COMPLIANT + wcstoumax(l3, &l4, 10); // NON_COMPLIANT + wcstoimax(l3, &l4, 10); // NON_COMPLIANT +} + +void test_cstring_function_pointer_addresses() { + char *(*l1)(char *, const char *) = &strcat; // NON_COMPLIANT + char *(*l2)(char *, const char *) = strcat; // NON_COMPLIANT + const char *(*l3)(const char *, int) = &strchr; // NON_COMPLIANT + const char *(*l4)(const char *, int) = strchr; // NON_COMPLIANT + int (*l5)(const char *, const char *) = &strcmp; // NON_COMPLIANT + int (*l6)(const char *, const char *) = strcmp; // NON_COMPLIANT + int (*l7)(const char *, const char *) = &strcoll; // NON_COMPLIANT + int (*l8)(const char *, const char *) = strcoll; // NON_COMPLIANT + char *(*l9)(char *, const char *) = &strcpy; // NON_COMPLIANT + char *(*l10)(char *, const char *) = strcpy; // NON_COMPLIANT + size_t (*l11)(const char *, const char *) = &strcspn; // NON_COMPLIANT + size_t (*l12)(const char *, const char *) = strcspn; // NON_COMPLIANT + char *(*l13)(int) = &strerror; // NON_COMPLIANT + char *(*l14)(int) = strerror; // NON_COMPLIANT + size_t (*l15)(const char *) = &strlen; // NON_COMPLIANT + size_t (*l16)(const char *) = strlen; // NON_COMPLIANT + char *(*l17)(char *, const char *, size_t) = &strncat; // NON_COMPLIANT + char *(*l18)(char *, const char *, size_t) = strncat; // NON_COMPLIANT + int (*l19)(const char *, const char *, size_t) = &strncmp; // NON_COMPLIANT + int (*l20)(const char *, const char *, size_t) = strncmp; // NON_COMPLIANT + char *(*l21)(char *, const char *, size_t) = &strncpy; // NON_COMPLIANT + char *(*l22)(char *, const char *, size_t) = strncpy; // NON_COMPLIANT + const char *(*l23)(const char *, const char *) = &strpbrk; // NON_COMPLIANT + const char *(*l24)(const char *, const char *) = strpbrk; // NON_COMPLIANT + const char *(*l25)(const char *, int) = &strrchr; // NON_COMPLIANT + const char *(*l26)(const char *, int) = strrchr; // NON_COMPLIANT + size_t (*l27)(const char *, const char *) = &strspn; // NON_COMPLIANT + size_t (*l28)(const char *, const char *) = strspn; // NON_COMPLIANT + const char *(*l29)(const char *, const char *) = &strstr; // NON_COMPLIANT + const char *(*l30)(const char *, const char *) = strstr; // NON_COMPLIANT + char *(*l31)(char *, const char *) = &strtok; // NON_COMPLIANT + char *(*l32)(char *, const char *) = strtok; // NON_COMPLIANT + size_t (*l33)(char *, const char *, size_t) = &strxfrm; // NON_COMPLIANT + size_t (*l34)(char *, const char *, size_t) = strxfrm; // NON_COMPLIANT +} + +void test_cstdlib_function_pointer_addresses() { + long (*l1)(const char *, char **, int) = &strtol; // NON_COMPLIANT + long (*l2)(const char *, char **, int) = strtol; // NON_COMPLIANT + long long (*l3)(const char *, char **, int) = &strtoll; // NON_COMPLIANT + long long (*l4)(const char *, char **, int) = strtoll; // NON_COMPLIANT + unsigned long (*l5)(const char *, char **, int) = &strtoul; // NON_COMPLIANT + unsigned long (*l6)(const char *, char **, int) = strtoul; // NON_COMPLIANT + unsigned long long (*l7)(const char *, char **, int) = + &strtoull; // NON_COMPLIANT + unsigned long long (*l8)(const char *, char **, int) = + strtoull; // NON_COMPLIANT + double (*l9)(const char *, char **) = &strtod; // NON_COMPLIANT + double (*l10)(const char *, char **) = strtod; // NON_COMPLIANT + float (*l11)(const char *, char **) = &strtof; // NON_COMPLIANT + float (*l12)(const char *, char **) = strtof; // NON_COMPLIANT + long double (*l13)(const char *, char **) = &strtold; // NON_COMPLIANT + long double (*l14)(const char *, char **) = strtold; // NON_COMPLIANT +} + +void test_cwchar_function_pointer_addresses() { + wint_t (*l1)(FILE *) = &fgetwc; // NON_COMPLIANT + wint_t (*l2)(FILE *) = fgetwc; // NON_COMPLIANT + wint_t (*l3)(wchar_t, FILE *) = &fputwc; // NON_COMPLIANT + wint_t (*l4)(wchar_t, FILE *) = fputwc; // NON_COMPLIANT + long (*l5)(const wchar_t *, wchar_t **, int) = &wcstol; // NON_COMPLIANT + long (*l6)(const wchar_t *, wchar_t **, int) = wcstol; // NON_COMPLIANT + long long (*l7)(const wchar_t *, wchar_t **, int) = &wcstoll; // NON_COMPLIANT + long long (*l8)(const wchar_t *, wchar_t **, int) = wcstoll; // NON_COMPLIANT + unsigned long (*l9)(const wchar_t *, wchar_t **, int) = + &wcstoul; // NON_COMPLIANT + unsigned long (*l10)(const wchar_t *, wchar_t **, int) = + wcstoul; // NON_COMPLIANT + unsigned long long (*l11)(const wchar_t *, wchar_t **, int) = + &wcstoull; // NON_COMPLIANT + unsigned long long (*l12)(const wchar_t *, wchar_t **, int) = + wcstoull; // NON_COMPLIANT + double (*l13)(const wchar_t *, wchar_t **) = &wcstod; // NON_COMPLIANT + double (*l14)(const wchar_t *, wchar_t **) = wcstod; // NON_COMPLIANT + float (*l15)(const wchar_t *, wchar_t **) = &wcstof; // NON_COMPLIANT + float (*l16)(const wchar_t *, wchar_t **) = wcstof; // NON_COMPLIANT + long double (*l17)(const wchar_t *, wchar_t **) = &wcstold; // NON_COMPLIANT + long double (*l18)(const wchar_t *, wchar_t **) = wcstold; // NON_COMPLIANT +} + +void test_cinttypes_function_pointer_addresses() { + uintmax_t (*l1)(const char *, char **, int) = &strtoumax; // NON_COMPLIANT + uintmax_t (*l2)(const char *, char **, int) = strtoumax; // NON_COMPLIANT + intmax_t (*l3)(const char *, char **, int) = &strtoimax; // NON_COMPLIANT + intmax_t (*l4)(const char *, char **, int) = strtoimax; // NON_COMPLIANT + uintmax_t (*l5)(const wchar_t *, wchar_t **, int) = + &wcstoumax; // NON_COMPLIANT + uintmax_t (*l6)(const wchar_t *, wchar_t **, int) = + wcstoumax; // NON_COMPLIANT + intmax_t (*l7)(const wchar_t *, wchar_t **, int) = + &wcstoimax; // NON_COMPLIANT + intmax_t (*l8)(const wchar_t *, wchar_t **, int) = wcstoimax; // NON_COMPLIANT +} + +void test_std_cstring_functions() { + char l1[100]; + char l2[100]; + const char *l3 = "test"; + + std::strcat(l1, l2); // NON_COMPLIANT + std::strchr(l3, 'e'); // NON_COMPLIANT + std::strcmp(l1, l2); // NON_COMPLIANT + std::strcoll(l1, l2); // NON_COMPLIANT + std::strcpy(l1, l3); // NON_COMPLIANT + std::strcspn(l1, l2); // NON_COMPLIANT + std::strerror(0); // NON_COMPLIANT + std::strlen(l3); // NON_COMPLIANT + std::strncat(l1, l2, 10); // NON_COMPLIANT + std::strncmp(l1, l2, 10); // NON_COMPLIANT + std::strncpy(l1, l3, 10); // NON_COMPLIANT + std::strpbrk(l1, l2); // NON_COMPLIANT + std::strrchr(l3, 'e'); // NON_COMPLIANT + std::strspn(l1, l2); // NON_COMPLIANT + std::strstr(l1, l3); // NON_COMPLIANT + std::strtok(l1, l2); // NON_COMPLIANT + std::strxfrm(l1, l2, 50); // NON_COMPLIANT +} + +void test_std_cstdlib_string_functions() { + const char *l1 = "123"; + char *l2; + + std::strtol(l1, &l2, 10); // NON_COMPLIANT + std::strtoll(l1, &l2, 10); // NON_COMPLIANT + std::strtoul(l1, &l2, 10); // NON_COMPLIANT + std::strtoull(l1, &l2, 10); // NON_COMPLIANT + std::strtod(l1, &l2); // NON_COMPLIANT + std::strtof(l1, &l2); // NON_COMPLIANT + std::strtold(l1, &l2); // NON_COMPLIANT +} + +void test_std_cwchar_functions() { + wchar_t l1[100]; + const wchar_t *l2 = L"123"; + wchar_t *l3; + FILE *l4 = nullptr; + + std::fgetwc(l4); // NON_COMPLIANT + std::fputwc(L'a', l4); // NON_COMPLIANT + std::wcstol(l2, &l3, 10); // NON_COMPLIANT + std::wcstoll(l2, &l3, 10); // NON_COMPLIANT + std::wcstoul(l2, &l3, 10); // NON_COMPLIANT + std::wcstoull(l2, &l3, 10); // NON_COMPLIANT + std::wcstod(l2, &l3); // NON_COMPLIANT + std::wcstof(l2, &l3); // NON_COMPLIANT + std::wcstold(l2, &l3); // NON_COMPLIANT +} + +void test_std_cinttypes_functions() { + const char *l1 = "123"; + char *l2; + const wchar_t *l3 = L"123"; + wchar_t *l4; + + std::strtoumax(l1, &l2, 10); // NON_COMPLIANT + std::strtoimax(l1, &l2, 10); // NON_COMPLIANT + std::wcstoumax(l3, &l4, 10); // NON_COMPLIANT + std::wcstoimax(l3, &l4, 10); // NON_COMPLIANT +} + +void test_std_cstring_function_pointer_addresses() { + char *(*l1)(char *, const char *) = &std::strcat; // NON_COMPLIANT + char *(*l2)(char *, const char *) = std::strcat; // NON_COMPLIANT + const char *(*l3)(const char *, int) = &std::strchr; // NON_COMPLIANT + const char *(*l4)(const char *, int) = std::strchr; // NON_COMPLIANT + int (*l5)(const char *, const char *) = &std::strcmp; // NON_COMPLIANT + int (*l6)(const char *, const char *) = std::strcmp; // NON_COMPLIANT + int (*l7)(const char *, const char *) = &std::strcoll; // NON_COMPLIANT + int (*l8)(const char *, const char *) = std::strcoll; // NON_COMPLIANT + char *(*l9)(char *, const char *) = &std::strcpy; // NON_COMPLIANT + char *(*l10)(char *, const char *) = std::strcpy; // NON_COMPLIANT + size_t (*l11)(const char *, const char *) = &std::strcspn; // NON_COMPLIANT + size_t (*l12)(const char *, const char *) = std::strcspn; // NON_COMPLIANT + char *(*l13)(int) = &std::strerror; // NON_COMPLIANT + char *(*l14)(int) = std::strerror; // NON_COMPLIANT + size_t (*l15)(const char *) = &std::strlen; // NON_COMPLIANT + size_t (*l16)(const char *) = std::strlen; // NON_COMPLIANT + char *(*l17)(char *, const char *, size_t) = &std::strncat; // NON_COMPLIANT + char *(*l18)(char *, const char *, size_t) = std::strncat; // NON_COMPLIANT + int (*l19)(const char *, const char *, size_t) = + &std::strncmp; // NON_COMPLIANT + int (*l20)(const char *, const char *, size_t) = + std::strncmp; // NON_COMPLIANT + char *(*l21)(char *, const char *, size_t) = &std::strncpy; // NON_COMPLIANT + char *(*l22)(char *, const char *, size_t) = std::strncpy; // NON_COMPLIANT + const char *(*l23)(const char *, const char *) = + &std::strpbrk; // NON_COMPLIANT + const char *(*l24)(const char *, const char *) = + std::strpbrk; // NON_COMPLIANT + const char *(*l25)(const char *, int) = &std::strrchr; // NON_COMPLIANT + const char *(*l26)(const char *, int) = std::strrchr; // NON_COMPLIANT + size_t (*l27)(const char *, const char *) = &std::strspn; // NON_COMPLIANT + size_t (*l28)(const char *, const char *) = std::strspn; // NON_COMPLIANT + const char *(*l29)(const char *, const char *) = + &std::strstr; // NON_COMPLIANT + const char *(*l30)(const char *, const char *) = std::strstr; // NON_COMPLIANT + char *(*l31)(char *, const char *) = &std::strtok; // NON_COMPLIANT + char *(*l32)(char *, const char *) = std::strtok; // NON_COMPLIANT + size_t (*l33)(char *, const char *, size_t) = &std::strxfrm; // NON_COMPLIANT + size_t (*l34)(char *, const char *, size_t) = std::strxfrm; // NON_COMPLIANT +} + +void test_std_cstdlib_function_pointer_addresses() { + long (*l1)(const char *, char **, int) = &std::strtol; // NON_COMPLIANT + long (*l2)(const char *, char **, int) = std::strtol; // NON_COMPLIANT + long long (*l3)(const char *, char **, int) = &std::strtoll; // NON_COMPLIANT + long long (*l4)(const char *, char **, int) = std::strtoll; // NON_COMPLIANT + unsigned long (*l5)(const char *, char **, int) = + &std::strtoul; // NON_COMPLIANT + unsigned long (*l6)(const char *, char **, int) = + std::strtoul; // NON_COMPLIANT + unsigned long long (*l7)(const char *, char **, int) = + &std::strtoull; // NON_COMPLIANT + unsigned long long (*l8)(const char *, char **, int) = + std::strtoull; // NON_COMPLIANT + double (*l9)(const char *, char **) = &std::strtod; // NON_COMPLIANT + double (*l10)(const char *, char **) = std::strtod; // NON_COMPLIANT + float (*l11)(const char *, char **) = &std::strtof; // NON_COMPLIANT + float (*l12)(const char *, char **) = std::strtof; // NON_COMPLIANT + long double (*l13)(const char *, char **) = &std::strtold; // NON_COMPLIANT + long double (*l14)(const char *, char **) = std::strtold; // NON_COMPLIANT +} + +void test_std_cwchar_function_pointer_addresses() { + wint_t (*l1)(FILE *) = &std::fgetwc; // NON_COMPLIANT + wint_t (*l2)(FILE *) = std::fgetwc; // NON_COMPLIANT + wint_t (*l3)(wchar_t, FILE *) = &std::fputwc; // NON_COMPLIANT + wint_t (*l4)(wchar_t, FILE *) = std::fputwc; // NON_COMPLIANT + long (*l5)(const wchar_t *, wchar_t **, int) = &std::wcstol; // NON_COMPLIANT + long (*l6)(const wchar_t *, wchar_t **, int) = std::wcstol; // NON_COMPLIANT + long long (*l7)(const wchar_t *, wchar_t **, int) = + &std::wcstoll; // NON_COMPLIANT + long long (*l8)(const wchar_t *, wchar_t **, int) = + std::wcstoll; // NON_COMPLIANT + unsigned long (*l9)(const wchar_t *, wchar_t **, int) = + &std::wcstoul; // NON_COMPLIANT + unsigned long (*l10)(const wchar_t *, wchar_t **, int) = + std::wcstoul; // NON_COMPLIANT + unsigned long long (*l11)(const wchar_t *, wchar_t **, int) = + &std::wcstoull; // NON_COMPLIANT + unsigned long long (*l12)(const wchar_t *, wchar_t **, int) = + std::wcstoull; // NON_COMPLIANT + double (*l13)(const wchar_t *, wchar_t **) = &std::wcstod; // NON_COMPLIANT + double (*l14)(const wchar_t *, wchar_t **) = std::wcstod; // NON_COMPLIANT + float (*l15)(const wchar_t *, wchar_t **) = &std::wcstof; // NON_COMPLIANT + float (*l16)(const wchar_t *, wchar_t **) = std::wcstof; // NON_COMPLIANT + long double (*l17)(const wchar_t *, wchar_t **) = + &std::wcstold; // NON_COMPLIANT + long double (*l18)(const wchar_t *, wchar_t **) = + std::wcstold; // NON_COMPLIANT +} + +void test_std_cinttypes_function_pointer_addresses() { + uintmax_t (*l1)(const char *, char **, int) = + &std::strtoumax; // NON_COMPLIANT + uintmax_t (*l2)(const char *, char **, int) = std::strtoumax; // NON_COMPLIANT + intmax_t (*l3)(const char *, char **, int) = &std::strtoimax; // NON_COMPLIANT + intmax_t (*l4)(const char *, char **, int) = std::strtoimax; // NON_COMPLIANT + uintmax_t (*l5)(const wchar_t *, wchar_t **, int) = + &std::wcstoumax; // NON_COMPLIANT + uintmax_t (*l6)(const wchar_t *, wchar_t **, int) = + std::wcstoumax; // NON_COMPLIANT + intmax_t (*l7)(const wchar_t *, wchar_t **, int) = + &std::wcstoimax; // NON_COMPLIANT + intmax_t (*l8)(const wchar_t *, wchar_t **, int) = + std::wcstoimax; // NON_COMPLIANT +} + +void test_compliant_alternatives() { + char l1[100]; + const char *l2 = "test"; + std::size_t l3 = 50; + + // Using std::string_view instead of strlen + std::string_view l4 = l2; + if (l4.size() + 1u < l3) { // COMPLIANT + l4.copy(l1, l4.size()); // COMPLIANT + l1[l4.size()] = 0; // COMPLIANT + } + + // Using std::string for string operations + std::string l5 = "hello"; + std::string l6 = "world"; + std::string l7 = l5 + l6; // COMPLIANT + + // Using standard library numeric conversions + std::string l8 = "123"; + std::int32_t l9 = std::stoi(l8); // COMPLIANT + double l10 = std::stod(l8); // COMPLIANT +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.expected b/cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.expected new file mode 100644 index 0000000000..fcb5a8aeee --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.expected @@ -0,0 +1,9 @@ +| test.cpp:4:3:4:13 | call to system | Call to banned function 'system'. | +| test.cpp:8:14:8:24 | system | Address taken for banned function 'system'. | +| test.cpp:9:29:9:39 | system | Address taken for banned function 'system'. | +| test.cpp:13:40:13:50 | system | Address taken for banned function 'system'. | +| test.cpp:17:3:17:13 | call to system | Call to banned function 'system'. | +| test.cpp:22:3:22:13 | call to system | Call to banned function 'system'. | +| test.cpp:35:3:35:8 | call to system | Call to banned function 'system'. | +| test.cpp:39:29:39:34 | system | Address taken for banned function 'system'. | +| test.cpp:44:3:44:21 | system(x) | Use of banned macro 'system'. | diff --git a/cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.qlref b/cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.qlref new file mode 100644 index 0000000000..2580c7a6a9 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.qlref @@ -0,0 +1 @@ +rules/RULE-21-2-3/BannedSystemFunction.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-2-3/test.cpp b/cpp/misra/test/rules/RULE-21-2-3/test.cpp new file mode 100644 index 0000000000..89ed82d88f --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-3/test.cpp @@ -0,0 +1,45 @@ +#include + +void test_direct_call_to_system() { + std::system("echo hello"); // NON_COMPLIANT +} + +void test_system_function_pointer() { + auto l1 = &std::system; // NON_COMPLIANT + int (*l2)(const char *) = std::system; // NON_COMPLIANT +} + +void test_system_address_taken() { + void *l1 = reinterpret_cast(&std::system); // NON_COMPLIANT +} + +void test_system_call_with_null() { + std::system(nullptr); // NON_COMPLIANT +} + +void test_system_call_with_variable() { + const char *l1 = "ls"; + std::system(l1); // NON_COMPLIANT +} + +void test_compliant_alternative() { + // Using compliant alternatives instead of system() + const char *l1 = "some command"; // COMPLIANT + // Implementation-specific alternatives would be used here +} + +// Test with C-style header (rule also applies to ) +#include + +void test_c_style_header_system() { + system("echo hello"); // NON_COMPLIANT +} + +void test_c_style_header_function_pointer() { + int (*l1)(const char *) = system; // NON_COMPLIANT +} + +#define system(x) 0 +void test_system_macro_expansion() { + system("echo test"); // NON_COMPLIANT +} diff --git a/cpp/misra/test/rules/RULE-21-2-4/MacroOffsetofShallNotBeUsed.testref b/cpp/misra/test/rules/RULE-21-2-4/MacroOffsetofShallNotBeUsed.testref new file mode 100644 index 0000000000..022fef6071 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-4/MacroOffsetofShallNotBeUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/macrooffsetofused/MacroOffsetofUsed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-6-4/GlobalSizedOperatorDeleteShallBeDefined.testref b/cpp/misra/test/rules/RULE-21-6-4/GlobalSizedOperatorDeleteShallBeDefined.testref new file mode 100644 index 0000000000..4d1e21d4cb --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-6-4/GlobalSizedOperatorDeleteShallBeDefined.testref @@ -0,0 +1 @@ +cpp/common/test/rules/globalsizedoperatordeletenotdefined/GlobalSizedOperatorDeleteNotDefined.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-6-4/GlobalUnsizedOperatorDeleteShallBeDefined.testref b/cpp/misra/test/rules/RULE-21-6-4/GlobalUnsizedOperatorDeleteShallBeDefined.testref new file mode 100644 index 0000000000..f2fcc2eded --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-6-4/GlobalUnsizedOperatorDeleteShallBeDefined.testref @@ -0,0 +1 @@ +cpp/common/test/rules/globalunsizedoperatordeletenotdefined/GlobalUnsizedOperatorDeleteNotDefined.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-6-5/PointerToAnIncompleteClassTypeDeleted.testref b/cpp/misra/test/rules/RULE-21-6-5/PointerToAnIncompleteClassTypeDeleted.testref new file mode 100644 index 0000000000..3f4895b1c4 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-6-5/PointerToAnIncompleteClassTypeDeleted.testref @@ -0,0 +1 @@ +cpp/common/test/rules/deleteofpointertoincompleteclass/DeleteOfPointerToIncompleteClass.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.expected b/cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.expected new file mode 100644 index 0000000000..a6d399c0d2 --- /dev/null +++ b/cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.expected @@ -0,0 +1,9 @@ +| test.cpp:23:25:23:27 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. | +| test.cpp:28:25:28:27 | call to unique_ptr | Use of raw pointer constructor for 'std::unique_ptr'. | +| test.cpp:34:3:34:32 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. | +| test.cpp:40:3:40:32 | call to unique_ptr | Use of raw pointer constructor for 'std::unique_ptr'. | +| test.cpp:46:6:46:32 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. | +| test.cpp:47:6:47:32 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. | +| test.cpp:57:27:57:29 | call to unique_ptr | Use of raw pointer constructor for 'std::unique_ptr'. | +| test.cpp:67:25:67:31 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. | +| test.cpp:74:39:74:45 | call to unique_ptr | Use of raw pointer constructor for 'std::unique_ptr'. | diff --git a/cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.qlref b/cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.qlref new file mode 100644 index 0000000000..337d1b2ade --- /dev/null +++ b/cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.qlref @@ -0,0 +1 @@ +rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-23-11-1/test.cpp b/cpp/misra/test/rules/RULE-23-11-1/test.cpp new file mode 100644 index 0000000000..1f0cb2cf7a --- /dev/null +++ b/cpp/misra/test/rules/RULE-23-11-1/test.cpp @@ -0,0 +1,84 @@ +#include +#include + +struct A { + std::int8_t i; +}; + +class B {}; + +void test_make_shared_compliant() { + auto p = std::make_shared(); // COMPLIANT + std::int8_t *pi = &(p->i); + std::shared_ptr q( + p, pi); // COMPLIANT - aliasing constructor, not taking ownership +} + +void test_make_unique_compliant() { + auto p = std::make_unique(); // COMPLIANT +} + +void test_raw_pointer_shared_ptr_non_compliant() { + A *l1 = new A(); + std::shared_ptr l2(l1); // NON_COMPLIANT +} + +void test_raw_pointer_unique_ptr_non_compliant() { + A *l1 = new A(); + std::unique_ptr l2(l1); // NON_COMPLIANT +} + +auto test_exception_safety_issue() { + auto *l1 = new A(); + auto l2 = std::make_unique(); // may throw + return std::shared_ptr(l1); // NON_COMPLIANT - memory leak + // if make_unique throws +} + +auto test_double_delete_issue(std::unique_ptr p) { + auto l1 = p.get(); + return std::unique_ptr(l1); // NON_COMPLIANT - causes double delete +} + +void f1(std::shared_ptr a, std::shared_ptr b); + +void test_function_argument_non_compliant() { + f1(std::shared_ptr(new A()), // NON_COMPLIANT + std::shared_ptr(new B())); // NON_COMPLIANT +} + +void test_function_argument_compliant() { + f1(std::make_shared(), // COMPLIANT + std::make_shared()); // COMPLIANT +} + +void test_array_raw_pointer_non_compliant() { + A *l1 = new A[10]; + std::unique_ptr l2(l1); // NON_COMPLIANT +} + +void test_array_make_unique_compliant() { + auto l1 = std::make_unique(10); // COMPLIANT +} + +void test_custom_deleter_shared_ptr() { + A *l1 = new A(); + auto l2 = [](A *p) { delete p; }; + std::shared_ptr l3(l1, l2); // NON_COMPLIANT - still + // using raw pointer constructor +} + +void test_custom_deleter_unique_ptr() { + A *l1 = new A(); + auto l2 = [](A *p) { delete p; }; + std::unique_ptr l3(l1, l2); // NON_COMPLIANT - still + // using raw pointer constructor +} + +void test_nullptr_shared_ptr() { + std::shared_ptr l1(nullptr); // COMPLIANT - no ownership taken +} + +void test_nullptr_unique_ptr() { + std::unique_ptr l1(nullptr); // COMPLIANT - no ownership taken +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.expected b/cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.expected new file mode 100644 index 0000000000..1c02073fb9 --- /dev/null +++ b/cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.expected @@ -0,0 +1,132 @@ +| test.cpp:11:3:11:14 | call to isalnum | Call to banned character handling function 'isalnum' from or . | +| test.cpp:12:3:12:14 | call to isalpha | Call to banned character handling function 'isalpha' from or . | +| test.cpp:13:3:13:14 | call to isblank | Call to banned character handling function 'isblank' from or . | +| test.cpp:14:3:14:14 | call to iscntrl | Call to banned character handling function 'iscntrl' from or . | +| test.cpp:15:3:15:14 | call to isdigit | Call to banned character handling function 'isdigit' from or . | +| test.cpp:16:3:16:14 | call to isgraph | Call to banned character handling function 'isgraph' from or . | +| test.cpp:17:3:17:14 | call to islower | Call to banned character handling function 'islower' from or . | +| test.cpp:18:3:18:14 | call to isprint | Call to banned character handling function 'isprint' from or . | +| test.cpp:19:3:19:14 | call to ispunct | Call to banned character handling function 'ispunct' from or . | +| test.cpp:20:3:20:14 | call to isspace | Call to banned character handling function 'isspace' from or . | +| test.cpp:21:3:21:14 | call to isupper | Call to banned character handling function 'isupper' from or . | +| test.cpp:22:3:22:15 | call to isxdigit | Call to banned character handling function 'isxdigit' from or . | +| test.cpp:25:3:25:14 | call to tolower | Call to banned character handling function 'tolower' from or . | +| test.cpp:26:3:26:14 | call to toupper | Call to banned character handling function 'toupper' from or . | +| test.cpp:33:3:33:9 | call to isalnum | Call to banned character handling function 'isalnum' from or . | +| test.cpp:34:3:34:9 | call to isalpha | Call to banned character handling function 'isalpha' from or . | +| test.cpp:35:3:35:9 | call to isblank | Call to banned character handling function 'isblank' from or . | +| test.cpp:36:3:36:9 | call to iscntrl | Call to banned character handling function 'iscntrl' from or . | +| test.cpp:37:3:37:9 | call to isdigit | Call to banned character handling function 'isdigit' from or . | +| test.cpp:38:3:38:9 | call to isgraph | Call to banned character handling function 'isgraph' from or . | +| test.cpp:39:3:39:9 | call to islower | Call to banned character handling function 'islower' from or . | +| test.cpp:40:3:40:9 | call to isprint | Call to banned character handling function 'isprint' from or . | +| test.cpp:41:3:41:9 | call to ispunct | Call to banned character handling function 'ispunct' from or . | +| test.cpp:42:3:42:9 | call to isspace | Call to banned character handling function 'isspace' from or . | +| test.cpp:43:3:43:9 | call to isupper | Call to banned character handling function 'isupper' from or . | +| test.cpp:44:3:44:10 | call to isxdigit | Call to banned character handling function 'isxdigit' from or . | +| test.cpp:47:3:47:9 | call to tolower | Call to banned character handling function 'tolower' from or . | +| test.cpp:48:3:48:9 | call to toupper | Call to banned character handling function 'toupper' from or . | +| test.cpp:55:3:55:15 | call to iswalnum | Call to banned character handling function 'iswalnum' from or . | +| test.cpp:56:3:56:15 | call to iswalpha | Call to banned character handling function 'iswalpha' from or . | +| test.cpp:57:3:57:15 | call to iswblank | Call to banned character handling function 'iswblank' from or . | +| test.cpp:58:3:58:15 | call to iswcntrl | Call to banned character handling function 'iswcntrl' from or . | +| test.cpp:59:3:59:15 | call to iswdigit | Call to banned character handling function 'iswdigit' from or . | +| test.cpp:60:3:60:15 | call to iswgraph | Call to banned character handling function 'iswgraph' from or . | +| test.cpp:61:3:61:15 | call to iswlower | Call to banned character handling function 'iswlower' from or . | +| test.cpp:62:3:62:15 | call to iswprint | Call to banned character handling function 'iswprint' from or . | +| test.cpp:63:3:63:15 | call to iswpunct | Call to banned character handling function 'iswpunct' from or . | +| test.cpp:64:3:64:15 | call to iswspace | Call to banned character handling function 'iswspace' from or . | +| test.cpp:65:3:65:15 | call to iswupper | Call to banned character handling function 'iswupper' from or . | +| test.cpp:66:3:66:16 | call to iswxdigit | Call to banned character handling function 'iswxdigit' from or . | +| test.cpp:69:3:69:15 | call to towlower | Call to banned character handling function 'towlower' from or . | +| test.cpp:70:3:70:15 | call to towupper | Call to banned character handling function 'towupper' from or . | +| test.cpp:73:3:73:13 | call to wctype | Call to banned character handling function 'wctype' from or . | +| test.cpp:74:3:74:15 | call to iswctype | Call to banned character handling function 'iswctype' from or . | +| test.cpp:74:21:74:31 | call to wctype | Call to banned character handling function 'wctype' from or . | +| test.cpp:75:3:75:14 | call to wctrans | Call to banned character handling function 'wctrans' from or . | +| test.cpp:76:3:76:16 | call to towctrans | Call to banned character handling function 'towctrans' from or . | +| test.cpp:76:22:76:33 | call to wctrans | Call to banned character handling function 'wctrans' from or . | +| test.cpp:83:3:83:10 | call to iswalnum | Call to banned character handling function 'iswalnum' from or . | +| test.cpp:84:3:84:10 | call to iswalpha | Call to banned character handling function 'iswalpha' from or . | +| test.cpp:85:3:85:10 | call to iswblank | Call to banned character handling function 'iswblank' from or . | +| test.cpp:86:3:86:10 | call to iswcntrl | Call to banned character handling function 'iswcntrl' from or . | +| test.cpp:87:3:87:10 | call to iswdigit | Call to banned character handling function 'iswdigit' from or . | +| test.cpp:88:3:88:10 | call to iswgraph | Call to banned character handling function 'iswgraph' from or . | +| test.cpp:89:3:89:10 | call to iswlower | Call to banned character handling function 'iswlower' from or . | +| test.cpp:90:3:90:10 | call to iswprint | Call to banned character handling function 'iswprint' from or . | +| test.cpp:91:3:91:10 | call to iswpunct | Call to banned character handling function 'iswpunct' from or . | +| test.cpp:92:3:92:10 | call to iswspace | Call to banned character handling function 'iswspace' from or . | +| test.cpp:93:3:93:10 | call to iswupper | Call to banned character handling function 'iswupper' from or . | +| test.cpp:94:3:94:11 | call to iswxdigit | Call to banned character handling function 'iswxdigit' from or . | +| test.cpp:97:3:97:10 | call to towlower | Call to banned character handling function 'towlower' from or . | +| test.cpp:98:3:98:10 | call to towupper | Call to banned character handling function 'towupper' from or . | +| test.cpp:101:3:101:8 | call to wctype | Call to banned character handling function 'wctype' from or . | +| test.cpp:102:3:102:10 | call to iswctype | Call to banned character handling function 'iswctype' from or . | +| test.cpp:102:16:102:21 | call to wctype | Call to banned character handling function 'wctype' from or . | +| test.cpp:103:3:103:9 | call to wctrans | Call to banned character handling function 'wctrans' from or . | +| test.cpp:104:3:104:11 | call to towctrans | Call to banned character handling function 'towctrans' from or . | +| test.cpp:104:17:104:23 | call to wctrans | Call to banned character handling function 'wctrans' from or . | +| test.cpp:109:20:109:32 | isalnum | Address taken for banned character handling function 'isalnum' from or . | +| test.cpp:110:20:110:32 | isalpha | Address taken for banned character handling function 'isalpha' from or . | +| test.cpp:111:20:111:32 | isblank | Address taken for banned character handling function 'isblank' from or . | +| test.cpp:112:20:112:32 | iscntrl | Address taken for banned character handling function 'iscntrl' from or . | +| test.cpp:113:20:113:32 | isdigit | Address taken for banned character handling function 'isdigit' from or . | +| test.cpp:114:20:114:32 | isgraph | Address taken for banned character handling function 'isgraph' from or . | +| test.cpp:115:20:115:32 | islower | Address taken for banned character handling function 'islower' from or . | +| test.cpp:116:20:116:32 | isprint | Address taken for banned character handling function 'isprint' from or . | +| test.cpp:117:20:117:32 | ispunct | Address taken for banned character handling function 'ispunct' from or . | +| test.cpp:118:21:118:33 | isspace | Address taken for banned character handling function 'isspace' from or . | +| test.cpp:119:21:119:33 | isupper | Address taken for banned character handling function 'isupper' from or . | +| test.cpp:120:21:120:34 | isxdigit | Address taken for banned character handling function 'isxdigit' from or . | +| test.cpp:121:21:121:33 | tolower | Address taken for banned character handling function 'tolower' from or . | +| test.cpp:122:21:122:33 | toupper | Address taken for banned character handling function 'toupper' from or . | +| test.cpp:125:22:125:28 | isalnum | Address taken for banned character handling function 'isalnum' from or . | +| test.cpp:126:22:126:28 | isalpha | Address taken for banned character handling function 'isalpha' from or . | +| test.cpp:127:22:127:28 | isblank | Address taken for banned character handling function 'isblank' from or . | +| test.cpp:128:22:128:28 | iscntrl | Address taken for banned character handling function 'iscntrl' from or . | +| test.cpp:129:22:129:28 | isdigit | Address taken for banned character handling function 'isdigit' from or . | +| test.cpp:130:22:130:28 | isgraph | Address taken for banned character handling function 'isgraph' from or . | +| test.cpp:131:22:131:28 | islower | Address taken for banned character handling function 'islower' from or . | +| test.cpp:132:22:132:28 | isprint | Address taken for banned character handling function 'isprint' from or . | +| test.cpp:133:22:133:28 | ispunct | Address taken for banned character handling function 'ispunct' from or . | +| test.cpp:134:22:134:28 | isspace | Address taken for banned character handling function 'isspace' from or . | +| test.cpp:135:22:135:28 | isupper | Address taken for banned character handling function 'isupper' from or . | +| test.cpp:136:22:136:29 | isxdigit | Address taken for banned character handling function 'isxdigit' from or . | +| test.cpp:137:22:137:28 | tolower | Address taken for banned character handling function 'tolower' from or . | +| test.cpp:138:22:138:28 | toupper | Address taken for banned character handling function 'toupper' from or . | +| test.cpp:141:25:141:37 | iswalnum | Address taken for banned character handling function 'iswalnum' from or . | +| test.cpp:142:25:142:37 | iswalpha | Address taken for banned character handling function 'iswalpha' from or . | +| test.cpp:143:25:143:37 | iswblank | Address taken for banned character handling function 'iswblank' from or . | +| test.cpp:144:25:144:37 | iswcntrl | Address taken for banned character handling function 'iswcntrl' from or . | +| test.cpp:145:25:145:37 | iswdigit | Address taken for banned character handling function 'iswdigit' from or . | +| test.cpp:146:25:146:37 | iswgraph | Address taken for banned character handling function 'iswgraph' from or . | +| test.cpp:147:25:147:37 | iswlower | Address taken for banned character handling function 'iswlower' from or . | +| test.cpp:148:25:148:37 | iswprint | Address taken for banned character handling function 'iswprint' from or . | +| test.cpp:149:25:149:37 | iswpunct | Address taken for banned character handling function 'iswpunct' from or . | +| test.cpp:150:25:150:37 | iswspace | Address taken for banned character handling function 'iswspace' from or . | +| test.cpp:151:25:151:37 | iswupper | Address taken for banned character handling function 'iswupper' from or . | +| test.cpp:152:25:152:38 | iswxdigit | Address taken for banned character handling function 'iswxdigit' from or . | +| test.cpp:153:28:153:40 | towlower | Address taken for banned character handling function 'towlower' from or . | +| test.cpp:154:28:154:40 | towupper | Address taken for banned character handling function 'towupper' from or . | +| test.cpp:155:36:155:46 | wctype | Address taken for banned character handling function 'wctype' from or . | +| test.cpp:156:35:156:47 | iswctype | Address taken for banned character handling function 'iswctype' from or . | +| test.cpp:157:37:157:48 | wctrans | Address taken for banned character handling function 'wctrans' from or . | +| test.cpp:158:39:158:52 | towctrans | Address taken for banned character handling function 'towctrans' from or . | +| test.cpp:161:25:161:32 | iswalnum | Address taken for banned character handling function 'iswalnum' from or . | +| test.cpp:162:25:162:32 | iswalpha | Address taken for banned character handling function 'iswalpha' from or . | +| test.cpp:163:25:163:32 | iswblank | Address taken for banned character handling function 'iswblank' from or . | +| test.cpp:164:25:164:32 | iswcntrl | Address taken for banned character handling function 'iswcntrl' from or . | +| test.cpp:165:25:165:32 | iswdigit | Address taken for banned character handling function 'iswdigit' from or . | +| test.cpp:166:25:166:32 | iswgraph | Address taken for banned character handling function 'iswgraph' from or . | +| test.cpp:167:25:167:32 | iswlower | Address taken for banned character handling function 'iswlower' from or . | +| test.cpp:168:25:168:32 | iswprint | Address taken for banned character handling function 'iswprint' from or . | +| test.cpp:169:25:169:32 | iswpunct | Address taken for banned character handling function 'iswpunct' from or . | +| test.cpp:170:25:170:32 | iswspace | Address taken for banned character handling function 'iswspace' from or . | +| test.cpp:171:25:171:32 | iswupper | Address taken for banned character handling function 'iswupper' from or . | +| test.cpp:172:25:172:33 | iswxdigit | Address taken for banned character handling function 'iswxdigit' from or . | +| test.cpp:173:28:173:35 | towlower | Address taken for banned character handling function 'towlower' from or . | +| test.cpp:174:28:174:35 | towupper | Address taken for banned character handling function 'towupper' from or . | +| test.cpp:175:36:175:41 | wctype | Address taken for banned character handling function 'wctype' from or . | +| test.cpp:176:35:176:42 | iswctype | Address taken for banned character handling function 'iswctype' from or . | +| test.cpp:177:37:177:43 | wctrans | Address taken for banned character handling function 'wctrans' from or . | +| test.cpp:178:39:178:47 | towctrans | Address taken for banned character handling function 'towctrans' from or . | diff --git a/cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.qlref b/cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.qlref new file mode 100644 index 0000000000..a2ac2abeab --- /dev/null +++ b/cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.qlref @@ -0,0 +1 @@ +rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-24-5-1/test.cpp b/cpp/misra/test/rules/RULE-24-5-1/test.cpp new file mode 100644 index 0000000000..6c06441c8d --- /dev/null +++ b/cpp/misra/test/rules/RULE-24-5-1/test.cpp @@ -0,0 +1,219 @@ +#include +#include +#include +#include +#include + +void test_cctype_functions() { + char l1 = 'A'; + + // Character classification functions from + std::isalnum(l1); // NON_COMPLIANT + std::isalpha(l1); // NON_COMPLIANT + std::isblank(l1); // NON_COMPLIANT + std::iscntrl(l1); // NON_COMPLIANT + std::isdigit(l1); // NON_COMPLIANT + std::isgraph(l1); // NON_COMPLIANT + std::islower(l1); // NON_COMPLIANT + std::isprint(l1); // NON_COMPLIANT + std::ispunct(l1); // NON_COMPLIANT + std::isspace(l1); // NON_COMPLIANT + std::isupper(l1); // NON_COMPLIANT + std::isxdigit(l1); // NON_COMPLIANT + + // Character case mapping functions from + std::tolower(l1); // NON_COMPLIANT + std::toupper(l1); // NON_COMPLIANT +} + +void test_ctype_h_functions() { + char l1 = 'A'; + + // Character classification functions from + isalnum(l1); // NON_COMPLIANT + isalpha(l1); // NON_COMPLIANT + isblank(l1); // NON_COMPLIANT + iscntrl(l1); // NON_COMPLIANT + isdigit(l1); // NON_COMPLIANT + isgraph(l1); // NON_COMPLIANT + islower(l1); // NON_COMPLIANT + isprint(l1); // NON_COMPLIANT + ispunct(l1); // NON_COMPLIANT + isspace(l1); // NON_COMPLIANT + isupper(l1); // NON_COMPLIANT + isxdigit(l1); // NON_COMPLIANT + + // Character case mapping functions from + tolower(l1); // NON_COMPLIANT + toupper(l1); // NON_COMPLIANT +} + +void test_cwctype_functions() { + wchar_t l1 = L'A'; + + // Wide character classification functions from + std::iswalnum(l1); // NON_COMPLIANT + std::iswalpha(l1); // NON_COMPLIANT + std::iswblank(l1); // NON_COMPLIANT + std::iswcntrl(l1); // NON_COMPLIANT + std::iswdigit(l1); // NON_COMPLIANT + std::iswgraph(l1); // NON_COMPLIANT + std::iswlower(l1); // NON_COMPLIANT + std::iswprint(l1); // NON_COMPLIANT + std::iswpunct(l1); // NON_COMPLIANT + std::iswspace(l1); // NON_COMPLIANT + std::iswupper(l1); // NON_COMPLIANT + std::iswxdigit(l1); // NON_COMPLIANT + + // Wide character case mapping functions from + std::towlower(l1); // NON_COMPLIANT + std::towupper(l1); // NON_COMPLIANT + + // Wide character type functions from + std::wctype("alpha"); // NON_COMPLIANT + std::iswctype(l1, std::wctype("alpha")); // NON_COMPLIANT + std::wctrans("tolower"); // NON_COMPLIANT + std::towctrans(l1, std::wctrans("tolower")); // NON_COMPLIANT +} + +void test_wctype_h_functions() { + wchar_t l1 = L'A'; + + // Wide character classification functions from + iswalnum(l1); // NON_COMPLIANT + iswalpha(l1); // NON_COMPLIANT + iswblank(l1); // NON_COMPLIANT + iswcntrl(l1); // NON_COMPLIANT + iswdigit(l1); // NON_COMPLIANT + iswgraph(l1); // NON_COMPLIANT + iswlower(l1); // NON_COMPLIANT + iswprint(l1); // NON_COMPLIANT + iswpunct(l1); // NON_COMPLIANT + iswspace(l1); // NON_COMPLIANT + iswupper(l1); // NON_COMPLIANT + iswxdigit(l1); // NON_COMPLIANT + + // Wide character case mapping functions from + towlower(l1); // NON_COMPLIANT + towupper(l1); // NON_COMPLIANT + + // Wide character type functions from + wctype("alpha"); // NON_COMPLIANT + iswctype(l1, wctype("alpha")); // NON_COMPLIANT + wctrans("tolower"); // NON_COMPLIANT + towctrans(l1, wctrans("tolower")); // NON_COMPLIANT +} + +void test_function_addresses() { + // Taking addresses of functions from + int (*l1)(int) = &std::isalnum; // NON_COMPLIANT + int (*l2)(int) = &std::isalpha; // NON_COMPLIANT + int (*l3)(int) = &std::isblank; // NON_COMPLIANT + int (*l4)(int) = &std::iscntrl; // NON_COMPLIANT + int (*l5)(int) = &std::isdigit; // NON_COMPLIANT + int (*l6)(int) = &std::isgraph; // NON_COMPLIANT + int (*l7)(int) = &std::islower; // NON_COMPLIANT + int (*l8)(int) = &std::isprint; // NON_COMPLIANT + int (*l9)(int) = &std::ispunct; // NON_COMPLIANT + int (*l10)(int) = &std::isspace; // NON_COMPLIANT + int (*l11)(int) = &std::isupper; // NON_COMPLIANT + int (*l12)(int) = &std::isxdigit; // NON_COMPLIANT + int (*l13)(int) = &std::tolower; // NON_COMPLIANT + int (*l14)(int) = &std::toupper; // NON_COMPLIANT + + // Taking addresses of functions from + int (*l15)(int) = &isalnum; // NON_COMPLIANT + int (*l16)(int) = &isalpha; // NON_COMPLIANT + int (*l17)(int) = &isblank; // NON_COMPLIANT + int (*l18)(int) = &iscntrl; // NON_COMPLIANT + int (*l19)(int) = &isdigit; // NON_COMPLIANT + int (*l20)(int) = &isgraph; // NON_COMPLIANT + int (*l21)(int) = &islower; // NON_COMPLIANT + int (*l22)(int) = &isprint; // NON_COMPLIANT + int (*l23)(int) = &ispunct; // NON_COMPLIANT + int (*l24)(int) = &isspace; // NON_COMPLIANT + int (*l25)(int) = &isupper; // NON_COMPLIANT + int (*l26)(int) = &isxdigit; // NON_COMPLIANT + int (*l27)(int) = &tolower; // NON_COMPLIANT + int (*l28)(int) = &toupper; // NON_COMPLIANT + + // Taking addresses of functions from + int (*l29)(wint_t) = &std::iswalnum; // NON_COMPLIANT + int (*l30)(wint_t) = &std::iswalpha; // NON_COMPLIANT + int (*l31)(wint_t) = &std::iswblank; // NON_COMPLIANT + int (*l32)(wint_t) = &std::iswcntrl; // NON_COMPLIANT + int (*l33)(wint_t) = &std::iswdigit; // NON_COMPLIANT + int (*l34)(wint_t) = &std::iswgraph; // NON_COMPLIANT + int (*l35)(wint_t) = &std::iswlower; // NON_COMPLIANT + int (*l36)(wint_t) = &std::iswprint; // NON_COMPLIANT + int (*l37)(wint_t) = &std::iswpunct; // NON_COMPLIANT + int (*l38)(wint_t) = &std::iswspace; // NON_COMPLIANT + int (*l39)(wint_t) = &std::iswupper; // NON_COMPLIANT + int (*l40)(wint_t) = &std::iswxdigit; // NON_COMPLIANT + wint_t (*l41)(wint_t) = &std::towlower; // NON_COMPLIANT + wint_t (*l42)(wint_t) = &std::towupper; // NON_COMPLIANT + wctype_t (*l43)(const char *) = &std::wctype; // NON_COMPLIANT + int (*l44)(wint_t, wctype_t) = &std::iswctype; // NON_COMPLIANT + wctrans_t (*l45)(const char *) = &std::wctrans; // NON_COMPLIANT + wint_t (*l46)(wint_t, wctrans_t) = &std::towctrans; // NON_COMPLIANT + + // Taking addresses of functions from + int (*l47)(wint_t) = &iswalnum; // NON_COMPLIANT + int (*l48)(wint_t) = &iswalpha; // NON_COMPLIANT + int (*l49)(wint_t) = &iswblank; // NON_COMPLIANT + int (*l50)(wint_t) = &iswcntrl; // NON_COMPLIANT + int (*l51)(wint_t) = &iswdigit; // NON_COMPLIANT + int (*l52)(wint_t) = &iswgraph; // NON_COMPLIANT + int (*l53)(wint_t) = &iswlower; // NON_COMPLIANT + int (*l54)(wint_t) = &iswprint; // NON_COMPLIANT + int (*l55)(wint_t) = &iswpunct; // NON_COMPLIANT + int (*l56)(wint_t) = &iswspace; // NON_COMPLIANT + int (*l57)(wint_t) = &iswupper; // NON_COMPLIANT + int (*l58)(wint_t) = &iswxdigit; // NON_COMPLIANT + wint_t (*l59)(wint_t) = &towlower; // NON_COMPLIANT + wint_t (*l60)(wint_t) = &towupper; // NON_COMPLIANT + wctype_t (*l61)(const char *) = &wctype; // NON_COMPLIANT + int (*l62)(wint_t, wctype_t) = &iswctype; // NON_COMPLIANT + wctrans_t (*l63)(const char *) = &wctrans; // NON_COMPLIANT + wint_t (*l64)(wint_t, wctrans_t) = &towctrans; // NON_COMPLIANT +} + +void test_compliant_locale_usage() { + char l1 = 'A'; + wchar_t l2 = L'A'; + std::locale l3{}; + + // Compliant usage with locale parameter + std::isalnum(l1, l3); // COMPLIANT + std::isalpha(l1, l3); // COMPLIANT + std::isblank(l1, l3); // COMPLIANT + std::iscntrl(l1, l3); // COMPLIANT + std::isdigit(l1, l3); // COMPLIANT + std::isgraph(l1, l3); // COMPLIANT + std::islower(l1, l3); // COMPLIANT + std::isprint(l1, l3); // COMPLIANT + std::ispunct(l1, l3); // COMPLIANT + std::isspace(l1, l3); // COMPLIANT + std::isupper(l1, l3); // COMPLIANT + std::isxdigit(l1, l3); // COMPLIANT + + std::tolower(l1, l3); // COMPLIANT + std::toupper(l1, l3); // COMPLIANT + + // Compliant wide character usage with locale parameter + std::isalnum(l2, l3); // COMPLIANT + std::isalpha(l2, l3); // COMPLIANT + std::isblank(l2, l3); // COMPLIANT + std::iscntrl(l2, l3); // COMPLIANT + std::isdigit(l2, l3); // COMPLIANT + std::isgraph(l2, l3); // COMPLIANT + std::islower(l2, l3); // COMPLIANT + std::isprint(l2, l3); // COMPLIANT + std::ispunct(l2, l3); // COMPLIANT + std::isspace(l2, l3); // COMPLIANT + std::isupper(l2, l3); // COMPLIANT + std::isxdigit(l2, l3); // COMPLIANT + + std::tolower(l2, l3); // COMPLIANT + std::toupper(l2, l3); // COMPLIANT +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.expected b/cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.expected new file mode 100644 index 0000000000..49ce89347c --- /dev/null +++ b/cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.expected @@ -0,0 +1,23 @@ +| test.cpp:9:3:9:8 | call to memcpy | Call to banned function 'memcpy' from . | +| test.cpp:10:3:10:13 | call to memcpy | Call to banned function 'memcpy' from . | +| test.cpp:17:3:17:9 | call to memmove | Call to banned function 'memmove' from . | +| test.cpp:18:3:18:14 | call to memmove | Call to banned function 'memmove' from . | +| test.cpp:25:12:25:17 | call to memcmp | Call to banned function 'memcmp' from . | +| test.cpp:26:12:26:22 | call to memcmp | Call to banned function 'memcmp' from . | +| test.cpp:30:52:30:57 | memcpy | Address taken for banned function 'memcpy' from . | +| test.cpp:31:52:31:58 | memmove | Address taken for banned function 'memmove' from . | +| test.cpp:32:56:32:61 | memcmp | Address taken for banned function 'memcmp' from . | +| test.cpp:34:52:34:62 | memcpy | Address taken for banned function 'memcpy' from . | +| test.cpp:36:7:36:18 | memmove | Address taken for banned function 'memmove' from . | +| test.cpp:38:7:38:17 | memcmp | Address taken for banned function 'memcmp' from . | +| test.cpp:50:7:50:12 | call to memcmp | Call to banned function 'memcmp' from . | +| test.cpp:53:7:53:17 | call to memcmp | Call to banned function 'memcmp' from . | +| test.cpp:61:7:61:12 | call to memcmp | Call to banned function 'memcmp' from . | +| test.cpp:64:7:64:17 | call to memcmp | Call to banned function 'memcmp' from . | +| test.cpp:71:3:71:8 | call to memcpy | Call to banned function 'memcpy' from . | +| test.cpp:72:3:72:9 | call to memmove | Call to banned function 'memmove' from . | +| test.cpp:74:3:74:13 | call to memcpy | Call to banned function 'memcpy' from . | +| test.cpp:75:3:75:14 | call to memmove | Call to banned function 'memmove' from . | +| test.cpp:78:1:78:28 | #define CUSTOM_MEMCPY memcpy | Call to banned function 'memcpy' from . | +| test.cpp:79:1:79:30 | #define CUSTOM_MEMMOVE memmove | Call to banned function 'memmove' from . | +| test.cpp:80:1:80:28 | #define CUSTOM_MEMCMP memcmp | Call to banned function 'memcmp' from . | diff --git a/cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.qlref b/cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.qlref new file mode 100644 index 0000000000..53307ad85f --- /dev/null +++ b/cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.qlref @@ -0,0 +1 @@ +rules/RULE-24-5-2/NoMemoryFunctionsFromCString.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-24-5-2/test.cpp b/cpp/misra/test/rules/RULE-24-5-2/test.cpp new file mode 100644 index 0000000000..f189afdbc6 --- /dev/null +++ b/cpp/misra/test/rules/RULE-24-5-2/test.cpp @@ -0,0 +1,89 @@ +#include +#include +#include + +void test_memcpy_usage() { + std::uint8_t l1[10]; + std::uint8_t l2[10]; + + memcpy(l1, l2, 10); // NON_COMPLIANT + std::memcpy(l1, l2, 10); // NON_COMPLIANT +} + +void test_memmove_usage() { + std::uint8_t l1[10]; + std::uint8_t l2[10]; + + memmove(l1, l2, 10); // NON_COMPLIANT + std::memmove(l1, l2, 10); // NON_COMPLIANT +} + +void test_memcmp_usage() { + std::uint8_t l1[10]; + std::uint8_t l2[10]; + + int l3 = memcmp(l1, l2, 10); // NON_COMPLIANT + int l4 = std::memcmp(l1, l2, 10); // NON_COMPLIANT +} + +void test_function_pointers() { + void *(*l1)(void *, const void *, std::size_t) = memcpy; // NON_COMPLIANT + void *(*l2)(void *, const void *, std::size_t) = memmove; // NON_COMPLIANT + int (*l3)(const void *, const void *, std::size_t) = memcmp; // NON_COMPLIANT + + void *(*l4)(void *, const void *, std::size_t) = std::memcpy; // NON_COMPLIANT + void *(*l5)(void *, const void *, std::size_t) = + std::memmove; // NON_COMPLIANT + int (*l6)(const void *, const void *, std::size_t) = + std::memcmp; // NON_COMPLIANT +} + +struct S { + bool m1; + std::int64_t m2; +}; + +void test_struct_comparison() { + S l1{true, 42}; + S l2{true, 42}; + + if (memcmp(&l1, &l2, sizeof(S)) != 0) { // NON_COMPLIANT + } + + if (std::memcmp(&l1, &l2, sizeof(S)) != 0) { // NON_COMPLIANT + } +} + +void test_buffer_comparison() { + char l1[12]; + char l2[12]; + + if (memcmp(l1, l2, sizeof(l1)) != 0) { // NON_COMPLIANT + } + + if (std::memcmp(l1, l2, sizeof(l1)) != 0) { // NON_COMPLIANT + } +} + +void test_overlapping_memory() { + std::uint8_t l1[20]; + + memcpy(l1 + 5, l1, 10); // NON_COMPLIANT + memmove(l1 + 5, l1, 10); // NON_COMPLIANT + + std::memcpy(l1 + 5, l1, 10); // NON_COMPLIANT + std::memmove(l1 + 5, l1, 10); // NON_COMPLIANT +} + +#define CUSTOM_MEMCPY memcpy // NON_COMPLIANT +#define CUSTOM_MEMMOVE memmove // NON_COMPLIANT +#define CUSTOM_MEMCMP memcmp // NON_COMPLIANT + +void test_macro_expansion() { + std::uint8_t l1[10]; + std::uint8_t l2[10]; + + CUSTOM_MEMCPY(l1, l2, 10); + CUSTOM_MEMMOVE(l1, l2, 10); + int l3 = CUSTOM_MEMCMP(l1, l2, 10); +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.expected b/cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.expected new file mode 100644 index 0000000000..fde7f610e8 --- /dev/null +++ b/cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.expected @@ -0,0 +1,9 @@ +| test.cpp:6:3:6:16 | call to setlocale | Call to banned function 'setlocale' from . | +| test.cpp:7:3:7:16 | call to setlocale | Call to banned function 'setlocale' from . | +| test.cpp:8:3:8:16 | call to setlocale | Call to banned function 'setlocale' from . | +| test.cpp:12:3:12:21 | call to global | Call to banned function 'global' from . | +| test.cpp:13:3:13:21 | call to global | Call to banned function 'global' from . | +| test.cpp:36:5:36:18 | call to setlocale | Call to banned function 'setlocale' from . | +| test.cpp:40:5:40:18 | call to setlocale | Call to banned function 'setlocale' from . | +| test.cpp:45:3:45:21 | call to global | Call to banned function 'global' from . | +| test.cpp:46:3:46:21 | call to global | Call to banned function 'global' from . | diff --git a/cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.qlref b/cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.qlref new file mode 100644 index 0000000000..f28199a5aa --- /dev/null +++ b/cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.qlref @@ -0,0 +1 @@ +rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-25-5-1/test.cpp b/cpp/misra/test/rules/RULE-25-5-1/test.cpp new file mode 100644 index 0000000000..b45be36f70 --- /dev/null +++ b/cpp/misra/test/rules/RULE-25-5-1/test.cpp @@ -0,0 +1,47 @@ +#include +#include +#include + +void test_setlocale_call() { + std::setlocale(LC_ALL, "C"); // NON_COMPLIANT + std::setlocale(LC_NUMERIC, "C"); // NON_COMPLIANT + std::setlocale(LC_TIME, "en_US.UTF-8"); // NON_COMPLIANT +} + +void test_locale_global_call() { + std::locale::global(std::locale("C")); // NON_COMPLIANT + std::locale::global(std::locale::classic()); // NON_COMPLIANT +} + +void test_compliant_locale_usage() { + wchar_t l1 = L'\u2002'; + std::locale l2("C"); + + if (std::isspace(l1, l2)) { // COMPLIANT + } + if (std::isalpha(l1, l2)) { // COMPLIANT + } + if (std::isdigit(l1, l2)) { // COMPLIANT + } +} + +void test_compliant_locale_construction() { + std::locale l3("C"); // COMPLIANT + std::locale l4 = std::locale::classic(); // COMPLIANT + std::locale l5; // COMPLIANT +} + +void test_nested_setlocale_calls() { + if (true) { + std::setlocale(LC_ALL, "ja_JP.utf8"); // NON_COMPLIANT + } + + for (int l6 = 0; l6 < 1; ++l6) { + std::setlocale(LC_CTYPE, "C"); // NON_COMPLIANT + } +} + +void test_locale_global_with_different_locales() { + std::locale::global(std::locale("en_US.UTF-8")); // NON_COMPLIANT + std::locale::global(std::locale("ja_JP.utf8")); // NON_COMPLIANT +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-25-5-2/PointersReturnedByLocaleFunctionsMustBeUsedAsConst.testref b/cpp/misra/test/rules/RULE-25-5-2/PointersReturnedByLocaleFunctionsMustBeUsedAsConst.testref new file mode 100644 index 0000000000..febf2e9d50 --- /dev/null +++ b/cpp/misra/test/rules/RULE-25-5-2/PointersReturnedByLocaleFunctionsMustBeUsedAsConst.testref @@ -0,0 +1 @@ +cpp/common/test/rules/constlikereturnvalue/ConstLikeReturnValue.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-25-5-3/CallToSetlocaleInvalidatesOldPointersMisra.testref b/cpp/misra/test/rules/RULE-25-5-3/CallToSetlocaleInvalidatesOldPointersMisra.testref new file mode 100644 index 0000000000..74cb92bd88 --- /dev/null +++ b/cpp/misra/test/rules/RULE-25-5-3/CallToSetlocaleInvalidatesOldPointersMisra.testref @@ -0,0 +1 @@ +cpp/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-25-5-3/CallToSetlocaleInvalidatesOldPointersWarnMisra.testref b/cpp/misra/test/rules/RULE-25-5-3/CallToSetlocaleInvalidatesOldPointersWarnMisra.testref new file mode 100644 index 0000000000..1628a12aa9 --- /dev/null +++ b/cpp/misra/test/rules/RULE-25-5-3/CallToSetlocaleInvalidatesOldPointersWarnMisra.testref @@ -0,0 +1 @@ +cpp/common/test/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-26-3-1/VectorShouldNotBeSpecializedWithBool.testref b/cpp/misra/test/rules/RULE-26-3-1/VectorShouldNotBeSpecializedWithBool.testref new file mode 100644 index 0000000000..a934690acb --- /dev/null +++ b/cpp/misra/test/rules/RULE-26-3-1/VectorShouldNotBeSpecializedWithBool.testref @@ -0,0 +1 @@ +cpp/common/test/rules/vectorshouldnotbespecializedwithbool/VectorShouldNotBeSpecializedWithBool.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-28-6-2/ForwardingReferencesAndForwardNotUsedTogether.testref b/cpp/misra/test/rules/RULE-28-6-2/ForwardingReferencesAndForwardNotUsedTogether.testref new file mode 100644 index 0000000000..d56acb8415 --- /dev/null +++ b/cpp/misra/test/rules/RULE-28-6-2/ForwardingReferencesAndForwardNotUsedTogether.testref @@ -0,0 +1 @@ +cpp/common/test/rules/forwardingreferencesandforwardnotusedtogether/ForwardingReferencesAndForwardNotUsedTogether.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-28-6-3/ObjectUsedWhileInPotentiallyMovedFromState.testref b/cpp/misra/test/rules/RULE-28-6-3/ObjectUsedWhileInPotentiallyMovedFromState.testref new file mode 100644 index 0000000000..5ae8b65a71 --- /dev/null +++ b/cpp/misra/test/rules/RULE-28-6-3/ObjectUsedWhileInPotentiallyMovedFromState.testref @@ -0,0 +1 @@ +cpp/common/test/rules/movedfromobjectsunspecifiedstate/MovedFromObjectsUnspecifiedState.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-30-0-1/CstdioFunctionsShallNotBeUsed.testref b/cpp/misra/test/rules/RULE-30-0-1/CstdioFunctionsShallNotBeUsed.testref new file mode 100644 index 0000000000..5f8b3d8a9a --- /dev/null +++ b/cpp/misra/test/rules/RULE-30-0-1/CstdioFunctionsShallNotBeUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/cstdiofunctionsused/CstdioFunctionsUsed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-30-0-1/CstdioMacrosShallNotBeUsed.testref b/cpp/misra/test/rules/RULE-30-0-1/CstdioMacrosShallNotBeUsed.testref new file mode 100644 index 0000000000..a1ba376c3b --- /dev/null +++ b/cpp/misra/test/rules/RULE-30-0-1/CstdioMacrosShallNotBeUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/cstdiomacrosused/CstdioMacrosUsed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-30-0-1/CstdioTypesShallNotBeUsed.testref b/cpp/misra/test/rules/RULE-30-0-1/CstdioTypesShallNotBeUsed.testref new file mode 100644 index 0000000000..4c08a75cfe --- /dev/null +++ b/cpp/misra/test/rules/RULE-30-0-1/CstdioTypesShallNotBeUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/cstdiotypesused/CstdioTypesUsed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-30-0-2/ReadsAndWritesOnStreamNotSeparatedByPositioning.testref b/cpp/misra/test/rules/RULE-30-0-2/ReadsAndWritesOnStreamNotSeparatedByPositioning.testref new file mode 100644 index 0000000000..0a8adf7272 --- /dev/null +++ b/cpp/misra/test/rules/RULE-30-0-2/ReadsAndWritesOnStreamNotSeparatedByPositioning.testref @@ -0,0 +1 @@ +cpp/common/test/rules/iofstreammissingpositioning/IOFstreamMissingPositioning.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-5-13-1/BackslashCharacterMisuse.testref b/cpp/misra/test/rules/RULE-5-13-1/BackslashCharacterMisuse.testref new file mode 100644 index 0000000000..924122e38e --- /dev/null +++ b/cpp/misra/test/rules/RULE-5-13-1/BackslashCharacterMisuse.testref @@ -0,0 +1 @@ +cpp/common/test/rules/backslashcharactermisuse/BackslashCharacterMisuse.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-5-13-2/NonTerminatedEscapeSequences.testref b/cpp/misra/test/rules/RULE-5-13-2/NonTerminatedEscapeSequences.testref new file mode 100644 index 0000000000..bfed44b1fd --- /dev/null +++ b/cpp/misra/test/rules/RULE-5-13-2/NonTerminatedEscapeSequences.testref @@ -0,0 +1 @@ +cpp/common/test/rules/nonterminatedescapesequences/NonTerminatedEscapeSequences.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-5-13-3/OctalConstantsUsed.testref b/cpp/misra/test/rules/RULE-5-13-3/OctalConstantsUsed.testref new file mode 100644 index 0000000000..97c466a866 --- /dev/null +++ b/cpp/misra/test/rules/RULE-5-13-3/OctalConstantsUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/useofnonzerooctalliteral/UseOfNonZeroOctalLiteral.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-5-13-4/UnsignedIntegerLiteralsNotAppropriatelySuffixed.testref b/cpp/misra/test/rules/RULE-5-13-4/UnsignedIntegerLiteralsNotAppropriatelySuffixed.testref new file mode 100644 index 0000000000..9133a84ce4 --- /dev/null +++ b/cpp/misra/test/rules/RULE-5-13-4/UnsignedIntegerLiteralsNotAppropriatelySuffixed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/unsignedintegerliteralsnotappropriatelysuffixed/UnsignedIntegerLiteralsNotAppropriatelySuffixed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-5-13-5/LowercaseLStartsInLiteralSuffix.testref b/cpp/misra/test/rules/RULE-5-13-5/LowercaseLStartsInLiteralSuffix.testref new file mode 100644 index 0000000000..760d407a2d --- /dev/null +++ b/cpp/misra/test/rules/RULE-5-13-5/LowercaseLStartsInLiteralSuffix.testref @@ -0,0 +1 @@ +cpp/common/test/rules/lowercaselstartsinliteralsuffix/LowercaseLStartsInLiteralSuffix.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-5-7-1/CharacterSequenceUsedWithinACStyleComment.testref b/cpp/misra/test/rules/RULE-5-7-1/CharacterSequenceUsedWithinACStyleComment.testref new file mode 100644 index 0000000000..971b1953f7 --- /dev/null +++ b/cpp/misra/test/rules/RULE-5-7-1/CharacterSequenceUsedWithinACStyleComment.testref @@ -0,0 +1 @@ +cpp/common/test/rules/charactersequenceusedwithinacstylecomment/CharacterSequenceUsedWithinACStyleComment.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-5-7-3/LineSplicingUsedInComments.testref b/cpp/misra/test/rules/RULE-5-7-3/LineSplicingUsedInComments.testref new file mode 100644 index 0000000000..7874a476a0 --- /dev/null +++ b/cpp/misra/test/rules/RULE-5-7-3/LineSplicingUsedInComments.testref @@ -0,0 +1 @@ +cpp/common/test/rules/linesplicingusedincomments/LineSplicingUsedInComments.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-0-3/GlobalNamespaceDeclarations.testref b/cpp/misra/test/rules/RULE-6-0-3/GlobalNamespaceDeclarations.testref new file mode 100644 index 0000000000..8f71738005 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-0-3/GlobalNamespaceDeclarations.testref @@ -0,0 +1 @@ +cpp/common/test/rules/globalnamespacedeclarations/GlobalNamespaceDeclarations.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-0-4/NonGlobalFunctionMain.testref b/cpp/misra/test/rules/RULE-6-0-4/NonGlobalFunctionMain.testref new file mode 100644 index 0000000000..e149f3a33b --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-0-4/NonGlobalFunctionMain.testref @@ -0,0 +1 @@ +cpp/common/test/rules/nonglobalfunctionmain/NonGlobalFunctionMain.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-2-1/OneDefinitionRuleViolated.testref b/cpp/misra/test/rules/RULE-6-2-1/OneDefinitionRuleViolated.testref new file mode 100644 index 0000000000..b51950abaa --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-2-1/OneDefinitionRuleViolated.testref @@ -0,0 +1 @@ +cpp/common/test/rules/onedefinitionruleviolation/OneDefinitionRuleViolation.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-4-1/VariableDeclaredInInnerScopeHidesOuterScope.testref b/cpp/misra/test/rules/RULE-6-4-1/VariableDeclaredInInnerScopeHidesOuterScope.testref new file mode 100644 index 0000000000..2f41afee3b --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-4-1/VariableDeclaredInInnerScopeHidesOuterScope.testref @@ -0,0 +1 @@ +cpp/common/test/rules/identifierhidden/IdentifierHidden.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-4-2/DefinitionShallBeConsideredForUnqualifiedLookup.testref b/cpp/misra/test/rules/RULE-6-4-2/DefinitionShallBeConsideredForUnqualifiedLookup.testref new file mode 100644 index 0000000000..7a5ae74d2e --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-4-2/DefinitionShallBeConsideredForUnqualifiedLookup.testref @@ -0,0 +1 @@ +cpp/common/test/rules/definitionnotconsideredforunqualifiedlookup/DefinitionNotConsideredForUnqualifiedLookup.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-4-2/InheritedNonOverridableMemberFunction.testref b/cpp/misra/test/rules/RULE-6-4-2/InheritedNonOverridableMemberFunction.testref new file mode 100644 index 0000000000..2fb9608ee8 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-4-2/InheritedNonOverridableMemberFunction.testref @@ -0,0 +1 @@ +cpp/common/test/rules/hiddeninheritednonoverridablememberfunction/HiddenInheritedNonOverridableMemberFunction.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-4-2/InheritedOverridableMemberFunction.testref b/cpp/misra/test/rules/RULE-6-4-2/InheritedOverridableMemberFunction.testref new file mode 100644 index 0000000000..e768ced8d3 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-4-2/InheritedOverridableMemberFunction.testref @@ -0,0 +1 @@ +cpp/common/test/rules/hiddeninheritedoverridablememberfunction/HiddenInheritedOverridableMemberFunction.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-4-3/NameShallBeReferredUsingAQualifiedIdOrThis.testref b/cpp/misra/test/rules/RULE-6-4-3/NameShallBeReferredUsingAQualifiedIdOrThis.testref new file mode 100644 index 0000000000..ad5590bc1f --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-4-3/NameShallBeReferredUsingAQualifiedIdOrThis.testref @@ -0,0 +1 @@ +cpp/common/test/rules/namenotreferredusingaqualifiedidorthis/NameNotReferredUsingAQualifiedIdOrThis.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-4-3/NameShallBeReferredUsingAQualifiedIdOrThisAudit.testref b/cpp/misra/test/rules/RULE-6-4-3/NameShallBeReferredUsingAQualifiedIdOrThisAudit.testref new file mode 100644 index 0000000000..f7ff9100a6 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-4-3/NameShallBeReferredUsingAQualifiedIdOrThisAudit.testref @@ -0,0 +1 @@ +cpp/common/test/rules/namenotreferredusingaqualifiedidorthisaudit/NameNotReferredUsingAQualifiedIdOrThisAudit.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-8-1/ObjectAccessedAfterLifetimeMisra.testref b/cpp/misra/test/rules/RULE-6-8-1/ObjectAccessedAfterLifetimeMisra.testref new file mode 100644 index 0000000000..979e12ac8c --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-8-1/ObjectAccessedAfterLifetimeMisra.testref @@ -0,0 +1 @@ +cpp/common/test/rules/objectaccessedafterlifetime/ObjectAccessedAfterLifetime.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-8-1/ObjectAccessedBeforeLifetimeMisra.testref b/cpp/misra/test/rules/RULE-6-8-1/ObjectAccessedBeforeLifetimeMisra.testref new file mode 100644 index 0000000000..3f22c45632 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-8-1/ObjectAccessedBeforeLifetimeMisra.testref @@ -0,0 +1 @@ +cpp/common/test/rules/objectaccessedbeforelifetime/ObjectAccessedBeforeLifetime.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-8-2/ReturnReferenceOrPointerToAutomaticLocalVariable.testref b/cpp/misra/test/rules/RULE-6-8-2/ReturnReferenceOrPointerToAutomaticLocalVariable.testref new file mode 100644 index 0000000000..45dbffde00 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-8-2/ReturnReferenceOrPointerToAutomaticLocalVariable.testref @@ -0,0 +1 @@ +cpp/common/test/rules/returnreferenceorpointertoautomaticlocalvariable/ReturnReferenceOrPointerToAutomaticLocalVariable.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.testref b/cpp/misra/test/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.testref new file mode 100644 index 0000000000..bb41437be6 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.testref @@ -0,0 +1 @@ +cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.expected b/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.expected new file mode 100644 index 0000000000..525ba1711a --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.expected @@ -0,0 +1,33 @@ +| test.cpp:25:7:25:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:25:12:25:13 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:27:7:27:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:27:12:27:13 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:29:7:29:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:29:12:29:13 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:31:8:31:9 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:35:7:35:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:35:12:35:13 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:37:7:37:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:37:12:37:13 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:39:7:39:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:39:13:39:14 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:41:7:41:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:41:13:41:14 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:45:7:45:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:47:7:47:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:49:7:49:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:53:20:53:21 | b1 | Conversion from 'bool' to 'double'. | +| test.cpp:54:20:54:21 | b1 | Conversion from 'bool' to 'double'. | +| test.cpp:55:28:55:29 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:58:34:58:35 | b1 | Conversion from 'bool' to 'int8_t'. | +| test.cpp:59:36:59:37 | b1 | Conversion from 'bool' to 'int32_t'. | +| test.cpp:62:6:62:7 | b1 | Conversion from 'bool' to 'int32_t'. | +| test.cpp:63:6:63:7 | b1 | Conversion from 'bool' to 'double'. | +| test.cpp:66:11:66:12 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:74:9:74:10 | b1 | Conversion from 'bool' to 'int8_t'. | +| test.cpp:75:10:75:11 | b1 | Conversion from 'bool' to 'int32_t'. | +| test.cpp:76:8:76:9 | b1 | Conversion from 'bool' to 'double'. | +| test.cpp:113:33:113:36 | 1 | Conversion from 'bool' to 'A *'. | +| test.cpp:116:8:116:11 | 1 | Conversion from 'bool' to 'int'. | +| test.cpp:117:8:117:12 | 0 | Conversion from 'bool' to 'int'. | +| test.cpp:118:25:118:28 | 1 | Conversion from 'bool' to 'int'. | diff --git a/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.qlref b/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.qlref new file mode 100644 index 0000000000..6d66f51484 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.qlref @@ -0,0 +1 @@ +rules/RULE-7-0-1/NoConversionFromBool.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-1/test.cpp b/cpp/misra/test/rules/RULE-7-0-1/test.cpp new file mode 100644 index 0000000000..29fc311e3f --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-1/test.cpp @@ -0,0 +1,125 @@ +#include + +struct A { + explicit A(bool) {} +}; +struct B { + B(int) {} +}; +struct BitField { + std::uint8_t bit : 1; +}; + +void f1(std::int32_t n) {} +void f2(double d) {} + +void test_bool_conversion_violations() { + bool b1 = true; + bool b2 = false; + double d1 = 1.0; + std::int8_t s8a = 0; + std::int32_t s32a = 0; + BitField bf; + + // Bitwise operations - non-compliant + if (b1 & b2) { // NON_COMPLIANT + } + if (b1 | b2) { // NON_COMPLIANT + } + if (b1 ^ b2) { // NON_COMPLIANT + } + if (~b1) { // NON_COMPLIANT + } + + // Relational operations - non-compliant + if (b1 < b2) { // NON_COMPLIANT + } + if (b1 > b2) { // NON_COMPLIANT + } + if (b1 <= b2) { // NON_COMPLIANT + } + if (b1 >= b2) { // NON_COMPLIANT + } + + // Comparison with integer literals - non-compliant + if (b1 == 0) { // NON_COMPLIANT + } + if (b1 == 1) { // NON_COMPLIANT + } + if (b1 != 0) { // NON_COMPLIANT + } + + // Arithmetic operations - non-compliant + double l1 = d1 * b1; // NON_COMPLIANT + double l2 = d1 + b1; // NON_COMPLIANT + std::int32_t l3 = s32a + b1; // NON_COMPLIANT + + // Explicit casts to integral types - non-compliant + s8a = static_cast(b1); // NON_COMPLIANT + s32a = static_cast(b1); // NON_COMPLIANT + + // Function parameter conversion - non-compliant + f1(b1); // NON_COMPLIANT + f2(b1); // NON_COMPLIANT + + // Switch statement - non-compliant + switch (b1) { // NON_COMPLIANT + case 0: + break; + case 1: + break; + } + + // Assignment to integral types - non-compliant + s8a = b1; // NON_COMPLIANT + s32a = b1; // NON_COMPLIANT + d1 = b1; // NON_COMPLIANT +} + +void test_bool_conversion_compliant() { + bool b1 = true; + bool b2 = false; + std::int8_t s8a = 0; + BitField bf; + + // Boolean equality operations - compliant + if (b1 == false) { // COMPLIANT + } + if (b1 == true) { // COMPLIANT + } + if (b1 == b2) { // COMPLIANT + } + if (b1 != b2) { // COMPLIANT + } + + // Logical operations - compliant + if (b1 && b2) { // COMPLIANT + } + if (b1 || b2) { // COMPLIANT + } + if (!b1) { // COMPLIANT + } + + // Conditional operator without conversion - compliant + s8a = b1 ? 3 : 7; // COMPLIANT + + // Function parameter without conversion - compliant + f1(b1 ? 1 : 0); // COMPLIANT + + // Explicit constructor calls - compliant + A l1{true}; // COMPLIANT + A l2(false); // COMPLIANT + A l3 = static_cast(true); // COMPLIANT + A *l4 = reinterpret_cast(true); // NON_COMPLIANT - converted to integer + // then pointer, does not + // use constructor. + B l5{true}; // NON_COMPLIANT + B l6(false); // NON_COMPLIANT + B l7 = static_cast(true); // NON_COMPLIANT + + // Assignment to constructor - compliant + A l8 = A{false}; // COMPLIANT + + // Bit-field assignment exception - compliant + bf.bit = b1; // COMPLIANT +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected b/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected new file mode 100644 index 0000000000..cc1db5b723 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected @@ -0,0 +1,27 @@ +| test.cpp:53:20:53:28 | (bool)... | Conversion from 'int' to 'bool'. | +| test.cpp:57:7:57:7 | (bool)... | Conversion from 'int' to 'bool'. | +| test.cpp:59:7:59:8 | (bool)... | Conversion from 'uint8_t' to 'bool'. | +| test.cpp:61:8:61:8 | (bool)... | Conversion from 'int' to 'bool'. | +| test.cpp:65:7:65:8 | (bool)... | Conversion from 'uint8_t' to 'bool'. | +| test.cpp:76:8:76:9 | (bool)... | Conversion from 'int16_t' to 'bool'. | +| test.cpp:85:20:85:21 | (bool)... | Conversion from 'int32_t' to 'bool'. | +| test.cpp:91:31:91:32 | (bool)... | Conversion from 'int32_t' to 'bool'. | +| test.cpp:99:30:99:31 | (bool)... | Conversion from 'int32_t' to 'bool'. | +| test.cpp:112:12:112:13 | (bool)... | Conversion from 'int32_t' to 'bool'. | +| test.cpp:127:13:127:16 | (bool)... | Conversion from 'int32_t *' to 'bool'. | +| test.cpp:135:13:135:32 | static_cast... | Conversion from 'int' to 'bool'. | +| test.cpp:136:13:136:14 | (bool)... | Conversion from 'uint8_t' to 'bool'. | +| test.cpp:139:13:139:19 | (bool)... | Conversion from 'int' to 'bool'. | +| test.cpp:140:13:140:19 | (bool)... | Conversion from 'int' to 'bool'. | +| test.cpp:150:13:150:13 | call to operator bool | Conversion operator call from 'TestClassImplicit' to 'bool'. | +| test.cpp:163:13:163:14 | (bool)... | Conversion from 'Color' to 'bool'. | +| test.cpp:164:7:164:8 | (bool)... | Conversion from 'Color' to 'bool'. | +| test.cpp:181:13:181:14 | (bool)... | Conversion from 'float' to 'bool'. | +| test.cpp:182:13:182:14 | (bool)... | Conversion from 'double' to 'bool'. | +| test.cpp:183:13:183:14 | (bool)... | Conversion from 'long double' to 'bool'. | +| test.cpp:184:7:184:8 | (bool)... | Conversion from 'float' to 'bool'. | +| test.cpp:186:7:186:8 | (bool)... | Conversion from 'double' to 'bool'. | +| test.cpp:188:7:188:8 | (bool)... | Conversion from 'long double' to 'bool'. | +| test.cpp:201:13:201:14 | (bool)... | Conversion from 'int32_t *' to 'bool'. | +| test.cpp:213:13:213:14 | (bool)... | Conversion from '..:: *' to 'bool'. | +| test.cpp:214:13:214:14 | (bool)... | Conversion from '..:: *' to 'bool'. | diff --git a/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.qlref b/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.qlref new file mode 100644 index 0000000000..a7b86d71f8 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.qlref @@ -0,0 +1 @@ +rules/RULE-7-0-2/NoImplicitBoolConversion.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-2/test.cpp b/cpp/misra/test/rules/RULE-7-0-2/test.cpp new file mode 100644 index 0000000000..01e53c15e4 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-2/test.cpp @@ -0,0 +1,216 @@ +#include +#include + +// Global variables for testing +std::uint8_t g1 = 5; +std::uint8_t g2 = 10; +std::uint8_t g3 = 15; +std::uint8_t g4 = 20; +std::int16_t g5 = 100; +std::int32_t g6 = 200; +bool g7 = true; +std::int32_t g8[5] = {1, 2, 3, 4, 5}; + +// Function declarations +std::int32_t f1(); +bool f2(); +std::int32_t *f3(); + +// Class with explicit operator bool +class TestClassExplicit { + std::int32_t m1; + +public: + explicit operator bool() const { return m1 < 0; } +}; + +class TestClassImplicit { + std::int32_t m1; + +public: + operator bool() const { return m1 < 0; } // Implicit conversion +}; + +// Class with member function pointer +class TestClassMemberFunc { +public: + void memberFunc() {} +}; + +// Bit-field struct for exception #3 +struct BitFieldStruct { + unsigned int m1 : 1; +}; + +void test_logical_operators() { + std::uint8_t l1 = 5; + std::uint8_t l2 = 10; + std::uint8_t l3 = 15; + std::uint8_t l4 = 20; + + if ((l1 < l2) && (l3 < l4)) { // COMPLIANT + } + if ((l1 < l2) && (l3 + l4)) { // NON_COMPLIANT + } + if (true && (l3 < l4)) { // COMPLIANT + } + if (1 && (l3 < l4)) { // NON_COMPLIANT + } + if (l1 && (l3 < l4)) { // NON_COMPLIANT + } + if (!0) { // NON_COMPLIANT + } + if (!false) { // COMPLIANT + } + if (l1) { // NON_COMPLIANT + } +} + +void test_conditional_operator() { + std::int32_t l1 = 100; + std::int32_t l2 = 200; + std::int32_t l3 = 300; + std::int16_t l4 = 50; + bool l5 = true; + + l1 = l4 ? l2 : l3; // NON_COMPLIANT + l1 = l5 ? l2 : l3; // COMPLIANT + l1 = (l4 < 5) ? l2 : l3; // COMPLIANT +} + +void test_if_statements() { + std::int32_t l1; + bool l2 = f2(); + + if (std::int32_t l3 = f1()) { // NON_COMPLIANT + } + if (std::int32_t l4 = f1(); l4 != 0) { // COMPLIANT + } + if (bool l5 = f2()) { // COMPLIANT + } + if (std::int32_t l6 = f1(); l6) { // NON_COMPLIANT + } +} + +void test_while_loops() { + while (std::int32_t l1 = f1()) { // COMPLIANT - exception #4 + } + + for (std::int32_t l2 = 10; l2; --l2) { // NON_COMPLIANT + } + + while (std::cin) { // COMPLIANT - exception #2 + } +} + +void test_do_while_loops() { + std::int32_t l1 = 5; + bool l2 = true; + + do { + --l1; + } while (l1); // NON_COMPLIANT + + do { + --l1; + } while (l2); // COMPLIANT + + do { + --l1; + } while (l1 > 0); // COMPLIANT +} + +void test_pointer_conversions() { + if (f3()) { // COMPLIANT - exception #2 + } + + bool l1 = f3(); // NON_COMPLIANT + bool l2 = f3() != nullptr; // COMPLIANT + + if (nullptr) { // COMPLIANT + } +} + +void test_assignment_to_bool() { + bool l1 = static_cast(4); // NON_COMPLIANT + bool l2 = g1; // NON_COMPLIANT + bool l3 = (g1 < g2); // COMPLIANT + bool l4 = g7; // COMPLIANT + bool l5 = bool(4); // NON_COMPLIANT + bool l6 = (bool)4; // NON_COMPLIANT +} + +void test_classes_with_bool_operators() { + TestClassExplicit l1; + + bool l2 = static_cast(l1); // COMPLIANT - exception #1 + if (l1) { // COMPLIANT - exception #2 + } + TestClassImplicit l3; + bool l4 = l3; // NON_COMPLIANT +} + +void test_bitfield_conversion() { + BitFieldStruct l1; + + bool l2 = l1.m1; // COMPLIANT - exception #3 +} + +void test_unscoped_enum_conversion() { + enum Color { RED, GREEN, BLUE }; + Color l1 = RED; + + bool l2 = l1; // NON_COMPLIANT + if (l1) { // NON_COMPLIANT + } + bool l3 = (l1 == RED); // COMPLIANT +} + +void test_scoped_enum_conversion() { + enum class Status { ACTIVE, INACTIVE }; + Status l1 = Status::ACTIVE; + + bool l2 = (l1 == Status::ACTIVE); // COMPLIANT +} + +void test_floating_point_conversion() { + float l1 = 3.14f; + double l2 = 2.71; + long double l3 = 1.41L; + + bool l4 = l1; // NON_COMPLIANT + bool l5 = l2; // NON_COMPLIANT + bool l6 = l3; // NON_COMPLIANT + if (l1) { // NON_COMPLIANT + } + if (l2) { // NON_COMPLIANT + } + if (l3) { // NON_COMPLIANT + } + bool l7 = (l1 > 0.0f); // COMPLIANT + bool l8 = (l2 != 0.0); // COMPLIANT +} + +void test_array_conversion() { + std::int32_t l1[5] = {1, 2, 3, 4, 5}; + + if (l1) { // COMPLIANT + } + if (g8) { // COMPLIANT + } + bool l2 = l1; // NON_COMPLIANT + bool l3 = (l1 != nullptr); // COMPLIANT +} + +void test_member_function_pointer_conversion() { + void (TestClassMemberFunc::*l1)() = &TestClassMemberFunc::memberFunc; + void (TestClassMemberFunc::*l2)() = nullptr; + + if (l1) { // COMPLIANT - exception #2 + } + if (l2) { // COMPLIANT - exception #2 + } + bool l3 = l1; // NON_COMPLIANT + bool l4 = l2; // NON_COMPLIANT + bool l5 = (l1 != nullptr); // COMPLIANT +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-3/NoCharacterNumericalValue.expected b/cpp/misra/test/rules/RULE-7-0-3/NoCharacterNumericalValue.expected new file mode 100644 index 0000000000..a6419404da --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-3/NoCharacterNumericalValue.expected @@ -0,0 +1,28 @@ +| test.cpp:17:13:17:14 | 10 | Conversion of character type 'int' to 'char' uses numerical value of character. | +| test.cpp:18:13:18:14 | 65 | Conversion of character type 'int' to 'char' uses numerical value of character. | +| test.cpp:19:13:19:13 | 0 | Conversion of character type 'int' to 'char' uses numerical value of character. | +| test.cpp:24:20:24:22 | 97 | Conversion of character type 'char' to 'int8_t' uses numerical value of character. | +| test.cpp:25:21:25:24 | 13 | Conversion of character type 'char' to 'uint8_t' uses numerical value of character. | +| test.cpp:26:12:26:14 | 98 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:43:13:43:14 | l1 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:43:13:43:20 | ... - ... | Conversion of character type 'int' to 'char' uses numerical value of character. | +| test.cpp:43:18:43:20 | 48 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:44:13:44:14 | l1 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:44:13:44:18 | ... + ... | Conversion of character type 'int' to 'char' uses numerical value of character. | +| test.cpp:45:13:45:14 | l1 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:45:13:45:18 | ... * ... | Conversion of character type 'int' to 'char' uses numerical value of character. | +| test.cpp:51:7:51:8 | l1 | Conversion of character type 'char' to 'bool' uses numerical value of character. | +| test.cpp:51:13:51:14 | l2 | Conversion of character type 'char' to 'bool' uses numerical value of character. | +| test.cpp:53:7:53:8 | l1 | Conversion of character type 'char' to 'bool' uses numerical value of character. | +| test.cpp:55:8:55:9 | l2 | Conversion of character type 'char' to 'bool' uses numerical value of character. | +| test.cpp:73:39:73:41 | 97 | Conversion of character type 'char' to 'int_type' uses numerical value of character. | +| test.cpp:84:17:84:19 | 120 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:90:8:90:9 | l1 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:90:14:90:16 | 48 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:90:23:90:24 | l1 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:90:29:90:31 | 57 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:103:25:103:26 | l1 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:118:15:118:16 | l2 | Conversion of character type 'int_type' to 'char' uses numerical value of character. | +| test.cpp:124:31:124:32 | 65 | Conversion of character type 'int' to 'char' uses numerical value of character. | +| test.cpp:125:29:125:31 | 65 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:131:6:131:7 | l2 | Conversion of character type 'char' to 'int' uses numerical value of character. | diff --git a/cpp/misra/test/rules/RULE-7-0-3/NoCharacterNumericalValue.qlref b/cpp/misra/test/rules/RULE-7-0-3/NoCharacterNumericalValue.qlref new file mode 100644 index 0000000000..b1254bda14 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-3/NoCharacterNumericalValue.qlref @@ -0,0 +1 @@ +rules/RULE-7-0-3/NoCharacterNumericalValue.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-3/test.cpp b/cpp/misra/test/rules/RULE-7-0-3/test.cpp new file mode 100644 index 0000000000..0338f4757f --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-3/test.cpp @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include +#include + +void test_character_literal_assignment() { + char l1 = 'a'; // COMPLIANT + char l2 = '\r'; // COMPLIANT + char l3 = '\n'; // COMPLIANT + char l4 = '\0'; // COMPLIANT +} + +void test_implicit_conversion_from_int() { + char l1 = 10; // NON_COMPLIANT + char l2 = 65; // NON_COMPLIANT + char l3 = 0; // NON_COMPLIANT +} + +void test_implicit_conversion_to_int() { + char l1 = 'a'; + std::int8_t l2 = 'a'; // NON_COMPLIANT + std::uint8_t l3 = '\r'; // NON_COMPLIANT + int l4 = 'b'; // NON_COMPLIANT +} + +void test_signed_char_assignment() { + signed char l1 = 11; // COMPLIANT + signed char l2 = 65; // COMPLIANT +} + +void test_conversion_between_character_types() { + char l1 = L'A'; // COMPLIANT + wchar_t l2 = 'B'; // COMPLIANT + char16_t l3 = 'C'; // COMPLIANT + char32_t l4 = 'D'; // COMPLIANT +} + +void test_arithmetic_operations() { + char l1 = 'a'; + char l2 = l1 - '0'; // NON_COMPLIANT + char l3 = l1 + 1; // NON_COMPLIANT + char l4 = l1 * 2; // NON_COMPLIANT +} + +void test_boolean_conversion() { + char l1 = 'a'; + char l2 = '\0'; + if (l1 && l2) { // NON_COMPLIANT + } + if (l1) { // NON_COMPLIANT + } + if (!l2) { // NON_COMPLIANT + } +} + +void test_same_type_comparison() { + char l1 = 'a'; + if (l1 != 'q') { // COMPLIANT + } + if (l1 == 'b') { // COMPLIANT + } +} + +void test_char_traits_usage() { + using CT = std::char_traits; + char l1 = 'a'; + if (CT::eq(l1, 'q')) { // COMPLIANT + } + auto l2 = CT::to_int_type('a'); // COMPLIANT + auto l3 = static_cast('a'); // NON_COMPLIANT +} + +void test_optional_comparison() { + std::optional l1; + if (l1 == 'r') { // COMPLIANT + } +} + +void test_unevaluated_operand() { + decltype('s' + 't') l1; // COMPLIANT + static_assert('x' > 0); // NON_COMPLIANT + sizeof('x'); // COMPLIANT +} + +void test_range_check_non_compliant() { + char l1 = 'a'; + if ((l1 >= '0') && (l1 <= '9')) { // NON_COMPLIANT + } +} + +void test_range_check_compliant() { + using CT = std::char_traits; + char l1 = 'a'; + if (!CT::lt(l1, '0') && !CT::lt('9', l1)) { // COMPLIANT + } +} + +void test_isdigit_non_compliant() { + char l1 = 'a'; + if (0 == std::isdigit(l1)) { // NON_COMPLIANT + } +} + +void test_isdigit_compliant() { + char l1 = 'a'; + if (std::isdigit(l1, std::locale{})) { // COMPLIANT + } +} + +void test_stream_conversion() { + std::istream &l1 = std::cin; + auto l2 = l1.get(); + using CT = std::char_traits; + if (CT::not_eof(l2)) { + char l3 = l2; // NON_COMPLIANT + char l4 = CT::to_char_type(l2); // COMPLIANT + } +} + +void test_explicit_cast() { + char l1 = static_cast(65); // NON_COMPLIANT + int l2 = static_cast('A'); // NON_COMPLIANT +} + +void test_function_parameter_conversion() { + auto f1 = [](int l1) {}; + char l2 = 'x'; + f1(l2); // NON_COMPLIANT +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected b/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected new file mode 100644 index 0000000000..3022ea3923 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected @@ -0,0 +1,49 @@ +| test.cpp:14:3:14:6 | s32a | Bitwise operator '&' requires unsigned numeric operands, but the left operand has type 'int32_t'. | +| test.cpp:14:9:14:12 | s32b | Bitwise operator '&' requires unsigned numeric operands, but the right operand has type 'int32_t'. | +| test.cpp:15:3:15:6 | s32a | Bitwise operator '\|' requires unsigned numeric operands, but the left operand has type 'int32_t'. | +| test.cpp:15:10:15:13 | s32b | Bitwise operator '\|' requires unsigned numeric operands, but the right operand has type 'int32_t'. | +| test.cpp:16:3:16:6 | s32a | Bitwise operator '^' requires unsigned numeric operands, but the left operand has type 'int32_t'. | +| test.cpp:16:10:16:13 | s32b | Bitwise operator '^' requires unsigned numeric operands, but the right operand has type 'int32_t'. | +| test.cpp:18:3:18:6 | s32a | Bitwise operator '&' requires unsigned numeric operands, but the left operand has type 'int32_t'. | +| test.cpp:19:10:19:13 | s32b | Bitwise operator '\|' requires unsigned numeric operands, but the right operand has type 'int32_t'. | +| test.cpp:30:3:30:5 | s32 | Bitwise operator '&=' requires unsigned numeric operands, but the left operand has type 'int32_t'. | +| test.cpp:30:10:30:15 | 65535 | Bitwise operator '&=' requires unsigned numeric operands, but the right operand has type 'int'. | +| test.cpp:31:3:31:5 | s32 | Bitwise operator '\|=' requires unsigned numeric operands, but the left operand has type 'int32_t'. | +| test.cpp:31:10:31:15 | 4096 | Bitwise operator '\|=' requires unsigned numeric operands, but the right operand has type 'int'. | +| test.cpp:32:3:32:5 | s32 | Bitwise operator '^=' requires unsigned numeric operands, but the left operand has type 'int32_t'. | +| test.cpp:32:10:32:15 | 21845 | Bitwise operator '^=' requires unsigned numeric operands, but the right operand has type 'int'. | +| test.cpp:42:4:42:6 | s32 | Bit complement operator '~' requires unsigned operand, but has type 'int32_t'. | +| test.cpp:54:3:54:3 | 1 | Shift operator '<<' requires unsigned left operand, but has type 'int'. | +| test.cpp:55:3:55:5 | s32 | Shift operator '<<' requires unsigned left operand, but has type 'int32_t'. | +| test.cpp:63:4:63:11 | ... + ... | Shift operator '<<' requires unsigned left operand, but has type 'int'. | +| test.cpp:74:10:74:11 | s8 | Shift operator '<<' requires unsigned right operand, but has type 'int8_t'. | +| test.cpp:75:10:75:11 | s8 | Shift operator '>>' requires unsigned right operand, but has type 'int8_t'. | +| test.cpp:85:10:85:11 | 32 | Shift operator '<<' shifts by 32 which is not within the valid range 0..31. | +| test.cpp:86:10:86:11 | 64 | Shift operator '<<' shifts by 64 which is not within the valid range 0..31. | +| test.cpp:87:10:87:11 | 32 | Shift operator '>>' shifts by 32 which is not within the valid range 0..31. | +| test.cpp:93:10:93:11 | - ... | Shift operator '<<' shifts by -1 which is not within the valid range 0..31. | +| test.cpp:94:10:94:11 | - ... | Shift operator '<<' shifts by -5 which is not within the valid range 0..31. | +| test.cpp:95:10:95:11 | - ... | Shift operator '>>' shifts by -1 which is not within the valid range 0..31. | +| test.cpp:96:10:96:11 | - ... | Shift operator '>>' shifts by -3 which is not within the valid range 0..31. | +| test.cpp:115:3:115:5 | s32 | Shift operator '<<=' requires unsigned left operand, but has type 'int32_t'. | +| test.cpp:116:3:116:5 | s32 | Shift operator '>>=' requires unsigned left operand, but has type 'int32_t'. | +| test.cpp:117:3:117:5 | s32 | Shift operator '<<=' requires unsigned left operand, but has type 'int32_t'. | +| test.cpp:118:3:118:5 | s32 | Shift operator '>>=' requires unsigned left operand, but has type 'int32_t'. | +| test.cpp:121:11:121:12 | s8 | Shift operator '<<=' requires unsigned right operand, but has type 'int8_t'. | +| test.cpp:122:11:122:12 | s8 | Shift operator '>>=' requires unsigned right operand, but has type 'int8_t'. | +| test.cpp:125:11:125:12 | 32 | Shift operator '<<=' shifts by 32 which is not within the valid range 0..31. | +| test.cpp:126:11:126:12 | 64 | Shift operator '<<=' shifts by 64 which is not within the valid range 0..31. | +| test.cpp:127:11:127:12 | 32 | Shift operator '>>=' shifts by 32 which is not within the valid range 0..31. | +| test.cpp:130:11:130:12 | - ... | Shift operator '<<=' shifts by -1 which is not within the valid range 0..31. | +| test.cpp:131:11:131:12 | - ... | Shift operator '<<=' shifts by -5 which is not within the valid range 0..31. | +| test.cpp:132:11:132:12 | - ... | Shift operator '>>=' shifts by -1 which is not within the valid range 0..31. | +| test.cpp:133:11:133:12 | - ... | Shift operator '>>=' shifts by -3 which is not within the valid range 0..31. | +| test.cpp:143:3:143:3 | 1 | Shift operator '<<' requires unsigned left operand, but has type 'int'. | +| test.cpp:144:3:144:3 | 2 | Shift operator '<<' requires unsigned left operand, but has type 'int'. | +| test.cpp:145:3:145:3 | 4 | Shift operator '<<' requires unsigned left operand, but has type 'int'. | +| test.cpp:146:3:146:3 | 8 | Shift operator '<<' requires unsigned left operand, but has type 'int'. | +| test.cpp:150:3:150:5 | 1 | Shift operator '<<' requires unsigned left operand, but has type 'long long'. | +| test.cpp:154:3:154:25 | 4611686018427387904 | Shift operator '<<' requires unsigned left operand, but has type 'long long'. | +| test.cpp:156:3:156:12 | 1073741824 | Shift operator '<<' requires unsigned left operand, but has type 'int'. | +| test.cpp:162:3:162:5 | s32 | Shift operator '<<' requires unsigned left operand, but has type 'int32_t'. | +| test.cpp:170:3:170:5 | s32 | Shift operator '>>' requires unsigned left operand, but has type 'int32_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.qlref b/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.qlref new file mode 100644 index 0000000000..df3c14d752 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.qlref @@ -0,0 +1 @@ +rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-4/test.cpp b/cpp/misra/test/rules/RULE-7-0-4/test.cpp new file mode 100644 index 0000000000..110c50070e --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-4/test.cpp @@ -0,0 +1,171 @@ +#include +#include + +void test_binary_bitwise_operators_unsigned_operands() { + std::uint32_t u32a = 0x12345678U; + std::uint32_t u32b = 0x87654321U; + std::int32_t s32a = 0x12345678; + std::int32_t s32b = 0x87654321; + + u32a &u32b; // COMPLIANT + u32a | u32b; // COMPLIANT + u32a ^ u32b; // COMPLIANT + + s32a &s32b; // NON_COMPLIANT + s32a | s32b; // NON_COMPLIANT + s32a ^ s32b; // NON_COMPLIANT + + s32a &u32b; // NON_COMPLIANT + u32a | s32b; // NON_COMPLIANT +} + +void test_compound_assignment_bitwise_operators() { + std::uint32_t u32 = 0x12345678U; + std::int32_t s32 = 0x12345678; + + u32 &= 0xFFFFU; // COMPLIANT + u32 |= 0x1000U; // COMPLIANT + u32 ^= 0x5555U; // COMPLIANT + + s32 &= 0xFFFF; // NON_COMPLIANT + s32 |= 0x1000; // NON_COMPLIANT + s32 ^= 0x5555; // NON_COMPLIANT +} + +void test_bit_complement_operator() { + std::uint32_t u32 = 0x12345678U; + std::uint8_t u8 = 0x55U; + std::int32_t s32 = 0x12345678; + + ~u32; // COMPLIANT + ~u8; // COMPLIANT + ~s32; // NON_COMPLIANT +} + +void test_shift_operators_left_operand_type() { + std::uint32_t u32 = 0x12345678U; + std::uint8_t u8 = 2U; + std::int32_t s32 = 0x12345678; + + 1U << u8; // COMPLIANT + 1U << 31; // COMPLIANT + u32 << 2U; // COMPLIANT + + 1 << u8; // NON_COMPLIANT + s32 << 2U; // NON_COMPLIANT +} + +void test_shift_operators_with_promotion() { + std::uint8_t u8 = 1U; + std::uint16_t u16 = 2U; + + static_cast(u8 + u16) << 2U; // COMPLIANT + (u8 + u16) << 2U; // NON_COMPLIANT +} + +void test_shift_operators_right_operand_unsigned() { + std::uint32_t u32 = 0x12345678U; + std::uint8_t u8 = 2U; + std::int8_t s8 = 2; + + u32 << u8; // COMPLIANT + u32 >> u8; // COMPLIANT + + u32 << s8; // NON_COMPLIANT + u32 >> s8; // NON_COMPLIANT +} + +void test_shift_operators_right_operand_constant_range() { + std::uint32_t u32 = 0x12345678U; + + u32 << 0; // COMPLIANT + u32 << 31; // COMPLIANT + u32 >> 15; // COMPLIANT + + u32 << 32; // NON_COMPLIANT + u32 << 64; // NON_COMPLIANT + u32 >> 32; // NON_COMPLIANT +} + +void test_shift_operators_negative_right_operand() { + std::uint32_t u32 = 0x12345678U; + + u32 << -1; // NON_COMPLIANT + u32 << -5; // NON_COMPLIANT + u32 >> -1; // NON_COMPLIANT + u32 >> -3; // NON_COMPLIANT +} + +void test_compound_assignment_shift_operators() { + std::uint32_t u32 = 0x12345678U; + std::uint8_t u8 = 2U; + std::int32_t s32 = 0x12345678; + std::int8_t s8 = 2; + + // Unsigned left operand with unsigned right operand + u32 <<= u8; // COMPLIANT + u32 >>= u8; // COMPLIANT + + // Unsigned left operand with constant right operand in valid range + u32 <<= 0; // COMPLIANT + u32 <<= 31; // COMPLIANT + u32 >>= 15; // COMPLIANT + + // Signed left operand + s32 <<= u8; // NON_COMPLIANT + s32 >>= u8; // NON_COMPLIANT + s32 <<= 2; // NON_COMPLIANT + s32 >>= 2; // NON_COMPLIANT + + // Unsigned left operand with signed right operand + u32 <<= s8; // NON_COMPLIANT + u32 >>= s8; // NON_COMPLIANT + + // Right operand out of range + u32 <<= 32; // NON_COMPLIANT + u32 <<= 64; // NON_COMPLIANT + u32 >>= 32; // NON_COMPLIANT + + // Negative right operand + u32 <<= -1; // NON_COMPLIANT + u32 <<= -5; // NON_COMPLIANT + u32 >>= -1; // NON_COMPLIANT + u32 >>= -3; // NON_COMPLIANT +} + +void test_exception_signed_constant_left_operand_exception() { + // Exception cases for signed constant expressions + 1 << 30; // COMPLIANT + 2 << 29; // COMPLIANT + 4 << 28; // COMPLIANT + 8 << 27; // COMPLIANT + + 1 << 31; // NON_COMPLIANT + 2 << 30; // NON_COMPLIANT + 4 << 29; // NON_COMPLIANT + 8 << 28; // NON_COMPLIANT + + 1LL << 31; // COMPLIANT - 64 bit type + 1LL << 62; // COMPLIANT - 64 bit type + 1LL << 63; // NON_COMPLIANT - 64 bit type + 0x1000'0000'0000'0000LL << 2; // COMPLIANT + 0x2000'0000'0000'0000LL << 1; // COMPLIANT + + 0x4000'0000'0000'0000LL << 1; // NON_COMPLIANT + + 0x40000000 << 1; // NON_COMPLIANT +} + +void test_exception_non_constant_signed_operand() { + std::int32_t s32 = 1; + + s32 << 2; // NON_COMPLIANT +} + +void test_right_shift_signed_operands() { + std::uint32_t u32 = 0x80000000U; + std::int32_t s32 = -1; + + u32 >> 1U; // COMPLIANT + s32 >> 1U; // NON_COMPLIANT +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected new file mode 100644 index 0000000000..7603386f12 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected @@ -0,0 +1,110 @@ +| test.cpp:22:3:22:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:22:8:22:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:23:3:23:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:23:7:23:8 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:24:3:24:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:24:8:24:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:25:3:25:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:25:8:25:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:26:3:26:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:26:8:26:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:27:3:27:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:27:7:27:8 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:28:3:28:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:28:8:28:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:29:3:29:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:29:8:29:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:43:3:43:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:43:9:43:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:44:3:44:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:44:9:44:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:45:3:45:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:45:9:45:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:46:3:46:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:46:9:46:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:47:3:47:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:47:9:47:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:48:3:48:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:48:9:48:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:49:3:49:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:49:9:49:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:50:3:50:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:50:9:50:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:62:3:62:4 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:63:3:63:4 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:64:3:64:4 | l2 | Integer promotion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:65:3:65:4 | l2 | Integer promotion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:68:9:68:10 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:69:9:69:10 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:73:3:73:4 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:74:3:74:4 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:75:3:75:4 | l2 | Integer promotion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:76:3:76:4 | l2 | Integer promotion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:79:10:79:11 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:80:10:80:11 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:91:3:91:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:92:3:92:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:93:3:93:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:94:3:94:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:95:3:95:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:96:3:96:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:98:3:98:4 | l3 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:98:8:98:9 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:99:3:99:4 | l3 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:99:8:99:9 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:109:8:109:9 | l2 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:109:13:109:14 | l4 | Integer promotion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:117:4:117:5 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:119:4:119:5 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:121:4:121:5 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:164:8:164:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:165:8:165:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:166:7:166:8 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:167:8:167:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:168:8:168:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:169:7:169:8 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:170:8:170:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:171:8:171:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:173:8:173:9 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:174:8:174:9 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:175:7:175:8 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:177:8:177:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:178:8:178:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:179:9:179:10 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:199:9:199:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | +| test.cpp:199:9:199:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | +| test.cpp:200:9:200:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | +| test.cpp:200:9:200:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | +| test.cpp:201:9:201:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | +| test.cpp:201:9:201:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | +| test.cpp:270:3:270:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:270:8:270:9 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:271:3:271:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:271:7:271:8 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:272:3:272:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:272:7:272:8 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:273:3:273:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:273:8:273:9 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:274:3:274:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:274:8:274:9 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:275:3:275:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:275:8:275:9 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:278:3:278:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:278:8:278:9 | l7 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:279:3:279:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:279:7:279:8 | l7 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:280:3:280:4 | l7 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:280:8:280:9 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:286:4:286:5 | l3 | Integer promotion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:287:4:287:5 | l3 | Integer promotion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:288:4:288:5 | l3 | Integer promotion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:294:3:294:31 | static_cast... | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:295:7:296:46 | static_cast... | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:299:3:299:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:299:8:299:9 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:300:3:300:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:300:9:300:10 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:301:3:301:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:301:9:301:10 | l7 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:304:3:304:4 | l3 | Integer promotion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:305:3:305:4 | l3 | Integer promotion from 'UnscopedEnumExplicit' to 'int' changes signedness. | diff --git a/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.qlref b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.qlref new file mode 100644 index 0000000000..ae020269b9 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.qlref @@ -0,0 +1 @@ +rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-5/test.cpp b/cpp/misra/test/rules/RULE-7-0-5/test.cpp new file mode 100644 index 0000000000..2571f725fd --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-5/test.cpp @@ -0,0 +1,330 @@ +#include + +// Global variables for testing +std::uint8_t g1 = 5; +std::uint8_t g2 = 10; +std::uint16_t g3 = 100; +std::uint32_t g4 = 1000; +std::int8_t g5 = -5; +std::int32_t g6 = -1000; +float g7 = 3.14f; + +constexpr std::int32_t f1(std::int32_t i) { return i * i; } + +void test_binary_arithmetic_operations() { + std::uint8_t l1 = 5; + std::uint8_t l2 = 10; + std::uint16_t l3 = 100; + std::uint32_t l4 = 1000; + std::int8_t l5 = -5; + std::int32_t l6 = -1000; + + l1 + l2; // NON_COMPLIANT - u8 + u8 -> signed int + l1 *l2; // NON_COMPLIANT - u8 * u8 -> signed int + l1 - l2; // NON_COMPLIANT - u8 - u8 -> signed int + l1 / l2; // NON_COMPLIANT - u8 / u8 -> signed int + l1 % l2; // NON_COMPLIANT - u8 % u8 -> signed int + l1 &l2; // NON_COMPLIANT - u8 & u8 -> signed int + l1 | l2; // NON_COMPLIANT - u8 | u8 -> signed int + l1 ^ l2; // NON_COMPLIANT - u8 ^ u8 -> signed int + + static_cast(l1) + l2; // COMPLIANT - l2 -> unsigned int + l1 + static_cast(l2); // COMPLIANT - l1 -> unsigned int + + l6 *l5; // COMPLIANT - l5 -> signed int + l4 / l1; // COMPLIANT - l1 -> unsigned int +} + +void test_assignment_operations() { + std::uint8_t l1 = 5; + std::uint8_t l2 = 10; + std::uint32_t l3 = 1000; + + l1 += l2; // NON_COMPLIANT - same as l1 + l2 + l1 -= l2; // NON_COMPLIANT - same as l1 - l2 + l1 *= l2; // NON_COMPLIANT - same as l1 * l2 + l1 /= l2; // NON_COMPLIANT - same as l1 / l2 + l1 %= l2; // NON_COMPLIANT - same as l1 % l2 + l1 &= l2; // NON_COMPLIANT - same as l1 & l2 + l1 |= l2; // NON_COMPLIANT - same as l1 | l2 + l1 ^= l2; // NON_COMPLIANT - same as l1 ^ l2 + + l1 += static_cast(l2); // COMPLIANT - l1 -> unsigned int + l1 += l3; // COMPLIANT - l1 -> unsigned int +} + +void test_shift_operations() { + std::uint8_t l1 = 5; + std::uint16_t l2 = 100; + std::uint32_t l3 = 1000; + std::int16_t l4; + + l1 << 2; // NON_COMPLIANT - l1 -> signed int + l1 >> 1; // NON_COMPLIANT - l1 -> signed int + l2 << 2; // NON_COMPLIANT - l2 -> signed int + l2 >> 1; // NON_COMPLIANT - l2 -> signed int + l3 << 2; // COMPLIANT + l3 >> 1; // COMPLIANT + l3 << l1; // NON_COMPLIANT - l1 -> signed int + l3 >> l1; // NON_COMPLIANT - l1 -> signed int + l3 << l4; // COMPLIANT + l3 >> l4; // COMPLIANT + + l1 <<= 2; // NON_COMPLIANT - l1 -> signed int + l1 >>= 1; // NON_COMPLIANT - l1 -> signed int + l2 <<= 2; // NON_COMPLIANT - l2 -> signed int + l2 >>= 1; // NON_COMPLIANT - l2 -> signed int + l3 <<= 2; // COMPLIANT + l3 >>= 1; // COMPLIANT + l3 <<= l1; // NON_COMPLIANT - l1 -> signed int + l3 >>= l1; // NON_COMPLIANT - l1 -> signed int + l3 <<= l4; // COMPLIANT + l3 >>= l4; // COMPLIANT +} + +void test_comparison_operations() { + std::int32_t l1 = -1000; + std::uint32_t l2 = 1000; + std::uint8_t l3 = 5; + std::uint16_t l4 = 100; + + l1 > l2; // NON_COMPLIANT - l1 -> unsigned int + l1 < l2; // NON_COMPLIANT - l1 -> unsigned int + l1 >= l2; // NON_COMPLIANT - l1 -> unsigned int + l1 <= l2; // NON_COMPLIANT - l1 -> unsigned int + l1 == l2; // NON_COMPLIANT - l1 -> unsigned int + l1 != l2; // NON_COMPLIANT - l1 -> unsigned int + + l3 > l4; // NON_COMPLIANT - l3 and l4 -> signed int + l3 < l4; // NON_COMPLIANT - l3 and l4 -> signed int +} + +void test_conditional_operator() { + bool l1 = true; + std::uint8_t l2 = 5; + std::uint8_t l3 = 10; + std::uint16_t l4 = 100; + + l1 ? l2 : l3; // COMPLIANT - no conversion + l1 ? l2 : l4; // NON_COMPLIANT - l2 and l4 -> signed int +} + +void test_unary_operations() { + std::uint8_t l1 = 5; + std::uint32_t l2 = 1000; + std::int8_t l3 = -5; + + ~l1; // NON_COMPLIANT - l1 -> signed int + ~l2; // COMPLIANT + -l1; // NON_COMPLIANT - l1 -> signed int + -l3; // COMPLIANT - l3 is signed + +l1; // NON_COMPLIANT - l1 -> signed int +} + +void test_increment_decrement() { + std::uint8_t l1 = 5; + std::uint16_t l2 = 100; + + l1++; // COMPLIANT - rule does not apply + ++l1; // COMPLIANT - rule does not apply + l1--; // COMPLIANT - rule does not apply + --l1; // COMPLIANT - rule does not apply + l2++; // COMPLIANT - rule does not apply + ++l2; // COMPLIANT - rule does not apply +} + +void test_array_subscript() { + int l1[10]; + std::uint8_t l2 = 5; + + l1[l2]; // COMPLIANT - rule does not apply +} + +void test_logical_operators() { + std::uint8_t l1 = 5; + std::uint8_t l2 = 10; + std::uint16_t l3 = 100; + std::int8_t l4 = -5; + bool l5 = true; + + l1 &&l2; // COMPLIANT - rule does not apply to logical operators + l1 || l2; // COMPLIANT - rule does not apply to logical operators + l1 &&l3; // COMPLIANT - rule does not apply to logical operators + l4 &&l1; // COMPLIANT - rule does not apply to logical operators + l5 &&l1; // COMPLIANT - rule does not apply to logical operators + l1 &&l5; // COMPLIANT - rule does not apply to logical operators +} + +void test_mixed_signed_unsigned_arithmetic() { + std::int8_t l1 = -5; + std::uint8_t l2 = 10; + std::int16_t l3 = -100; + std::uint16_t l4 = 200; + + l1 + l2; // NON_COMPLIANT - l1 and l2 -> signed int + l1 - l2; // NON_COMPLIANT - l1 and l2 -> signed int + l1 *l2; // NON_COMPLIANT - l1 and l2 -> signed int + l1 / l2; // NON_COMPLIANT - l1 and l2 -> signed int + l1 % l2; // NON_COMPLIANT - l1 and l2 -> signed int + l1 &l2; // NON_COMPLIANT - l1 and l2 -> signed int + l1 | l2; // NON_COMPLIANT - l1 and l2 -> signed int + l1 ^ l2; // NON_COMPLIANT - l1 and l2 -> signed int + + l3 + l4; // NON_COMPLIANT - l3 and l4 -> signed int + l3 - l4; // NON_COMPLIANT - l3 and l4 -> signed int + l3 *l4; // NON_COMPLIANT - l3 and l4 -> signed int + + l1 < l2; // NON_COMPLIANT - l1 and l2 -> signed int + l1 > l2; // NON_COMPLIANT - l1 and l2 -> signed int + l3 == l4; // NON_COMPLIANT - l3 and l4 -> signed int +} + +void test_exception_compile_time_constants() { + std::uint32_t l1 = 1000; + float l2 = 3.14f; + std::int32_t l3 = 5; + + l1 - 1; // COMPLIANT - exception #1 + l1 + 42; // COMPLIANT - exception #1 + l2 += 1; // COMPLIANT - exception #2 + l2 += 0x10001; // COMPLIANT - exception #2 + l3 + f1(10); // COMPLIANT - exception #1 + l2 + f1(10); // COMPLIANT - exception #2 +} + +void test_floating_point_conversions() { + float l1; + std::uint32_t l2; + + l1 += l2; // NON_COMPLIANT - l2 -> floating + l1 *= l2; // NON_COMPLIANT - l2 -> floating + l1 /= l2; // NON_COMPLIANT - l2 -> floating +} + +void test_pointer_arithmetic() { + int l1[10]; + std::uint8_t l2 = 5; + std::uint16_t l3 = 2; + std::int8_t l4 = 3; + std::int32_t l5 = 1; + int *l6 = l1; + + l1 + l2; // COMPLIANT - rule does not apply to pointer arithmetic + l1 + l3; // COMPLIANT - rule does not apply to pointer arithmetic + l1 + l4; // COMPLIANT - rule does not apply to pointer arithmetic + l1 + l5; // COMPLIANT - rule does not apply to pointer arithmetic + l6 + l2; // COMPLIANT - rule does not apply to pointer arithmetic + l6 + l3; // COMPLIANT - rule does not apply to pointer arithmetic + + l1 - l2; // COMPLIANT - rule does not apply to pointer arithmetic + l6 - l3; // COMPLIANT - rule does not apply to pointer arithmetic + + l6 - l1; // COMPLIANT - rule does not apply to pointer arithmetic +} + +void test_pointer_assignment_arithmetic() { + int l1[10]; + std::uint8_t l2 = 5; + std::uint16_t l3 = 2; + std::int8_t l4 = 3; + int *l5 = l1; + + l5 += l2; // COMPLIANT - rule does not apply to pointer arithmetic + l5 += l3; // COMPLIANT - rule does not apply to pointer arithmetic + l5 += l4; // COMPLIANT - rule does not apply to pointer arithmetic + + l5 -= l2; // COMPLIANT - rule does not apply to pointer arithmetic + l5 -= l3; // COMPLIANT - rule does not apply to pointer arithmetic + l5 -= l4; // COMPLIANT - rule does not apply to pointer arithmetic +} + +// Enum types for testing +enum UnscopedEnum { VALUE1, VALUE2, VALUE3 }; +enum class ScopedEnum { VALUE1, VALUE2, VALUE3 }; +enum UnscopedEnumExplicit : std::uint8_t { + EXPLICIT_VALUE1 = 1, + EXPLICIT_VALUE2 = 2 +}; +enum class ScopedEnumExplicit : std::uint8_t { + EXPLICIT_VALUE1 = 1, + EXPLICIT_VALUE2 = 2 +}; + +void test_enum_types() { + UnscopedEnum l1 = VALUE1; + UnscopedEnum l2 = VALUE2; + UnscopedEnumExplicit l3 = EXPLICIT_VALUE1; + UnscopedEnumExplicit l4 = EXPLICIT_VALUE2; + ScopedEnum l5 = ScopedEnum::VALUE1; + ScopedEnumExplicit l6 = ScopedEnumExplicit::EXPLICIT_VALUE1; + std::uint8_t l7 = 5; + std::uint32_t l8 = 10; + + // Unscoped enum without explicit underlying type - not considered numeric + // type + l1 + l2; // COMPLIANT - rule does not apply + l1 *l2; // COMPLIANT - rule does not apply + l1 &l2; // COMPLIANT - rule does not apply + + // Unscoped enum with explicit underlying type - considered numeric type + l3 + l4; // NON_COMPLIANT - uint8_t + uint8_t -> signed int + l3 *l4; // NON_COMPLIANT - uint8_t * uint8_t -> signed int + l3 &l4; // NON_COMPLIANT - uint8_t & uint8_t -> signed int + l3 - l4; // NON_COMPLIANT - uint8_t - uint8_t -> signed int + l3 | l4; // NON_COMPLIANT - uint8_t | uint8_t -> signed int + l3 ^ l4; // NON_COMPLIANT - uint8_t ^ uint8_t -> signed int + + // Mixed enum and integer arithmetic + l3 + l7; // NON_COMPLIANT - uint8_t + uint8_t -> signed int + l3 *l7; // NON_COMPLIANT - uint8_t * uint8_t -> signed int + l7 - l3; // NON_COMPLIANT - uint8_t - uint8_t -> signed int + + l3 + l8; // COMPLIANT - uint8_t -> signed int (matches l8) + l8 *l3; // COMPLIANT - uint8_t -> signed int (matches l8) + + // Unary operations on enum with explicit underlying type + ~l3; // NON_COMPLIANT - uint8_t -> signed int + -l3; // NON_COMPLIANT - uint8_t -> signed int + +l3; // NON_COMPLIANT - uint8_t -> signed int + + // Scoped enums - not considered numeric type regardless of underlying type + static_cast(l5) + + static_cast(ScopedEnum::VALUE2); // COMPLIANT - rule does not apply + // to explicit casts + static_cast(l6) + // NON_COMPLIANT + static_cast( // NON_COMPLIANT + ScopedEnumExplicit::EXPLICIT_VALUE2); + + // Comparison operations with enum + l3 > l4; // NON_COMPLIANT - uint8_t > uint8_t -> signed int + l3 == l4; // NON_COMPLIANT - uint8_t == uint8_t -> signed int + l3 != l7; // NON_COMPLIANT - uint8_t != uint8_t -> signed int + + // Shift operations with enum + l3 << 1; // NON_COMPLIANT - uint8_t -> signed int + l3 >> 1; // NON_COMPLIANT - uint8_t -> signed int + + // Conditional operator with enum + true ? l3 : l4; // COMPLIANT - same types, no conversion + true ? l3 : l8; // COMPLIANT - same underlying types, no conversion +} + +#define A 100LL // intmax_t +#define B 200LL // intmax_t +#define C 300ULL // uintmax_t +#define D 400ULL // uintmax_t + +#if A + B > 250 // COMPLIANT - both intmax_t, no conversion +; +#elif C + D < 800 // COMPLIANT - both uintmax_t, no conversion +; +#endif + +#define SIGNED_MAX 9223372036854775807LL // intmax_t +#define UNSIGNED_VAL 1ULL // uintmax_t + +#if SIGNED_MAX + UNSIGNED_VAL > 0 // NON_COMPLIANT[FALSE_NEGATIVE] +// intmax_t + uintmax_t → both converted to uintmax_t +// This changes SIGNED_MAX from signed to unsigned +; +#endif diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected new file mode 100644 index 0000000000..068608c126 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -0,0 +1,325 @@ +| test.cpp:36:8:36:11 | 300 | Assignment between incompatible numeric types from 'unsigned int' to 'uint8_t'. | +| test.cpp:39:7:39:10 | 0.0 | Assignment between incompatible numeric types from 'float' to 'double'. | +| test.cpp:45:8:45:9 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | +| test.cpp:46:8:46:9 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int8_t'. | +| test.cpp:51:8:51:10 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test.cpp:52:9:52:11 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'uint16_t'. | +| test.cpp:57:7:57:9 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | +| test.cpp:58:9:58:9 | f | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test.cpp:95:12:95:13 | m1 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test.cpp:96:12:96:13 | m2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint64_t'. | +| test.cpp:97:13:97:14 | m1 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test.cpp:98:13:98:14 | m2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint64_t'. | +| test.cpp:103:9:103:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint32_t'. | +| test.cpp:104:9:104:12 | (...) | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test.cpp:105:9:105:37 | static_cast... | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test.cpp:110:8:110:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:111:21:111:27 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | +| test.cpp:134:11:134:11 | 4 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test.cpp:137:11:137:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test.cpp:141:11:141:13 | 256 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test.cpp:143:11:143:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test.cpp:144:11:144:13 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned char'. | +| test.cpp:148:11:148:13 | 512 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test.cpp:149:11:149:15 | 65535 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test.cpp:150:11:150:15 | 65536 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test.cpp:153:11:153:13 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | +| test.cpp:157:11:157:15 | 65536 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test.cpp:160:11:160:13 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | +| test.cpp:164:11:164:16 | 131072 | Assignment between incompatible numeric types from 'int' to 'unsigned int'. | +| test.cpp:168:11:168:13 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'unsigned int'. | +| test.cpp:172:11:172:22 | 4294967296 | Assignment between incompatible numeric types from 'unsigned long' to 'unsigned int'. | +| test.cpp:176:11:176:13 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'unsigned int'. | +| test.cpp:180:11:180:21 | 8589934592 | Assignment between incompatible numeric types from 'long' to 'unsigned long'. | +| test.cpp:193:11:193:12 | 16 | Assignment between incompatible numeric types from 'int32_t' to 'signed char'. | +| test.cpp:194:11:194:13 | - ... | Assignment between incompatible numeric types from 'int' to 'signed char'. | +| test.cpp:196:11:196:13 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'signed char'. | +| test.cpp:200:11:200:14 | 2048 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test.cpp:201:11:201:15 | - ... | Assignment between incompatible numeric types from 'int' to 'short'. | +| test.cpp:204:11:204:13 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test.cpp:208:12:208:22 | 134217728 | Assignment between incompatible numeric types from 'long long' to 'int'. | +| test.cpp:209:12:209:23 | - ... | Assignment between incompatible numeric types from 'long long' to 'int'. | +| test.cpp:224:8:224:9 | l1 | Assignment between incompatible numeric types from 'Colour' to 'uint8_t'. | +| test.cpp:234:6:234:8 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'int64_t'. | +| test.cpp:237:6:237:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:239:6:239:7 | l1 | Assignment between incompatible numeric types from 'int' to 'int32_t'. | +| test.cpp:252:6:252:7 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. | +| test.cpp:261:6:261:6 | 2 | Assignment between incompatible numeric types from 'int' to 'long'. | +| test.cpp:269:14:269:15 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int'. | +| test.cpp:289:6:289:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'size_t'. | +| test.cpp:294:12:294:14 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | +| test.cpp:313:9:313:10 | 42 | Assignment between incompatible numeric types from 'int' to 'long'. | +| test.cpp:339:12:339:13 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. | +| test.cpp:340:12:340:13 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. | +| test.cpp:342:32:342:33 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. | +| test.cpp:362:25:362:27 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned long'. | +| test.cpp:374:19:374:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | +| test.cpp:379:10:379:12 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:412:8:412:9 | l6 | Assignment between incompatible numeric types from 'uint32_t &' to 'uint8_t'. | +| test.cpp:413:8:413:9 | l7 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | +| test.cpp:414:9:414:10 | l8 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | +| test.cpp:425:6:425:7 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int64_t'. | +| test.cpp:426:6:426:7 | l4 | Assignment between incompatible numeric types from 'uint16_t &' to 'int32_t'. | +| test.cpp:437:8:437:9 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int8_t'. | +| test.cpp:438:8:438:9 | l4 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | +| test.cpp:451:9:451:10 | l4 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | +| test.cpp:452:7:452:8 | l5 | Assignment between incompatible numeric types from 'double &' to 'float'. | +| test.cpp:453:7:453:8 | l6 | Assignment between incompatible numeric types from 'int32_t &' to 'float'. | +| test.cpp:464:8:464:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:482:7:482:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. | +| test.cpp:485:7:485:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. | +| test.cpp:534:12:534:13 | l1 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | +| test.cpp:535:12:535:13 | l1 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | +| test.cpp:537:12:537:13 | l2 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. | +| test.cpp:538:12:538:13 | l2 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. | +| test.cpp:558:12:558:14 | 300 | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:559:12:559:16 | 70000 | Assignment between incompatible numeric types from 'int' to 'uint16_t'. | +| test.cpp:560:12:560:27 | 4294967296 | Assignment between incompatible numeric types from 'unsigned long long' to 'uint32_t'. | +| test.cpp:561:12:561:14 | 200 | Assignment between incompatible numeric types from 'int' to 'int8_t'. | +| test.cpp:562:12:562:16 | 40000 | Assignment between incompatible numeric types from 'int' to 'int16_t'. | +| test.cpp:563:12:563:26 | 4294967296 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | +| test.cpp:564:12:564:14 | 1.0 | Assignment between incompatible numeric types from 'double' to 'float'. | +| test.cpp:565:12:565:15 | 1.0 | Assignment between incompatible numeric types from 'float' to 'double'. | +| test.cpp:570:12:570:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:571:12:571:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint16_t'. | +| test.cpp:572:12:572:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint32_t'. | +| test.cpp:574:12:574:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int16_t'. | +| test.cpp:575:12:575:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int32_t'. | +| test.cpp:576:12:576:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'float'. | +| test.cpp:577:12:577:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'double'. | +| test.cpp:607:9:607:37 | static_cast... | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | +| test_aggregate.cpp:29:22:29:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_aggregate.cpp:31:26:31:28 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | +| test_aggregate.cpp:33:31:33:33 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_aggregate.cpp:35:22:35:24 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | +| test_aggregate.cpp:38:22:38:24 | 256 | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test_aggregate.cpp:38:27:38:31 | 65536 | Assignment between incompatible numeric types from 'int' to 'uint16_t'. | +| test_aggregate.cpp:39:22:39:33 | 2147483648 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | +| test_aggregate.cpp:51:22:51:24 | 300 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test_aggregate.cpp:51:27:51:29 | 400 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test_aggregate.cpp:51:32:51:34 | 500 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test_aggregate.cpp:52:22:52:23 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. | +| test_aggregate.cpp:52:26:52:27 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. | +| test_aggregate.cpp:52:30:52:31 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. | +| test_aggregate.cpp:53:22:53:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test_aggregate.cpp:53:27:53:29 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test_aggregate.cpp:53:32:53:34 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test_aggregate.cpp:58:26:58:28 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | +| test_aggregate.cpp:58:31:58:33 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | +| test_aggregate.cpp:58:38:58:40 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | +| test_aggregate.cpp:58:43:58:45 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | +| test_aggregate.cpp:59:26:59:27 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | +| test_aggregate.cpp:59:30:59:31 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | +| test_aggregate.cpp:60:26:60:27 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | +| test_aggregate.cpp:60:30:60:31 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | +| test_aggregate.cpp:76:8:76:10 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_aggregate.cpp:80:7:80:9 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. | +| test_aggregate.cpp:96:24:96:26 | 300 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test_aggregate.cpp:96:29:96:33 | 70000 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test_aggregate.cpp:96:36:96:39 | 5000 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test_aggregate.cpp:97:24:97:26 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test_aggregate.cpp:97:29:97:31 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | +| test_aggregate.cpp:97:34:97:36 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test_aggregate.cpp:107:28:107:30 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_member_pointers.cpp:25:12:25:14 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_member_pointers.cpp:26:12:26:14 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:27:12:27:14 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:28:12:28:14 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | +| test_member_pointers.cpp:32:13:32:15 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_member_pointers.cpp:33:13:33:15 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:34:13:34:15 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:35:13:35:15 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | +| test_member_pointers.cpp:42:12:42:14 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_member_pointers.cpp:43:12:43:14 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:44:12:44:14 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:45:12:45:14 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | +| test_member_pointers.cpp:49:13:49:15 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_member_pointers.cpp:50:13:50:15 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:51:13:51:15 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:52:13:52:15 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | +| test_member_pointers.cpp:58:11:58:13 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | +| test_member_pointers.cpp:60:11:60:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:66:11:66:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:67:11:67:13 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:82:6:82:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_member_pointers.cpp:83:6:83:8 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:84:6:84:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:85:6:85:8 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | +| test_member_pointers.cpp:90:6:90:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_member_pointers.cpp:91:6:91:8 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:92:6:92:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:93:6:93:8 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | +| test_member_pointers.cpp:97:7:97:9 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | +| test_member_pointers.cpp:100:7:100:9 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:106:41:106:43 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:107:41:107:43 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:125:12:125:14 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int64_t'. | +| test_member_pointers.cpp:126:12:126:14 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int64_t'. | +| test_member_pointers.cpp:127:12:127:14 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int64_t'. | +| test_operators.cpp:99:8:99:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:100:8:100:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:104:8:104:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:105:8:105:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:109:7:109:8 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:110:7:110:8 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:114:8:114:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:115:8:115:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:119:8:119:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:120:8:120:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:124:7:124:8 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:125:7:125:8 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:129:8:129:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:130:8:130:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:134:8:134:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:135:8:135:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:139:9:139:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:140:9:140:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:144:9:144:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:145:9:145:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:150:9:150:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:151:9:151:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:155:9:155:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:156:9:156:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:160:8:160:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:161:8:161:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:165:9:165:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:166:9:166:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:170:8:170:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:171:8:171:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:175:9:175:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:176:9:176:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:181:6:181:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:182:6:182:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:187:6:187:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:188:6:188:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:190:10:190:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:191:6:191:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:192:6:192:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:192:10:192:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:197:8:197:9 | l3 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | +| test_operators.cpp:198:8:198:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:199:8:199:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:203:9:203:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:204:9:204:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:208:9:208:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:209:9:209:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:213:9:213:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:214:9:214:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:218:9:218:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:219:9:219:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:223:9:223:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:224:9:224:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:228:9:228:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:229:9:229:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:233:9:233:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:234:9:234:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:238:9:238:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:239:9:239:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:243:10:243:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:244:10:244:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:248:10:248:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:249:10:249:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:254:3:254:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:255:3:255:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:259:3:259:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:260:3:260:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:264:3:264:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:265:3:265:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:277:8:277:12 | 42.0 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test_operators.cpp:292:8:292:10 | 42 | Assignment between incompatible numeric types from 'long' to 'int32_t'. | +| test_operators.cpp:293:8:293:11 | 42 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | +| test_operators.cpp:294:8:294:10 | 42 | Assignment between incompatible numeric types from 'unsigned int' to 'int32_t'. | +| test_specified.cpp:37:8:37:9 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_specified.cpp:38:8:38:9 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | +| test_specified.cpp:41:8:41:9 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'int8_t'. | +| test_specified.cpp:42:8:42:9 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. | +| test_specified.cpp:43:9:43:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. | +| test_specified.cpp:48:8:48:9 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | +| test_specified.cpp:49:9:49:10 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'uint16_t'. | +| test_specified.cpp:50:9:50:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. | +| test_specified.cpp:58:9:58:10 | l7 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test_specified.cpp:59:9:59:10 | l8 | Assignment between incompatible numeric types from 'double' to 'int32_t'. | +| test_specified.cpp:71:7:71:8 | l8 | Assignment between incompatible numeric types from 'double' to 'float'. | +| test_specified.cpp:94:8:94:9 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_specified.cpp:95:8:95:9 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | +| test_specified.cpp:96:9:96:10 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | +| test_specified.cpp:97:8:97:9 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'int8_t'. | +| test_specified.cpp:98:8:98:9 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. | +| test_specified.cpp:99:9:99:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. | +| test_specified.cpp:102:8:102:9 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | +| test_specified.cpp:103:9:103:10 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'uint16_t'. | +| test_specified.cpp:104:9:104:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. | +| test_specified.cpp:105:8:105:9 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int8_t'. | +| test_specified.cpp:106:9:106:10 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'int16_t'. | +| test_specified.cpp:107:9:107:10 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_specified.cpp:110:9:110:10 | l7 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test_specified.cpp:111:9:111:10 | l8 | Assignment between incompatible numeric types from 'double' to 'int32_t'. | +| test_specified.cpp:112:7:112:8 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'float'. | +| test_specified.cpp:113:7:113:8 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'float'. | +| test_specified.cpp:114:7:114:8 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | +| test_specified.cpp:115:7:115:8 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'double'. | +| test_specified.cpp:116:7:116:8 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'double'. | +| test_specified.cpp:117:7:117:8 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'double'. | +| test_specified.cpp:120:7:120:8 | l8 | Assignment between incompatible numeric types from 'double' to 'float'. | +| test_specified.cpp:143:8:143:9 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_specified.cpp:144:8:144:9 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | +| test_specified.cpp:145:9:145:10 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | +| test_specified.cpp:146:8:146:9 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'int8_t'. | +| test_specified.cpp:147:8:147:9 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. | +| test_specified.cpp:148:9:148:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. | +| test_specified.cpp:151:8:151:9 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | +| test_specified.cpp:152:9:152:10 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'uint16_t'. | +| test_specified.cpp:153:9:153:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. | +| test_specified.cpp:154:8:154:9 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int8_t'. | +| test_specified.cpp:155:9:155:10 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'int16_t'. | +| test_specified.cpp:156:9:156:10 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_specified.cpp:159:9:159:10 | l7 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test_specified.cpp:160:9:160:10 | l8 | Assignment between incompatible numeric types from 'double' to 'int32_t'. | +| test_specified.cpp:161:7:161:8 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'float'. | +| test_specified.cpp:162:7:162:8 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'float'. | +| test_specified.cpp:163:7:163:8 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | +| test_specified.cpp:164:7:164:8 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'double'. | +| test_specified.cpp:165:7:165:8 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'double'. | +| test_specified.cpp:166:7:166:8 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'double'. | +| test_specified.cpp:169:7:169:8 | l8 | Assignment between incompatible numeric types from 'double' to 'float'. | +| test_specified.cpp:213:8:213:9 | l6 | Assignment between incompatible numeric types from 'const uint16_t &' to 'uint8_t'. | +| test_specified.cpp:214:8:214:10 | l10 | Assignment between incompatible numeric types from 'volatile uint16_t &' to 'uint8_t'. | +| test_specified.cpp:215:8:215:10 | l14 | Assignment between incompatible numeric types from 'const volatile uint16_t &' to 'uint8_t'. | +| test_specified.cpp:218:8:218:9 | l5 | Assignment between incompatible numeric types from 'const uint8_t &' to 'int8_t'. | +| test_specified.cpp:219:8:219:9 | l7 | Assignment between incompatible numeric types from 'const int8_t &' to 'uint8_t'. | +| test_specified.cpp:220:8:220:9 | l9 | Assignment between incompatible numeric types from 'volatile uint8_t &' to 'int8_t'. | +| test_specified.cpp:221:8:221:10 | l11 | Assignment between incompatible numeric types from 'volatile int8_t &' to 'uint8_t'. | +| test_specified.cpp:222:8:222:10 | l13 | Assignment between incompatible numeric types from 'const volatile uint8_t &' to 'int8_t'. | +| test_specified.cpp:223:8:223:10 | l15 | Assignment between incompatible numeric types from 'const volatile int8_t &' to 'uint8_t'. | +| test_specified.cpp:226:9:226:10 | l8 | Assignment between incompatible numeric types from 'const float &' to 'int32_t'. | +| test_specified.cpp:227:9:227:11 | l12 | Assignment between incompatible numeric types from 'volatile float &' to 'int32_t'. | +| test_specified.cpp:228:9:228:11 | l16 | Assignment between incompatible numeric types from 'const volatile float &' to 'int32_t'. | +| test_specified.cpp:229:7:229:8 | l3 | Assignment between incompatible numeric types from 'int8_t' to 'float'. | +| test_specified.cpp:230:7:230:8 | l7 | Assignment between incompatible numeric types from 'const int8_t &' to 'float'. | +| test_specified.cpp:231:7:231:9 | l11 | Assignment between incompatible numeric types from 'volatile int8_t &' to 'float'. | +| test_specified.cpp:232:7:232:9 | l15 | Assignment between incompatible numeric types from 'const volatile int8_t &' to 'float'. | +| test_specified.cpp:245:7:245:8 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'const uint32_t'. | +| test_specified.cpp:246:7:246:8 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'const uint32_t'. | +| test_specified.cpp:247:7:247:8 | l3 | Assignment between incompatible numeric types from 'int8_t' to 'volatile int64_t'. | +| test_specified.cpp:248:7:248:8 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'const volatile uint16_t'. | +| test_specified.cpp:250:7:250:8 | l3 | Assignment between incompatible numeric types from 'int8_t' to 'const volatile uint16_t'. | +| test_specified.cpp:285:8:285:22 | g4 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_specified.cpp:287:8:287:19 | s4 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_specified.cpp:292:9:292:23 | g5 | Assignment between incompatible numeric types from 'int8_t' to 'uint16_t'. | +| test_specified.cpp:294:9:294:20 | s5 | Assignment between incompatible numeric types from 'int8_t' to 'uint16_t'. | +| test_specified.cpp:308:23:308:25 | 300 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test_specified.cpp:308:28:308:32 | 70000 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test_specified.cpp:308:35:308:38 | 3000 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test_specified.cpp:309:12:309:16 | 70000 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test_specified.cpp:314:23:314:25 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test_specified.cpp:314:28:314:30 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | +| test_specified.cpp:314:33:314:35 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test_specified.cpp:329:8:329:9 | l2 | Assignment between incompatible numeric types from 'CVColour' to 'uint8_t'. | +| test_specified.cpp:331:8:331:9 | l3 | Assignment between incompatible numeric types from 'CVColour' to 'uint8_t'. | +| test_specified.cpp:342:8:342:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test_specified.cpp:343:8:343:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test_specified.cpp:344:8:344:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test_specified.cpp:351:9:351:12 | (...) | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test_specified.cpp:352:9:352:12 | (...) | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test_specified.cpp:370:18:370:20 | 300 | Assignment between incompatible numeric types from 'int' to 'const uint8_t'. | +| test_specified.cpp:370:23:370:27 | 70000 | Assignment between incompatible numeric types from 'int' to 'volatile uint16_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.qlref b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.qlref new file mode 100644 index 0000000000..967340a41e --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.qlref @@ -0,0 +1 @@ +rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp new file mode 100644 index 0000000000..35aca81707 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -0,0 +1,643 @@ +#include +#include + +// Global variables for testing +std::uint32_t u32; +std::int32_t s32; +std::uint8_t u8; +std::int8_t s8; +std::uint16_t u16; +std::int16_t s16; +std::uint64_t u64; +std::int64_t s64; +float f; +double d; + +namespace TestNamespace { +std::uint8_t g1; +std::uint16_t g2; +} // namespace TestNamespace + +struct TestStruct { + std::uint8_t m1; + std::uint16_t m2; + static std::uint8_t s1; + static std::uint16_t s2; +}; + +std::uint8_t TestStruct::s1; +std::uint16_t TestStruct::s2; + +// Test basic constant assignments +void test_constant_assignments() { + u32 = 1; // COMPLIANT + s32 = 4u * 2u; // COMPLIANT + u8 = 3u; // COMPLIANT + u8 = 300u; // NON_COMPLIANT + f = 1; // COMPLIANT + f = 9999999999; // COMPLIANT + d = 0.0f; // NON_COMPLIANT + f = 0.0f; // COMPLIANT +} + +// Test signedness violations +void test_signedness_violations() { + u8 = s8; // NON_COMPLIANT + s8 = u8; // NON_COMPLIANT +} + +// Test size violations +void test_size_violations() { + u8 = u16; // NON_COMPLIANT + u16 = u64; // NON_COMPLIANT +} + +// Test type category violations +void test_type_category_violations() { + f = s32; // NON_COMPLIANT + s32 = f; // NON_COMPLIANT +} + +// Test widening of id-expressions +void test_widening_id_expressions() { + u32 = u8; // COMPLIANT - widening of id-expression + s64 = s8; // COMPLIANT - widening of id-expression + u64 = u16; // COMPLIANT - widening of id-expression +} + +// Test widening with namespace qualifiers (allowed) +void test_widening_namespace_qualified() { + u32 = TestNamespace::g1; // COMPLIANT - namespace qualified id-expression + u64 = TestNamespace::g2; // COMPLIANT - namespace qualified id-expression +} + +// Test widening with type qualifiers (allowed) +void test_widening_type_qualified() { + u32 = TestStruct::s1; // COMPLIANT - type qualified id-expression + u64 = TestStruct::s2; // COMPLIANT - type qualified id-expression +} + +// Test widening with decltype (allowed) +void test_widening_decltype_qualified() { + std::uint8_t l1 = 42; + std::uint16_t l2 = 42; + u32 = decltype(l1){}; // COMPLIANT - treated as a constant + u64 = decltype(l2){}; // COMPLIANT - treated as a constant + TestStruct l3; + u32 = decltype(l3)::s1; // COMPLIANT - decltype qualified + u64 = decltype(l3)::s2; // COMPLIANT - decltype qualified +} + +// Test widening with object member access (not allowed) +void test_widening_object_member_access() { + TestStruct l1; + TestStruct *l2 = &l1; + u32 = l1.m1; // NON_COMPLIANT - object member access, not id-expression + u64 = l1.m2; // NON_COMPLIANT - object member access, not id-expression + u32 = l2->m1; // NON_COMPLIANT - object member access, not id-expression + u64 = l2->m2; // NON_COMPLIANT - object member access, not id-expression +} + +// Test widening with expressions (not allowed) +void test_widening_expressions() { + u32 = u8 + 0; // NON_COMPLIANT - not id-expression + u32 = (u8); // NON_COMPLIANT - not id-expression (parenthesized) + u32 = static_cast(u8); // NON_COMPLIANT - not id-expression +} + +// Test expression results +void test_expression_results() { + u8 = u8 + u8; // NON_COMPLIANT + std::int16_t l1 = s8 + s8; // NON_COMPLIANT +} + +// Test bit-fields with various sizes around boundaries +struct S { + std::uint32_t m1 : 2; // 2-bit field + std::uint32_t m2 : 8; // 8-bit field (boundary) + std::uint32_t m3 : 9; // 9-bit field (boundary + 1) + std::uint32_t m4 : 16; // 16-bit field (boundary) + std::uint32_t m5 : 17; // 17-bit field (boundary + 1) + std::uint32_t m6 : 32; // 32-bit field (boundary) + std::uint64_t m7 : 33; // 33-bit field (boundary + 1) + std::int32_t m8 : 5; // Signed 5-bit field + std::int32_t m9 : 12; // Signed 12-bit field + std::int32_t m10 : 28; // Signed 28-bit field +}; + +void test_bitfields() { + S l1; + + // 2-bit field tests + l1.m1 = 2; // COMPLIANT - value fits in 2 bits + l1.m1 = 3; // COMPLIANT - value fits in 2 bits + l1.m1 = 4; // NON_COMPLIANT - constant does not fit in 2 bits + + l1.m1 = u8; // COMPLIANT - u8 is fine, not integer constant + l1.m1 = u16; // NON_COMPLIANT - narrowing from uint16_t + + // 8-bit boundary field tests + l1.m2 = 255; // COMPLIANT - value fits in uint8_t + l1.m2 = 256; // NON_COMPLIANT - value does not fit in unint8_t + l1.m2 = u8; // COMPLIANT - same width as uint8_t + l1.m2 = u16; // NON_COMPLIANT - narrowing from uint16_t + l1.m2 = u32; // NON_COMPLIANT - narrowing from uint32_t + + // 9-bit boundary + 1 field tests + l1.m3 = 511; // COMPLIANT + l1.m3 = 512; // NON_COMPLIANT - value does not fit in 9 bits + l1.m3 = 65535; // NON_COMPLIANT - value does not fit in 9 bits + l1.m3 = 65536; // NON_COMPLIANT - value does not fit in 9 bits + l1.m3 = u8; // COMPLIANT - widening from uint8_t to uint16_t + l1.m3 = u16; // COMPLIANT + l1.m3 = u32; // NON_COMPLIANT - narrowing from uint32_t + + // 16-bit boundary field tests + l1.m4 = 65535; // COMPLIANT - value fits in 16 bits + l1.m4 = 65536; // NON_COMPLIANT - value does not fit in 16 bits + l1.m4 = u8; // COMPLIANT - widening from uint8_t + l1.m4 = u16; // COMPLIANT - same width as uint16_t + l1.m4 = u32; // NON_COMPLIANT - narrowing from uint32_t + + // 17-bit boundary + 1 field tests + l1.m5 = 131071; // COMPLIANT - value fits in 17 bits + l1.m5 = 131072; // NON_COMPLIANT - value does not fit in 17 bits + l1.m5 = u8; // COMPLIANT - widening from uint8_t + l1.m5 = u16; // COMPLIANT - widening from uint16_t + l1.m5 = u32; // COMPLIANT + l1.m5 = u64; // NON_COMPLIANT - narrowing from uint64_t + + // 32-bit boundary field tests + l1.m6 = 4294967295U; // COMPLIANT - value fits in 32 bits + l1.m6 = 4294967296UL; // NON_COMPLIANT - value does not fit in 32 bits + l1.m6 = u8; // COMPLIANT - widening from uint8_t + l1.m6 = u16; // COMPLIANT - widening from uint16_t + l1.m6 = u32; // COMPLIANT - same width as uint32_t + l1.m6 = u64; // NON_COMPLIANT - narrowing from uint64_t + + // 33-bit boundary + 1 field tests + l1.m7 = 8589934591ULL; // COMPLIANT + l1.m7 = 8589934592L; // NON_COMPLIANT - value does not fit in 33 bits + l1.m7 = 8589934592ULL; // COMPLIANT - integer constant does not satisfy + // conditions, but the type matches the deduced type of + // the bitfield (unsigned long long), so is considered + // compliant by the rule(!) + l1.m7 = u8; // COMPLIANT - widening from uint8_t + l1.m7 = u16; // COMPLIANT - widening from uint16_t + l1.m7 = u32; // COMPLIANT - widening from uint32_t + l1.m7 = u64; // COMPLIANT - narrowing from uint64_t + + // Signed bitfield tests + l1.m8 = 15; // COMPLIANT + l1.m8 = -16; // COMPLIANT + l1.m8 = 16; // NON_COMPLIANT - value does not fit in signed 5-bit type + l1.m8 = -17; // NON_COMPLIANT - value does not fit in signed 5-bit type + l1.m8 = s8; // COMPLIANT - same width as int8_t + l1.m8 = s16; // NON_COMPLIANT - narrowing from int16_t + + l1.m9 = 2047; // COMPLIANT - value fits in signed 12-bit type + l1.m9 = -2048; // COMPLIANT - value fits in signed 12-bit type + l1.m9 = 2048; // NON_COMPLIANT - value does not fit in signed 12-bit type + l1.m9 = -2049; // NON_COMPLIANT - value does not fit in signed 12-bit type + l1.m9 = s8; // COMPLIANT - widening from int8_t + l1.m9 = s16; // COMPLIANT - same width as int16_t + l1.m9 = s32; // NON_COMPLIANT - narrowing from int32_t + + l1.m10 = 134217727; // COMPLIANT - value fits in signed 28-bit type + l1.m10 = -134217728; // COMPLIANT - value fits in signed 28-bit type + l1.m10 = 134217728LL; // NON_COMPLIANT - does not fit in signed 28-bit type + l1.m10 = -134217729LL; // NON_COMPLIANT - does not fit in signed 28-bit type + l1.m10 = s8; // COMPLIANT - widening from int8_t + l1.m10 = s16; // COMPLIANT - widening from int16_t + l1.m10 = s32; // COMPLIANT +} + +// Test enums +enum Colour : std::uint16_t { red, green, blue }; + +enum States { enabled, disabled }; + +void test_enums() { + Colour l1 = red; + u8 = red; // COMPLIANT + u32 = red; // COMPLIANT + u8 = l1; // NON_COMPLIANT + u32 = l1; // COMPLIANT + u8 = enabled; // COMPLIANT - enabled is not numeric +} + +// Test function parameters - non-overload-independent +void f1(std::int64_t l1) {} +void f2(std::int32_t l1) {} + +void test_function_parameters_non_overload_independent() { + f1(s32); // NON_COMPLIANT + f1(s64); // COMPLIANT + f2(s32); // COMPLIANT + f2(s64); // NON_COMPLIANT + int l1 = 42; + f2(l1); // NON_COMPLIANT - needs to be the same type as the parameter + signed int l2 = 42; + f2(l2); // COMPLIANT - int32_t is defined as `signed int` in this database +} + +// Test overloaded functions, but still non-overload-independent +// because they are "extensible" (i.e., they can be extended with new +// overloads). +void f3(std::int64_t l1) {} +void f3(std::int32_t l1) {} + +void test_overloaded_functions() { + f3(s32); // COMPLIANT + f3(s8); // NON_COMPLIANT + f3(s64); // COMPLIANT +} + +// Test function pointers - always "overload-independent" +void f4(long l1) {} + +void test_function_pointers() { + void (*l1)(long) = &f4; + f4(2); // NON_COMPLIANT + l1(2); // COMPLIANT +} + +// Test variadic functions +void f5(const char *l1, ...) {} + +void test_variadic_functions() { + f5("test", u8); // NON_COMPLIANT - will be promoted to `int` + f5("test", s32); // COMPLIANT - already `int`, no promotion needed +} + +struct A { + // first parameter to f6 with two arguments is overload-independent + void f6(std::size_t l1, int l2) {} + void f6(std::size_t l1, std::string l2) {} + // Different overload, so does not conflict with f6 above + void f6(std::int8_t l1, std::string l2, int x) {} + // Deleted function, ignored for overload independence calculations + void f6(float l1, float l2) = delete; + // Not overload-independent when called with one parameter + // Overload-independent when called with two parameters + void f7(float l1) {} + void f7(std::int32_t l1, int x = 1) {} + void f8(); +}; + +void A::f8() { + f6(u32, "answer"); // NON_COMPLIANT - extensible, could call a global + // function instead - e.g. `void f6(std::uint32_t l1, + // std::string l2)` + this->f6(u32, "answer"); // COMPLIANT + this->f6(u32, 42); // COMPLIANT + this->f7(s16); // NON_COMPLIANT - no widening as not overload-independent + this->f7(s16, 2); // COMPLIANT - overload-independent, only one target +} + +void test_member_function_overload_independent() { + A l1; + l1.f6(42, "answer"); // COMPLIANT + A *l2 = &l1; + l2->f6(42, "answer"); // COMPLIANT +} + +// Test member function calls - not overload-independent +struct B { + void f8(int l1, int l2) {} + void f8(long l1, std::string l2) {} +}; + +void test_member_function_not_overload_independent() { + B l1; + l1.f8(42, "answer"); // NON_COMPLIANT +} + +// Test constructor exception +struct MyInt { + explicit MyInt(std::int32_t l1) {} + MyInt(std::int32_t l1, std::int32_t l2) {} + // Move and copy constructors are allowed + MyInt(MyInt const &) = default; + MyInt(MyInt &&) = default; +}; + +struct ConstructorException { + explicit ConstructorException(std::int32_t l1, std::int32_t l2 = 2) {} +}; + +struct NotInConstructorException { + explicit NotInConstructorException(std::int32_t l1) {} + NotInConstructorException(std::int16_t l1, std::int32_t l2 = 2) {} +}; + +void f9(MyInt l1) {} + +void test_constructor_exception() { + f9(MyInt{s8}); // COMPLIANT + MyInt l1{s8}; // COMPLIANT + f9(MyInt{s8, 10}); // NON_COMPLIANT - not covered by exception + MyInt l2{s8, 10}; // NON_COMPLIANT - not covered by exception + ConstructorException l3{s8}; // COMPLIANT + NotInConstructorException l4{s8}; // NON_COMPLIANT - ambiguous constructor +} + +template struct D { + // Overload-independent - f10 parameters are always the same type + void f10(T l1, int l2) {} + void f10(T l1, std::string l2) {} + // Not overload-independent + template void f11(S1 l1, int l2) {} + template void f11(S2 l1, std::string l2) {} + void f11(std::int32_t l1, float f) {} +}; + +void test_template_functions() { + D l1; + l1.f10(u32, "X"); // COMPLIANT - can widen, because always same type + l1.f10(u32, 1); // COMPLIANT - can widen, because always same type + D l2; + l2.f10(u16, "X"); // COMPLIANT - can widen, because always same type + l2.f10(u16, 1); // COMPLIANT - can widen, because always same type + l1.f11(u32, "X"); // NON_COMPLIANT - not overload-independent + // and not the same type as the parameter + // so cannot widen - must be the same type + l1.f11(s32, 1); // COMPLIANT - same as specialized type + l1.f11(s32, 0.0f); // COMPLIANT - matches parameter type +} + +// Test initialization forms +std::int32_t f12(std::int8_t l1) { + std::int16_t l2 = l1; // COMPLIANT + std::int16_t l3{l1}; // COMPLIANT + std::int16_t l4(l1); // COMPLIANT + std::int16_t l5{l1 + l1}; // NON_COMPLIANT + return l1; // COMPLIANT +} + +std::int32_t test_return() { + return u32; // NON_COMPLIANT - wrong signedness +} + +// Test switch cases +void test_switch_cases() { + switch (s8) { + case 1: // COMPLIANT + break; + case 0x7F: // COMPLIANT + break; + case 0x80: // COMPLIANT - condition subject to promotion + break; + // Our extractor and supported compilers prohibit the below + // narrowing conversion. + // case 0xFFFF'FFFF'FFFF: + // break; + } +} + +// Test reference types - references to numeric types are considered numeric +void test_reference_types_basic() { + std::uint8_t l1 = 42; + std::uint32_t l2 = 100; + std::int8_t l3 = -5; + float l4 = 3.14f; + + std::uint8_t &l5 = l1; // COMPLIANT + std::uint32_t &l6 = l2; // COMPLIANT + std::int8_t &l7 = l3; // COMPLIANT + float &l8 = l4; // COMPLIANT + + // Reference types follow same rules as their referred types + u32 = l5; // COMPLIANT - widening of id-expression (reference) + u8 = l6; // NON_COMPLIANT - narrowing from reference + u8 = l7; // NON_COMPLIANT - different signedness from reference + s32 = l8; // NON_COMPLIANT - different type category from reference +} + +void test_reference_types_function_parameters() { + std::uint8_t l1 = 42; + std::uint16_t l2 = 1000; + + std::uint8_t &l3 = l1; + std::uint16_t &l4 = l2; + + // Function calls with reference arguments + f1(l3); // NON_COMPLIANT - widening conversion through reference + f2(l4); // NON_COMPLIANT - narrowing conversion through reference +} + +void test_reference_types_signedness() { + std::uint8_t l1 = 42; + std::int8_t l2 = -5; + + std::uint8_t &l3 = l1; + std::int8_t &l4 = l2; + + // Signedness violations through references + s8 = l3; // NON_COMPLIANT - different signedness through reference + u8 = l4; // NON_COMPLIANT - different signedness through reference +} + +void test_reference_types_floating_point() { + float l1 = 3.14f; + double l2 = 2.718; + std::int32_t l3 = 42; + + float &l4 = l1; + double &l5 = l2; + std::int32_t &l6 = l3; + + // Type category violations through references + s32 = l4; // NON_COMPLIANT - different type category through reference + f = l5; // NON_COMPLIANT - different size through reference + f = l6; // NON_COMPLIANT - different type category through reference +} + +void test_reference_types_expressions() { + std::uint8_t l1 = 42; + std::uint8_t l2 = 24; + + std::uint8_t &l3 = l1; + std::uint8_t &l4 = l2; + + // Expression results with references still follow expression rules + u8 = l3 + l4; // NON_COMPLIANT - addition promotes to int + s32 = l3 + l4; // COMPLIANT - promotion to int +} + +// Test reference parameters in functions +void f13(std::uint8_t &l1) {} +void f13(std::uint16_t &l1) {} + +void f14(std::uint32_t l1) {} + +void test_references_to_parameters() { + std::uint8_t l1 = 42; + std::uint16_t l2 = 1000; + + f13(l1); // COMPLIANT - not covered by rule, as pass-by-ref + f13(l2); // COMPLIANT - not covered by rule, as pass-by-ref + + std::uint16_t &l3 = l2; + f14(l3); // NON_COMPLIANT - must be the same type, as non-overload-independent + std::uint64_t l4 = 1000; + std::uint64_t &l5 = l4; + f14(l5); // NON_COMPLIANT - narrowing conversion through reference +} + +// Test compound assignments - rule does not apply to compound assignments +void test_compound_assignments() { + std::uint8_t l1 = 10; + std::uint16_t l2 = 100; + std::int8_t l3 = 5; + float l4 = 1.5f; + + l1 += l2; // COMPLIANT - compound assignment, rule does not apply + l1 -= l3; // COMPLIANT - compound assignment, rule does not apply + l2 *= l1; // COMPLIANT - compound assignment, rule does not apply + l2 /= l3; // COMPLIANT - compound assignment, rule does not apply + l1 %= l3; // COMPLIANT - compound assignment, rule does not apply + l2 &= l1; // COMPLIANT - compound assignment, rule does not apply + l2 |= l3; // COMPLIANT - compound assignment, rule does not apply + l2 ^= l1; // COMPLIANT - compound assignment, rule does not apply + l2 <<= 2; // COMPLIANT - compound assignment, rule does not apply + l2 >>= 1; // COMPLIANT - compound assignment, rule does not apply + l4 += l1; // COMPLIANT - compound assignment, rule does not apply + l4 -= s32; // COMPLIANT - compound assignment, rule does not apply +} + +// Test constructor field initializers +struct ConstructorTest { + std::uint8_t m1; + std::uint16_t m2; + std::uint32_t m3; + std::int8_t m4; + std::int16_t m5; + std::int32_t m6; + float m7; + double m8; + + // Constructor with various member initializer scenarios + ConstructorTest(std::uint8_t l1, std::uint16_t l2, std::int8_t l3) + : m1(l1), // COMPLIANT - same type + m2(l2), // COMPLIANT - same type + m3(l1), // COMPLIANT - widening of id-expression + m4(l3), // COMPLIANT - same type + m5(l3), // COMPLIANT - widening of id-expression + m6(l3), // COMPLIANT - widening of id-expression + m7(1.0f), // COMPLIANT - same type + m8(1.0) { // COMPLIANT - same type + } + + // Constructor with non-compliant initializers + ConstructorTest(std::uint32_t l1, std::int32_t l2, float l3) + : m1(l1), // NON_COMPLIANT - narrowing + m2(l1), // NON_COMPLIANT - narrowing + m3(l1), // COMPLIANT - same type + m4(l2), // NON_COMPLIANT - narrowing and different signedness + m5(l2), // NON_COMPLIANT - narrowing and different signedness + m6(l2), // COMPLIANT - same type + m7(l3), // COMPLIANT - same type + m8(l3) { // COMPLIANT - allowed to use float to initialize double + } + + // Constructor with constant initializers + ConstructorTest() + : m1(100), // COMPLIANT - constant fits + m2(65535), // COMPLIANT - constant fits + m3(4294967295U), // COMPLIANT - constant fits + m4(127), // COMPLIANT - constant fits + m5(32767), // COMPLIANT - constant fits + m6(2147483647), // COMPLIANT - constant fits + m7(3.14f), // COMPLIANT - same type constant + m8(2.718) { // COMPLIANT - same type constant + } + + // Constructor with non-compliant constant initializers + ConstructorTest(int) + : m1(300), // NON_COMPLIANT - constant too large + m2(70000), // NON_COMPLIANT - constant too large + m3(0x1'0000'0000ULL), // NON_COMPLIANT - constant too large + m4(200), // NON_COMPLIANT - constant too large + m5(40000), // NON_COMPLIANT - constant too large + m6(0x1'0000'0000LL), // NON_COMPLIANT - constant too large + m7(1.0), // NON_COMPLIANT - different size + m8(1.0f) { // NON_COMPLIANT - different size + } + + // Constructor with expression initializers + ConstructorTest(std::uint8_t l1, std::uint8_t l2, std::int8_t l3) + : m1(l1 + l2), // NON_COMPLIANT - expression result is int + m2(l1 + l2), // NON_COMPLIANT - expression result is int + m3(l1 + l2), // NON_COMPLIANT - expression result is int + m4(l3), // COMPLIANT - widening of id-expression + m5(l1), // NON_COMPLIANT - different signedness + m6(l1), // NON_COMPLIANT - different signedness + m7(l1), // NON_COMPLIANT - different type category + m8(l1) { // NON_COMPLIANT - different type category + } +}; + +void test_constructor_field_initializers() { + std::uint8_t l1 = 42; + std::uint16_t l2 = 1000; + std::int8_t l3 = 10; + + ConstructorTest l4(l1, l2, l3); // Test first constructor + ConstructorTest l5(u32, s32, f); // Test second constructor + ConstructorTest l6; // Test third constructor + ConstructorTest l7(0); // Test fourth constructor + ConstructorTest l8(l1, l1, l3); // Test fifth constructor +} + +// Test explicit casts +void test_explicit_casts() { + std::uint8_t l1 = 42; + std::uint16_t l2 = 1000; + std::int8_t l3 = -10; + std::int32_t l4 = -100; + float l5 = 3.14f; + double l6 = 2.718; + + // Explicit cast expressions are treated as expressions, not id-expressions + u8 = static_cast(l2); // COMPLIANT + u16 = static_cast(l1); // COMPLIANT + s8 = static_cast(l4); // COMPLIANT + s32 = static_cast(l3); // COMPLIANT + s32 = static_cast(l3); // NON_COMPLIANT + + // Type category conversions with explicit casts + f = static_cast(l4); // COMPLIANT + s32 = static_cast(l5); // COMPLIANT + + // Size conversions with explicit casts + d = static_cast(l5); // COMPLIANT + l5 = static_cast(l6); // COMPLIANT + + // C-style casts (also expressions) + u8 = (std::uint8_t)l2; // COMPLIANT + s8 = (std::int8_t)l4; // COMPLIANT + f = (float)l4; // COMPLIANT + + // Functional style casts (also expressions) + u8 = std::uint8_t(l2); // COMPLIANT + s8 = std::int8_t(l4); // COMPLIANT + f = float(l4); // COMPLIANT + + // Const_cast (creates expressions) + const std::uint8_t l7 = 100; + u8 = const_cast(l7); // COMPLIANT + + // Reinterpret_cast (creates expressions) + u32 = reinterpret_cast(l4); // COMPLIANT + + // Assignment to variables through explicit casts + std::uint32_t l8; + std::uint16_t l9; + l8 = static_cast(l9); // COMPLIANT + l9 = static_cast(l8); // COMPLIANT + + // Function calls with explicit casts + f1(static_cast(l4)); // COMPLIANT + f2(static_cast(l4)); // COMPLIANT +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-6/test_aggregate.cpp b/cpp/misra/test/rules/RULE-7-0-6/test_aggregate.cpp new file mode 100644 index 0000000000..7e215bc602 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-6/test_aggregate.cpp @@ -0,0 +1,111 @@ +#include + +std::uint32_t u32; +std::int32_t s32; +std::uint8_t u8; +std::int8_t s8; +std::uint16_t u16; +std::int16_t s16; +std::uint64_t u64; +std::int64_t s64; +float f; +double d; + +// Test aggregate initialization - struct with multiple members +struct SimpleAggregate { + std::uint8_t m1; + std::uint16_t m2; + std::int32_t m3; + float m4; +}; + +void test_aggregate_initialization_basic() { + // Compliant cases - exact types or constants that fit + SimpleAggregate l1{42, 1000, -50, 3.14f}; // COMPLIANT + SimpleAggregate l2{u8, u16, s32, f}; // COMPLIANT + SimpleAggregate l3{255, 65535, 2147483647, 0.0f}; // COMPLIANT + + // Non-compliant cases - type violations + SimpleAggregate l4{u16, u8, s32, // NON_COMPLIANT - narrowing u16 to uint8_t + f}; + SimpleAggregate l5{u8, u32, s32, // NON_COMPLIANT - narrowing u32 to uint16_t + f}; + SimpleAggregate l6{u8, u16, u32, f}; // NON_COMPLIANT - different signedness + SimpleAggregate l7{u8, u16, s32, + s32}; // NON_COMPLIANT - different type category + + // Constants that don't fit + SimpleAggregate l8{256, 65536, // NON_COMPLIANT - constants don't fit + 2147483648LL, // NON_COMPLIANT - constants don't fit + 0.0f}; + + // Widening of id-expressions is allowed + SimpleAggregate l9{u8, u8, s8, f}; // COMPLIANT - widening allowed +} + +// Test aggregate initialization - arrays +void test_aggregate_initialization_arrays() { + // Basic arrays + std::uint8_t l1[3]{10, 20, 30}; // COMPLIANT + std::uint8_t l2[3]{u8, u8, u8}; // COMPLIANT + std::uint8_t l3[3]{300, 400, 500}; // NON_COMPLIANT - constants don't fit + std::uint8_t l4[3]{s8, s8, s8}; // NON_COMPLIANT - signedness mismatch + std::uint8_t l5[3]{u16, u16, u16}; // NON_COMPLIANT - narrowing + + // Multi-dimensional arrays + std::int16_t l6[2][2]{{1, 2}, {3, 4}}; // COMPLIANT + std::int16_t l7[2][2]{{s8, s8}, {s8, s8}}; // COMPLIANT - widening allowed + std::int16_t l8[2][2]{{s32, s32}, {s32, s32}}; // NON_COMPLIANT - narrowing + std::int16_t l9[2][2]{{u8, u8}, // NON_COMPLIANT - signedness mismatch + {u8, u8}}; // NON_COMPLIANT - signedness mismatch +} + +// Test aggregate initialization - nested structs +struct NestedAggregate { + SimpleAggregate m1; + std::uint32_t m2; +}; + +void test_aggregate_initialization_nested() { + // Compliant nested initialization + NestedAggregate l1{{10, 100, -5, 1.0f}, 500}; // COMPLIANT + NestedAggregate l2{{u8, u16, s32, f}, u32}; // COMPLIANT + + // Non-compliant nested initialization + NestedAggregate l3{ + {u16, u8, s32, f}, // NON_COMPLIANT - narrowing in nested struct + u32}; + NestedAggregate l4{ + {u8, u16, s32, f}, + s32}; // NON_COMPLIANT - signedness mismatch in outer member +} + +// Test aggregate initialization - struct with bit-fields +struct BitfieldAggregate { + std::uint32_t m1 : 8; + std::uint32_t m2 : 16; + std::int32_t m3 : 12; +}; + +void test_aggregate_initialization_bitfields() { + // Compliant cases + BitfieldAggregate l1{100, 30000, -500}; // COMPLIANT + BitfieldAggregate l2{u8, u16, s16}; // COMPLIANT - appropriate sizes + + // Non-compliant cases + BitfieldAggregate l3{300, 70000, 5000}; // NON_COMPLIANT - constants don't fit + BitfieldAggregate l4{u16, u32, s32}; // NON_COMPLIANT - narrowing +} + +// Test aggregate initialization with designated initializers (C++20 feature, +// but test for basic cases) +void test_aggregate_initialization_designated() { + // Note: Designated initializers are C++20, but we can test basic aggregate + // init patterns + SimpleAggregate l1{.m1 = 10, .m2 = 100, .m3 = -5, .m4 = 1.0f}; // COMPLIANT + SimpleAggregate l2{.m1 = u8, .m2 = u16, .m3 = s32, .m4 = f}; // COMPLIANT + SimpleAggregate l3{.m1 = u16, // NON_COMPLIANT - type violation + .m2 = u8, + .m3 = s32, + .m4 = f}; +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-6/test_member_pointers.cpp b/cpp/misra/test/rules/RULE-7-0-6/test_member_pointers.cpp new file mode 100644 index 0000000000..d6f3de7eb8 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-6/test_member_pointers.cpp @@ -0,0 +1,128 @@ +#include + +std::int16_t s16; +std::uint16_t u16; +std::int32_t s32; +std::uint32_t u32; +std::int64_t s64; +std::uint64_t u64; + +struct MemberFunctionPointerTest { + void mf15(std::int32_t l1) {} + void mf15(std::uint32_t l1) {} + void mf16(std::int32_t l1) {} +}; + +void test_pointer_to_member_functions() { + MemberFunctionPointerTest l1; + MemberFunctionPointerTest *l6 = &l1; + + // mf15 is overload independent when used as a member function pointer + void (MemberFunctionPointerTest::*l2)(std::int32_t) = + &MemberFunctionPointerTest::mf15; + (l1.*l2)(s16); // COMPLIANT - widening of id-expression + (l1.*l2)(s32); // COMPLIANT - type match + (l1.*l2)(s64); // NON_COMPLIANT - narrowing + (l1.*l2)(u16); // NON_COMPLIANT - wrong sign + (l1.*l2)(u32); // NON_COMPLIANT - wrong sign + (l1.*l2)(u64); // NON_COMPLIANT - wrong sign and narrowing + + (l6->*l2)(s16); // COMPLIANT - is widening of id-expression + (l6->*l2)(s32); // COMPLIANT - type match + (l6->*l2)(s64); // NON_COMPLIANT - narrowing + (l6->*l2)(u16); // NON_COMPLIANT - wrong sign + (l6->*l2)(u32); // NON_COMPLIANT - wrong sign + (l6->*l2)(u64); // NON_COMPLIANT - wrong sign and narrowing + + // mf16 is overload independent when used as a member function pointer + void (MemberFunctionPointerTest::*l3)(std::int32_t) = + &MemberFunctionPointerTest::mf16; + (l1.*l3)(s16); // COMPLIANT - widening of id-expression + (l1.*l3)(s32); // COMPLIANT - type match + (l1.*l3)(s64); // NON_COMPLIANT - narrowing + (l1.*l3)(u16); // NON_COMPLIANT - wrong sign + (l1.*l3)(u32); // NON_COMPLIANT - wrong sign + (l1.*l3)(u64); // NON_COMPLIANT - wrong sign and narrowing + + (l6->*l3)(s16); // COMPLIANT - widening of id-expression + (l6->*l3)(s32); // COMPLIANT - type match + (l6->*l3)(s64); // NON_COMPLIANT - narrowing + (l6->*l3)(u16); // NON_COMPLIANT - wrong sign + (l6->*l3)(u32); // NON_COMPLIANT - wrong sign + (l6->*l3)(u64); // NON_COMPLIANT - wrong sign and narrowing + + // Direct calls for comparison + + // mf15 is not overload-independent, so it should only be compliant + // where an exact type of an overload is used + l1.mf15(s16); // NON_COMPLIANT - widening not allowed + l1.mf15(s32); // COMPLIANT - exact type match + l1.mf15(u16); // NON_COMPLIANT - widening not allowed + l1.mf15(u32); // COMPLIANT - exact type match + + // A qualified call to mf16 is overload-independent + l1.mf16(s16); // COMPLIANT - widening of id-expression + l1.mf16(s32); // COMPLIANT - exact type match + l1.mf16(u16); // NON_COMPLIANT + l1.mf16(u32); // NON_COMPLIANT +} + +// Test static member function pointers - should be overload-independent +struct StaticMemberFunctionPointerTest { + static void mf19(std::int32_t l1) {} + static void mf19(std::uint32_t l1) {} + static void mf20(std::int32_t l1) {} +}; + +void test_static_member_function_pointers() { + // Static member function pointers - overload-independent + void (*l1)(std::int32_t) = &StaticMemberFunctionPointerTest::mf19; + l1(s16); // COMPLIANT - widening of id-expression + l1(s32); // COMPLIANT - type match + l1(s64); // NON_COMPLIANT - narrowing + l1(u16); // NON_COMPLIANT - wrong sign + l1(u32); // NON_COMPLIANT - wrong sign + l1(u64); // NON_COMPLIANT - wrong sign and narrowing + + void (*l2)(std::int32_t) = &StaticMemberFunctionPointerTest::mf20; + l2(s16); // COMPLIANT - widening of id-expression + l2(s32); // COMPLIANT - type match + l2(s64); // NON_COMPLIANT - narrowing + l2(u16); // NON_COMPLIANT - wrong sign + l2(u32); // NON_COMPLIANT - wrong sign + l2(u64); // NON_COMPLIANT - wrong sign and narrowing + + // Direct calls for comparison - not overload-independent + StaticMemberFunctionPointerTest::mf19( + s16); // NON_COMPLIANT - widening not allowed + StaticMemberFunctionPointerTest::mf19(s32); // COMPLIANT - exact type match + StaticMemberFunctionPointerTest::mf19( + u16); // NON_COMPLIANT - widening not allowed + StaticMemberFunctionPointerTest::mf19(u32); // COMPLIANT - exact type match + + StaticMemberFunctionPointerTest::mf20( + s16); // COMPLIANT - widening of id-expression + StaticMemberFunctionPointerTest::mf20(s32); // COMPLIANT - exact type match + StaticMemberFunctionPointerTest::mf20(u16); // NON_COMPLIANT + StaticMemberFunctionPointerTest::mf20(u32); // NON_COMPLIANT +} + +// Test member data pointers - not function calls, but test assignment to them +struct MemberDataPointerTest { + std::int64_t m1; + std::int64_t m2 : 10; +}; + +void test_member_data_pointers() { + MemberDataPointerTest l1; + + // Member data pointer assignments - follow normal assignment rules + std::int64_t MemberDataPointerTest::*l2 = &MemberDataPointerTest::m1; + + l1.*l2 = s16; // COMPLIANT - widening conversion allowed + l1.*l2 = s32; // COMPLIANT - widening conversion allowed + l1.*l2 = s64; // COMPLIANT + l1.*l2 = u16; // NON_COMPLIANT - signedness violation + l1.*l2 = u32; // NON_COMPLIANT - different signedness/size + l1.*l2 = u64; // NON_COMPLIANT - different signedness +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-6/test_non_numeric.cpp b/cpp/misra/test/rules/RULE-7-0-6/test_non_numeric.cpp new file mode 100644 index 0000000000..3da5c21c81 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-6/test_non_numeric.cpp @@ -0,0 +1,138 @@ +#include +#include + +// Test non-numeric type categories - these should not trigger rule violations +void test_non_numeric_type_categories() { + // Character category types + char l1 = 'a'; + wchar_t l2 = L'b'; + char16_t l3 = u'c'; + char32_t l4 = U'd'; + + // Other category types + bool l5 = true; + void *l6 = nullptr; + std::nullptr_t l7 = nullptr; + + // Assignments between character types and numeric types + // Rule should not apply since source/target involve non-numeric types + std::uint8_t l8 = 42; + std::int32_t l9 = 100; + float l10 = 3.14f; + + // Character to numeric - rule does not apply + l8 = l1; // COMPLIANT - char is character category, not numeric + l9 = l2; // COMPLIANT - wchar_t is character category, not numeric + l8 = l3; // COMPLIANT - char16_t is character category, not numeric + l9 = l4; // COMPLIANT - char32_t is character category, not numeric + l10 = l1; // COMPLIANT - char is character category, not numeric + + // Numeric to character - rule does not apply + l1 = l8; // COMPLIANT - char is character category, not numeric + l2 = l9; // COMPLIANT - wchar_t is character category, not numeric + l3 = l8; // COMPLIANT - char16_t is character category, not numeric + l4 = l9; // COMPLIANT - char32_t is character category, not numeric + l1 = l10; // COMPLIANT - char is character category, not numeric + + // Other category to numeric - rule does not apply + l8 = l5; // COMPLIANT - bool is other category, not numeric + l9 = l5; // COMPLIANT - bool is other category, not numeric + l10 = l5; // COMPLIANT - bool is other category, not numeric + + // Numeric to other category - rule does not apply + l5 = l8; // COMPLIANT - bool is other category, not numeric + l5 = l9; // COMPLIANT - bool is other category, not numeric + l5 = l10; // COMPLIANT - bool is other category, not numeric + + // Character to character - rule does not apply + l1 = l2; // COMPLIANT - both character category, not numeric + l3 = l4; // COMPLIANT - both character category, not numeric + l1 = l3; // COMPLIANT - both character category, not numeric + + // Other to other - rule does not apply + std::nullptr_t l11 = l7; // COMPLIANT - both other category, not numeric + l6 = l7; // COMPLIANT - both other category, not numeric + + // Character to other - rule does not apply + l5 = l1; // COMPLIANT - neither is numeric category + l6 = nullptr; // COMPLIANT - neither is numeric category + + // Other to character - rule does not apply + l1 = l5; // COMPLIANT - neither is numeric category +} + +// Test function parameters with non-numeric types +void f15(char l1) {} +void f16(bool l1) {} +void f17(wchar_t l1) {} + +void test_non_numeric_function_parameters() { + std::uint8_t l1 = 42; + std::int32_t l2 = 100; + char l3 = 'x'; + bool l4 = true; + wchar_t l5 = L'y'; + + // Function calls with non-numeric parameters - rule does not apply + f15(l1); // COMPLIANT - parameter is character category, not numeric + f15(l2); // COMPLIANT - parameter is character category, not numeric + f15(l3); // COMPLIANT - parameter is character category, not numeric + + f16(l1); // COMPLIANT - parameter is other category, not numeric + f16(l2); // COMPLIANT - parameter is other category, not numeric + f16(l4); // COMPLIANT - parameter is other category, not numeric + + f17(l1); // COMPLIANT - parameter is character category, not numeric + f17(l2); // COMPLIANT - parameter is character category, not numeric + f17(l5); // COMPLIANT - parameter is character category, not numeric +} + +// Test references to non-numeric types +void test_non_numeric_references() { + char l1 = 'a'; + bool l2 = true; + wchar_t l3 = L'b'; + std::uint8_t l4 = 42; + std::int32_t l5 = 100; + + char &l6 = l1; + bool &l7 = l2; + wchar_t &l8 = l3; + + // Assignments involving references to non-numeric types - rule does not apply + l4 = l6; // COMPLIANT - reference to character category, not numeric + l5 = l7; // COMPLIANT - reference to other category, not numeric + l4 = l8; // COMPLIANT - reference to character category, not numeric + + l6 = l4; // COMPLIANT - reference to character category, not numeric + l7 = l5; // COMPLIANT - reference to other category, not numeric + l8 = l4; // COMPLIANT - reference to character category, not numeric +} + +// Test bit-fields with non-numeric types (though these are rare in practice) +struct NonNumericBitFields { + bool m1 : 1; // Other category + char m2 : 7; // Character category + wchar_t m3 : 16; // Character category +}; + +void test_non_numeric_bitfields() { + NonNumericBitFields l1; + std::uint8_t l2 = 42; + std::int32_t l3 = 100; + bool l4 = true; + char l5 = 'x'; + + // Assignments to/from non-numeric bit-fields - rule does not apply + l1.m1 = l2; // COMPLIANT - bit-field is other category, not numeric + l1.m1 = l4; // COMPLIANT - bit-field is other category, not numeric + l1.m2 = l2; // COMPLIANT - bit-field is character category, not numeric + l1.m2 = l5; // COMPLIANT - bit-field is character category, not numeric + l1.m3 = l3; // COMPLIANT - bit-field is character category, not numeric + + l2 = l1.m1; // COMPLIANT - bit-field is other category, not numeric + l4 = l1.m1; // COMPLIANT - bit-field is other category, not numeric + l2 = l1.m2; // COMPLIANT - bit-field is character category, not numeric + l5 = l1.m2; // COMPLIANT - bit-field is character category, not numeric + l3 = l1.m3; // COMPLIANT - bit-field is character category, not numeric +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp b/cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp new file mode 100644 index 0000000000..4f2e256b26 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp @@ -0,0 +1,295 @@ +#include + +// Test user-defined operators - always non-extensible +struct UserDefinedOperators { + UserDefinedOperators(std::int32_t l1) {} + + // Binary operators + UserDefinedOperators operator+(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator-(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator*(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator/(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator%(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator&(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator|(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator^(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator<<(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator>>(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + + // Comparison operators + bool operator==(std::int32_t l1) const { return true; } + bool operator!=(std::int32_t l1) const { return false; } + bool operator<(std::int32_t l1) const { return false; } + bool operator<=(std::int32_t l1) const { return false; } + bool operator>(std::int32_t l1) const { return false; } + bool operator>=(std::int32_t l1) const { return false; } + + // Subscript operator + std::int32_t operator[](std::int32_t l1) const { return 0; } + + // Function call operator + std::int32_t operator()(std::int32_t l1) const { return 0; } + std::int32_t operator()(std::int32_t l1, std::int32_t l2) const { return 0; } + + // Assignment operators + UserDefinedOperators &operator=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator+=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator-=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator*=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator/=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator%=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator&=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator|=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator^=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator<<=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator>>=(std::int32_t l1) { return *this; } + + // Increment/decrement operators + UserDefinedOperators &operator++() { return *this; } + UserDefinedOperators operator++(int) { return UserDefinedOperators{0}; } + UserDefinedOperators &operator--() { return *this; } + UserDefinedOperators operator--(int) { return UserDefinedOperators{0}; } +}; + +// Global user-defined operators +UserDefinedOperators operator+(std::int32_t l1, + const UserDefinedOperators &l2) { + return UserDefinedOperators{0}; +} + +UserDefinedOperators operator-(std::int32_t l1, + const UserDefinedOperators &l2) { + return UserDefinedOperators{0}; +} + +bool operator==(std::int32_t l1, const UserDefinedOperators &l2) { + return true; +} + +void test_user_defined_operators() { + UserDefinedOperators l1{42}; + std::int32_t l2 = 10; + std::int16_t l3 = 5; + std::int64_t l4 = 100; + std::uint32_t l5 = 20; + + // Member operators - non-extensible, exact type match required + l1 + l2; // COMPLIANT - exact type match + l1 + l3; // COMPLIANT - widening conversion is allowed + l1 + l4; // NON_COMPLIANT - different type + l1 + l5; // NON_COMPLIANT - different signedness + + l1 - l2; // COMPLIANT - exact type match + l1 - l3; // COMPLIANT - widening conversion is allowed + l1 - l4; // NON_COMPLIANT - different type + l1 - l5; // NON_COMPLIANT - different signedness + + l1 *l2; // COMPLIANT - exact type match + l1 *l3; // COMPLIANT - widening conversion is allowed + l1 *l4; // NON_COMPLIANT - different type + l1 *l5; // NON_COMPLIANT - different signedness + + l1 / l2; // COMPLIANT - exact type match + l1 / l3; // COMPLIANT - widening conversion is allowed + l1 / l4; // NON_COMPLIANT - different type + l1 / l5; // NON_COMPLIANT - different signedness + + l1 % l2; // COMPLIANT - exact type match + l1 % l3; // COMPLIANT - widening conversion is allowed + l1 % l4; // NON_COMPLIANT - different type + l1 % l5; // NON_COMPLIANT - different signedness + + l1 &l2; // COMPLIANT - exact type match + l1 &l3; // COMPLIANT - widening conversion is allowed + l1 &l4; // NON_COMPLIANT - different type + l1 &l5; // NON_COMPLIANT - different signedness + + l1 | l2; // COMPLIANT - exact type match + l1 | l3; // COMPLIANT - widening conversion is allowed + l1 | l4; // NON_COMPLIANT - different type + l1 | l5; // NON_COMPLIANT - different signedness + + l1 ^ l2; // COMPLIANT - exact type match + l1 ^ l3; // COMPLIANT - widening conversion is allowed + l1 ^ l4; // NON_COMPLIANT - different type + l1 ^ l5; // NON_COMPLIANT - different signedness + + l1 << l2; // COMPLIANT - exact type match + l1 << l3; // COMPLIANT - widening conversion is allowed + l1 << l4; // NON_COMPLIANT - different type + l1 << l5; // NON_COMPLIANT - different signedness + + l1 >> l2; // COMPLIANT - exact type match + l1 >> l3; // COMPLIANT - widening conversion is allowed + l1 >> l4; // NON_COMPLIANT - different type + l1 >> l5; // NON_COMPLIANT - different signedness + + // Comparison operators + l1 == l2; // COMPLIANT - exact type match + l1 == l3; // COMPLIANT - widening conversion is allowed + l1 == l4; // NON_COMPLIANT - different type + l1 == l5; // NON_COMPLIANT - different signedness + + l1 != l2; // COMPLIANT - exact type match + l1 != l3; // COMPLIANT - widening conversion is allowed + l1 != l4; // NON_COMPLIANT - different type + l1 != l5; // NON_COMPLIANT - different signedness + + l1 < l2; // COMPLIANT - exact type match + l1 < l3; // COMPLIANT - widening conversion is allowed + l1 < l4; // NON_COMPLIANT - different type + l1 < l5; // NON_COMPLIANT - different signedness + + l1 <= l2; // COMPLIANT - exact type match + l1 <= l3; // COMPLIANT - widening conversion is allowed + l1 <= l4; // NON_COMPLIANT - different type + l1 <= l5; // NON_COMPLIANT + + l1 > l2; // COMPLIANT - exact type match + l1 > l3; // COMPLIANT - widening conversion is allowed + l1 > l4; // NON_COMPLIANT + l1 > l5; // NON_COMPLIANT - different signedness + + l1 >= l2; // COMPLIANT - exact type match + l1 >= l3; // COMPLIANT - widening conversion is allowed + l1 >= l4; // NON_COMPLIANT + l1 >= l5; // NON_COMPLIANT - different signedness + + // Subscript operator + l1[l2]; // COMPLIANT - exact type match + l1[l3]; // COMPLIANT - widening conversion is allowed + l1[l4]; // NON_COMPLIANT - different type + l1[l5]; // NON_COMPLIANT - different signedness + + // Function call operator + l1(l2); // COMPLIANT - exact type match + l1(l3); // COMPLIANT - widening conversion is allowed + l1(l4); // NON_COMPLIANT - different type + l1(l5); // NON_COMPLIANT - different signedness + l1(l2, l2); // COMPLIANT - both exact type match + l1(l2, l4); // NON_COMPLIANT - second parameter different type + l1(l4, l2); // NON_COMPLIANT - first parameter different type + l1(l4, l5); // NON_COMPLIANT - both parameters different type + + // The presence of a default copy constructor for UserDefinedOperators means + // that assignments through operator= must be exact type matches. + l1 = l2; // COMPLIANT - exact type match + l1 = l3; // NON_COMPLIANT + l1 = l4; // NON_COMPLIANT + l1 = l5; // NON_COMPLIANT + + l1 += l2; // COMPLIANT - exact type match + l1 += l3; // COMPLIANT - widening conversion is allowed + l1 += l4; // NON_COMPLIANT - different type + l1 += l5; // NON_COMPLIANT - different signedness + + l1 -= l2; // COMPLIANT - exact type match + l1 -= l3; // COMPLIANT - widening conversion is allowed + l1 -= l4; // NON_COMPLIANT - different type + l1 -= l5; // NON_COMPLIANT - different signedness + + l1 *= l2; // COMPLIANT - exact type match + l1 *= l3; // COMPLIANT - widening conversion is allowed + l1 *= l4; // NON_COMPLIANT - different type + l1 *= l5; // NON_COMPLIANT - different signedness + + l1 /= l2; // COMPLIANT - exact type match + l1 /= l3; // COMPLIANT - widening conversion is allowed + l1 /= l4; // NON_COMPLIANT - different type + l1 /= l5; // NON_COMPLIANT - different signedness + + l1 %= l2; // COMPLIANT - exact type match + l1 %= l3; // COMPLIANT - widening conversion is allowed + l1 %= l4; // NON_COMPLIANT - different type + l1 %= l5; // NON_COMPLIANT - different signedness + + l1 &= l2; // COMPLIANT - exact type match + l1 &= l3; // COMPLIANT - widening conversion is allowed + l1 &= l4; // NON_COMPLIANT - different type + l1 &= l5; // NON_COMPLIANT - different signedness + + l1 |= l2; // COMPLIANT - exact type match + l1 |= l3; // COMPLIANT - widening conversion is allowed + l1 |= l4; // NON_COMPLIANT - different type + l1 |= l5; // NON_COMPLIANT - different signedness + + l1 ^= l2; // COMPLIANT - exact type match + l1 ^= l3; // COMPLIANT - widening conversion is allowed + l1 ^= l4; // NON_COMPLIANT - different type + l1 ^= l5; // NON_COMPLIANT - different signedness + + l1 <<= l2; // COMPLIANT - exact type match + l1 <<= l3; // COMPLIANT - widening conversion is allowed + l1 <<= l4; // NON_COMPLIANT - different type + l1 <<= l5; // NON_COMPLIANT - different signedness + + l1 >>= l2; // COMPLIANT - exact type match + l1 >>= l3; // COMPLIANT - widening conversion is allowed + l1 >>= l4; // NON_COMPLIANT - different type + l1 >>= l5; // NON_COMPLIANT - different signedness + + // Global operators + l2 + l1; // COMPLIANT - exact type match + l3 + l1; // COMPLIANT - widening conversion is allowed + l4 + l1; // NON_COMPLIANT - different type + l5 + l1; // NON_COMPLIANT - different signedness + + l2 - l1; // COMPLIANT - exact type match + l3 - l1; // COMPLIANT - widening conversion is allowed + l4 - l1; // NON_COMPLIANT - different type + l5 - l1; // NON_COMPLIANT - different signedness + + l2 == l1; // COMPLIANT - exact type match + l3 == l1; // COMPLIANT - widening conversion is allowed + l4 == l1; // NON_COMPLIANT - different type + l5 == l1; // NON_COMPLIANT - different signedness +} + +// Test user-defined operators with constants +void test_user_defined_operators_constants() { + UserDefinedOperators l1{42}; + + // Constants with exact type match + l1 + 42; // COMPLIANT + l1 + 42L; // COMPLIANT + l1 + 42LL; // COMPLIANT + l1 + 42U; // COMPLIANT + l1 + 42.0f; // NON_COMPLIANT - float constant + + l1 == 42; // COMPLIANT - integer constant is int/int32_t + l1 == 42L; // COMPLIANT - long constant + l1 == 42LL; // COMPLIANT - long long constant + l1 == 42U; // COMPLIANT - unsigned constant + + l1[42]; // COMPLIANT - integer constant is int/int32_t + l1[42L]; // COMPLIANT - long constant + l1[42LL]; // COMPLIANT - long long constant + l1[42U]; // COMPLIANT - unsigned constant + + // The presence of a default copy constructor for UserDefinedOperators means + // that assignments through operator= must be exact type matches. + l1 = 42; // COMPLIANT - integer constant is int/int32_t + l1 = 42L; // NON_COMPLIANT + l1 = 42LL; // NON_COMPLIANT + l1 = 42U; // NON_COMPLIANT +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-6/test_specified.cpp b/cpp/misra/test/rules/RULE-7-0-6/test_specified.cpp new file mode 100644 index 0000000000..dc58ade311 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-6/test_specified.cpp @@ -0,0 +1,371 @@ +#include +#include + +// Global variables for testing +std::uint32_t u32; +std::int32_t s32; +std::uint8_t u8; +std::int8_t s8; +std::uint16_t u16; +std::int16_t s16; +std::uint64_t u64; +std::int64_t s64; +float f; +double d; + +// Test cv-qualified types +void test_cv_qualified_const() { + const std::uint8_t l1 = 42; // COMPLIANT + const std::uint16_t l2 = 1000; // COMPLIANT + const std::uint32_t l3 = 50000; // COMPLIANT + const std::int8_t l4 = -5; // COMPLIANT + const std::int16_t l5 = -1000; // COMPLIANT + const std::int32_t l6 = -50000; // COMPLIANT + const float l7 = 3.14f; // COMPLIANT + const double l8 = 2.718; // COMPLIANT + + // Widening of const id-expressions - allowed + // Also allowed because the integer constant expressions are within the range + u16 = l1; // COMPLIANT + u32 = l1; // COMPLIANT + u32 = l2; // COMPLIANT + s16 = l4; // COMPLIANT + s32 = l4; // COMPLIANT + s32 = l5; // COMPLIANT + + // Narrowing of const id-expressions - not allowed + u8 = l2; // NON_COMPLIANT + u8 = l3; // NON_COMPLIANT + // Permitted because the integer constant expression is within the range + u16 = l3; // COMPLIANT + s8 = l5; // NON_COMPLIANT + s8 = l6; // NON_COMPLIANT + s16 = l6; // NON_COMPLIANT + + // Incorrect signedness conversions, and the integer constant + // expressions are not in the range of the target type (as they are all + // negative) + u8 = l4; // NON_COMPLIANT + u16 = l5; // NON_COMPLIANT + u32 = l6; // NON_COMPLIANT + // These are signedness violations, but as they are integer constant + // expressions within range they are allowed + s8 = l1; // COMPLIANT + s16 = l2; // COMPLIANT + s32 = l3; // COMPLIANT + + // Type category errors (int to float) + s32 = l7; // NON_COMPLIANT + s32 = l8; // NON_COMPLIANT + // These are not type category errors, as they are integer constant + // expressions whose value fits within both floating point types, as the range + // is infinite + f = l4; // COMPLIANT + f = l5; // COMPLIANT + f = l6; // COMPLIANT + d = l4; // COMPLIANT + d = l5; // COMPLIANT + d = l6; // COMPLIANT + + // Size violations within same type category with const + f = l8; // NON_COMPLIANT + d = l7; // COMPLIANT +} + +void test_cv_qualified_volatile() { + volatile std::uint8_t l1 = 42; + volatile std::uint16_t l2 = 1000; + volatile std::uint32_t l3 = 50000; + volatile std::int8_t l4 = -5; + volatile std::int16_t l5 = -1000; + volatile std::int32_t l6 = -50000; + volatile float l7 = 3.14f; + volatile double l8 = 2.718; + + // Widening of volatile id-expressions - allowed + u16 = l1; // COMPLIANT + u32 = l1; // COMPLIANT + u32 = l2; // COMPLIANT + s16 = l4; // COMPLIANT + s32 = l4; // COMPLIANT + s32 = l5; // COMPLIANT + + // Narrowing of volatile id-expressions - not allowed + u8 = l2; // NON_COMPLIANT + u8 = l3; // NON_COMPLIANT + u16 = l3; // NON_COMPLIANT + s8 = l5; // NON_COMPLIANT + s8 = l6; // NON_COMPLIANT + s16 = l6; // NON_COMPLIANT + + // Signedness violations with volatile + u8 = l4; // NON_COMPLIANT + u16 = l5; // NON_COMPLIANT + u32 = l6; // NON_COMPLIANT + s8 = l1; // NON_COMPLIANT + s16 = l2; // NON_COMPLIANT + s32 = l3; // NON_COMPLIANT + + // Type category violations with volatile + s32 = l7; // NON_COMPLIANT + s32 = l8; // NON_COMPLIANT + f = l4; // NON_COMPLIANT + f = l5; // NON_COMPLIANT + f = l6; // NON_COMPLIANT + d = l4; // NON_COMPLIANT + d = l5; // NON_COMPLIANT + d = l6; // NON_COMPLIANT + + // Size violations within same type category with volatile + f = l8; // NON_COMPLIANT + d = l7; // COMPLIANT +} + +void test_cv_qualified_const_volatile() { + const volatile std::uint8_t l1 = 42; + const volatile std::uint16_t l2 = 1000; + const volatile std::uint32_t l3 = 50000; + const volatile std::int8_t l4 = -5; + const volatile std::int16_t l5 = -1000; + const volatile std::int32_t l6 = -50000; + const volatile float l7 = 3.14f; + const volatile double l8 = 2.718; + + // Widening of const volatile id-expressions - allowed + u16 = l1; // COMPLIANT + u32 = l1; // COMPLIANT + u32 = l2; // COMPLIANT + s16 = l4; // COMPLIANT + s32 = l4; // COMPLIANT + s32 = l5; // COMPLIANT + + // Narrowing of const volatile id-expressions - not allowed + u8 = l2; // NON_COMPLIANT + u8 = l3; // NON_COMPLIANT + u16 = l3; // NON_COMPLIANT + s8 = l5; // NON_COMPLIANT + s8 = l6; // NON_COMPLIANT + s16 = l6; // NON_COMPLIANT + + // Signedness violations with const volatile + u8 = l4; // NON_COMPLIANT + u16 = l5; // NON_COMPLIANT + u32 = l6; // NON_COMPLIANT + s8 = l1; // NON_COMPLIANT + s16 = l2; // NON_COMPLIANT + s32 = l3; // NON_COMPLIANT + + // Type category violations with const volatile + s32 = l7; // NON_COMPLIANT + s32 = l8; // NON_COMPLIANT + f = l4; // NON_COMPLIANT + f = l5; // NON_COMPLIANT + f = l6; // NON_COMPLIANT + d = l4; // NON_COMPLIANT + d = l5; // NON_COMPLIANT + d = l6; // NON_COMPLIANT + + // Size violations within same type category with const volatile + f = l8; // NON_COMPLIANT + d = l7; // COMPLIANT +} + +// Test cv-qualified references +void test_cv_qualified_references() { + std::uint8_t l1 = 42; + std::uint16_t l2 = 1000; + std::int8_t l3 = -5; + float l4 = 3.14f; + + const std::uint8_t &l5 = l1; + const std::uint16_t &l6 = l2; + const std::int8_t &l7 = l3; + const float &l8 = l4; + + volatile std::uint8_t &l9 = l1; + volatile std::uint16_t &l10 = l2; + volatile std::int8_t &l11 = l3; + volatile float &l12 = l4; + + const volatile std::uint8_t &l13 = l1; + const volatile std::uint16_t &l14 = l2; + const volatile std::int8_t &l15 = l3; + const volatile float &l16 = l4; + + // Widening through cv-qualified references - allowed + u16 = l5; // COMPLIANT + u32 = l5; // COMPLIANT + u32 = l6; // COMPLIANT + s16 = l7; // COMPLIANT + s32 = l7; // COMPLIANT + u16 = l9; // COMPLIANT + u32 = l9; // COMPLIANT + u32 = l10; // COMPLIANT + s16 = l11; // COMPLIANT + s32 = l11; // COMPLIANT + u16 = l13; // COMPLIANT + u32 = l13; // COMPLIANT + u32 = l14; // COMPLIANT + s16 = l15; // COMPLIANT + s32 = l15; // COMPLIANT + + // Narrowing through cv-qualified references - not allowed + u8 = l6; // NON_COMPLIANT + u8 = l10; // NON_COMPLIANT + u8 = l14; // NON_COMPLIANT + + // Signedness violations through cv-qualified references + s8 = l5; // NON_COMPLIANT + u8 = l7; // NON_COMPLIANT + s8 = l9; // NON_COMPLIANT + u8 = l11; // NON_COMPLIANT + s8 = l13; // NON_COMPLIANT + u8 = l15; // NON_COMPLIANT + + // Type category violations through cv-qualified references + s32 = l8; // NON_COMPLIANT + s32 = l12; // NON_COMPLIANT + s32 = l16; // NON_COMPLIANT + f = l3; // NON_COMPLIANT + f = l7; // NON_COMPLIANT + f = l11; // NON_COMPLIANT + f = l15; // NON_COMPLIANT +} + +// Test cv-qualified function parameters +void f15(const std::uint32_t l1) {} +void f16(volatile std::int64_t l1) {} +void f17(const volatile std::uint16_t l1) {} + +void test_cv_qualified_function_parameters() { + const std::uint8_t l1 = 42; + volatile std::uint16_t l2 = 1000; + const volatile std::int8_t l3 = -5; + + f15(l1); // NON_COMPLIANT + f15(l2); // NON_COMPLIANT + f16(l3); // NON_COMPLIANT + f17(l1); // NON_COMPLIANT + f17(l2); // COMPLIANT + f17(l3); // NON_COMPLIANT +} + +// Test cv-qualified static and namespace variables +namespace CVNamespace { +const std::uint8_t g3 = 42; +volatile std::uint16_t g4 = 1000; +const volatile std::int8_t g5 = -5; +} // namespace CVNamespace + +struct CVStruct { + static const std::uint8_t s3; + static volatile std::uint16_t s4; + static const volatile std::int8_t s5; +}; + +const std::uint8_t CVStruct::s3 = 42; +volatile std::uint16_t CVStruct::s4 = 1000; +const volatile std::int8_t CVStruct::s5 = -5; + +void test_cv_qualified_static_and_namespace() { + // Widening of cv-qualified namespace and static variables - allowed + u16 = CVNamespace::g3; // COMPLIANT + u32 = CVNamespace::g3; // COMPLIANT + u32 = CVNamespace::g4; // COMPLIANT + s16 = CVNamespace::g5; // COMPLIANT + s32 = CVNamespace::g5; // COMPLIANT + + u16 = CVStruct::s3; // COMPLIANT + u32 = CVStruct::s3; // COMPLIANT + u32 = CVStruct::s4; // COMPLIANT + s16 = CVStruct::s5; // COMPLIANT + s32 = CVStruct::s5; // COMPLIANT + + // Narrowing of cv-qualified namespace and static variables - not allowed + u8 = CVNamespace::g4; // NON_COMPLIANT + s8 = CVNamespace::g5; // COMPLIANT - constant fits + u8 = CVStruct::s4; // NON_COMPLIANT + s8 = CVStruct::s5; // COMPLIANT - constant fits + + // Signedness violations with cv-qualified namespace and static variables + s8 = CVNamespace::g3; // COMPLIANT - constant expression + u16 = CVNamespace::g5; // NON_COMPLIANT + s8 = CVStruct::s3; // COMPLIANT - constant expression + u16 = CVStruct::s5; // NON_COMPLIANT +} + +// Test cv-qualified bitfields +struct CVBitfieldStruct { + const std::uint32_t m11 : 8; + volatile std::uint32_t m12 : 16; + const volatile std::int32_t m13 : 12; +}; + +void test_cv_qualified_bitfields() { + CVBitfieldStruct l1{100, 30000, -500}; // COMPLIANT + + // CV-qualified bitfields follow same rules as regular bitfields + CVBitfieldStruct l2{300, 70000, 3000}; // NON_COMPLIANT + l2.m12 = 70000; // NON_COMPLIANT + + CVBitfieldStruct l3{u8, u16, s16}; // COMPLIANT + l1.m12 = u16; // COMPLIANT + + CVBitfieldStruct l4{u16, u32, s32}; // NON_COMPLIANT +} + +// Test cv-qualified enums +enum CVColour : std::uint16_t { cv_red, cv_green, cv_blue }; + +void test_cv_qualified_enums() { + const CVColour l1 = cv_red; + volatile CVColour l2 = cv_green; + const volatile CVColour l3 = cv_blue; + + u8 = cv_red; // COMPLIANT + u32 = cv_red; // COMPLIANT + u8 = l1; // COMPLIANT - constant fits in uint8_t + u32 = l1; // COMPLIANT + u8 = l2; // NON_COMPLIANT + u32 = l2; // COMPLIANT + u8 = l3; // NON_COMPLIANT + u32 = l3; // COMPLIANT +} + +// Test cv-qualified expressions with operators +void test_cv_qualified_expressions() { + const std::uint8_t l1 = 10; + volatile std::uint8_t l2 = 20; + const volatile std::uint8_t l3 = 30; + + // Expressions with cv-qualified operands still follow expression rules + u8 = l1 + l2; // NON_COMPLIANT + u8 = l1 + l3; // NON_COMPLIANT + u8 = l2 + l3; // NON_COMPLIANT + s32 = l1 + l2; // COMPLIANT + s32 = l1 + l3; // COMPLIANT + s32 = l2 + l3; // COMPLIANT + + // Parenthesized cv-qualified expressions are not id-expressions + u32 = (l1); // COMPLIANT - constant expression fits + u32 = (l2); // NON_COMPLIANT + u32 = (l3); // NON_COMPLIANT +} + +// Test cv-qualified aggregate initialization +struct CVAggregate { + const std::uint8_t m1; + volatile std::uint16_t m2; + const volatile std::int32_t m3; +}; + +void test_cv_qualified_aggregate_initialization() { + const std::uint8_t l1 = 42; + volatile std::uint16_t l2 = 1000; + const volatile std::int8_t l3 = -5; + + // CV-qualified aggregate members follow same rules + CVAggregate l4{10, 100, -50}; // COMPLIANT + CVAggregate l5{l1, l2, l3}; // COMPLIANT + CVAggregate l6{300, 70000, l3}; // NON_COMPLIANT +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-11-1/NullptrNotTheOnlyFormOfTheNullPointerConstant.testref b/cpp/misra/test/rules/RULE-7-11-1/NullptrNotTheOnlyFormOfTheNullPointerConstant.testref new file mode 100644 index 0000000000..aeb655a341 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-11-1/NullptrNotTheOnlyFormOfTheNullPointerConstant.testref @@ -0,0 +1 @@ +cpp/common/test/rules/nullptrnottheonlyformofthenullpointerconstant/NullptrNotTheOnlyFormOfTheNullPointerConstant.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-11-2/ArrayPassedAsFunctionArgumentDecayToAPointer.testref b/cpp/misra/test/rules/RULE-7-11-2/ArrayPassedAsFunctionArgumentDecayToAPointer.testref new file mode 100644 index 0000000000..06f2ec8fbb --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-11-2/ArrayPassedAsFunctionArgumentDecayToAPointer.testref @@ -0,0 +1 @@ +cpp/common/test/rules/arraypassedasfunctionargumentdecaytoapointer/ArrayPassedAsFunctionArgumentDecayToAPointer.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-11-3/FunctionPointerConversionContext.expected b/cpp/misra/test/rules/RULE-7-11-3/FunctionPointerConversionContext.expected new file mode 100644 index 0000000000..be07c4b103 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-11-3/FunctionPointerConversionContext.expected @@ -0,0 +1,16 @@ +| test.cpp:11:7:11:7 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:14:7:14:7 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:18:16:18:16 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:21:14:21:14 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:25:7:25:7 | call to operator void (*)() | Inappropriate conversion from function type to pointer-to-function type in 'call to operator void (*)()'. | +| test.cpp:33:14:33:14 | call to operator void (*)() | Inappropriate conversion from function type to pointer-to-function type in 'call to operator void (*)()'. | +| test.cpp:61:13:61:13 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:64:13:64:13 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:67:7:67:7 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:71:7:71:7 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:74:7:74:7 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:77:7:77:7 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:83:7:83:7 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:87:7:87:7 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:92:7:92:7 | call to operator void (*)() | Inappropriate conversion from function type to pointer-to-function type in 'call to operator void (*)()'. | +| test.cpp:96:7:96:7 | call to operator void (*)() | Inappropriate conversion from function type to pointer-to-function type in 'call to operator void (*)()'. | diff --git a/cpp/misra/test/rules/RULE-7-11-3/FunctionPointerConversionContext.qlref b/cpp/misra/test/rules/RULE-7-11-3/FunctionPointerConversionContext.qlref new file mode 100644 index 0000000000..d05d05586b --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-11-3/FunctionPointerConversionContext.qlref @@ -0,0 +1 @@ +rules/RULE-7-11-3/FunctionPointerConversionContext.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-11-3/test.cpp b/cpp/misra/test/rules/RULE-7-11-3/test.cpp new file mode 100644 index 0000000000..0522a703fc --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-11-3/test.cpp @@ -0,0 +1,98 @@ +#include +#include + +// Test functions +extern int *f(); +void f1(double); +void f1(std::uint32_t); +void simple_function(); + +void test_function_to_pointer_conversion() { + if (f) { // NON_COMPLIANT + } + + if (f == nullptr) { // NON_COMPLIANT + } + + std::cout << std::boolalpha // COMPLIANT - considered assignment + << f; // NON_COMPLIANT - not assignment + + // Non-compliant: Unary plus operator causing pointer decay + auto l1 = +f; // NON_COMPLIANT + + auto lam = []() {}; + // Lambda used in boolean context + if (lam) { // NON_COMPLIANT + } + + // Lambda used in address-of operator + if (&lam) { // COMPLIANT + } + + // Unary plus on lambda + auto l2 = +lam; // NON_COMPLIANT + + // Using address-of operator + if (&f != nullptr) { // COMPLIANT + } + + // Function call + (f)(); // COMPLIANT + lam(); // COMPLIANT + + // static_cast conversion + auto selected = static_cast(f1); // COMPLIANT + + // Assignment to pointer-to-function type + void (*p)() = lam; // COMPLIANT + + // Assignment to pointer-to-function type + int *(*func_ptr)() = f; // COMPLIANT + + // Using address-of operator + void (*simple_ptr)() = &simple_function; // COMPLIANT + + // Direct assignment without conversion + void (*simple_ptr2)() = simple_function; // COMPLIANT +} + +void test_arithmetic_expressions() { + // Function used in arithmetic expression (triggers pointer decay) + auto l3 = f + 0; // NON_COMPLIANT + + // Function used in arithmetic subtraction expression + auto l4 = f - 0; // NON_COMPLIANT + + // Function used in comparison with non-null pointer + if (f > nullptr) { // NON_COMPLIANT + } + + // Function used in relational operators + if (f < nullptr) { // NON_COMPLIANT + } + + if (f <= nullptr) { // NON_COMPLIANT + } + + if (f >= nullptr) { // NON_COMPLIANT + } +} + +void test_logical_expressions() { + // Function used in logical AND expression + if (f && true) { // NON_COMPLIANT + } + + // Function used in logical OR expression + if (f || false) { // NON_COMPLIANT + } + + // Lambda used in logical AND expression + auto lam = []() {}; + if (lam && true) { // NON_COMPLIANT + } + + // Lambda used in logical OR expression + if (lam || false) { // NON_COMPLIANT + } +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-18-2/ResultOfAnAssignmentOperatorShouldNotBeUsed.testref b/cpp/misra/test/rules/RULE-8-18-2/ResultOfAnAssignmentOperatorShouldNotBeUsed.testref new file mode 100644 index 0000000000..1e29dba140 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-18-2/ResultOfAnAssignmentOperatorShouldNotBeUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/resultofanassignmentoperatorshouldnotbeused/ResultOfAnAssignmentOperatorShouldNotBeUsed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-19-1/CommaOperatorShouldNotBeUsed.testref b/cpp/misra/test/rules/RULE-8-19-1/CommaOperatorShouldNotBeUsed.testref new file mode 100644 index 0000000000..845133096b --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-19-1/CommaOperatorShouldNotBeUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/commaoperatorused/CommaOperatorUsed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.testref b/cpp/misra/test/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.testref new file mode 100644 index 0000000000..475d3fd8be --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.testref @@ -0,0 +1 @@ +cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-2-10/FunctionsCallThemselvesEitherDirectlyOrIndirectly.testref b/cpp/misra/test/rules/RULE-8-2-10/FunctionsCallThemselvesEitherDirectlyOrIndirectly.testref new file mode 100644 index 0000000000..f459a29bf1 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-10/FunctionsCallThemselvesEitherDirectlyOrIndirectly.testref @@ -0,0 +1 @@ +cpp/common/test/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.expected b/cpp/misra/test/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.expected new file mode 100644 index 0000000000..a2b3b522cc --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.expected @@ -0,0 +1,7 @@ +| test.cpp:8:22:8:37 | (uint32_t)... | Use of explicit c-style cast to uint32_t. | +| test.cpp:9:22:9:32 | (unsigned int)... | Use of explicit c-style cast to unsigned int. | +| test.cpp:70:1:70:31 | #define ADD_ONE(x) ((int)x) + 1 | Use of explicit c-style cast to int. | +| test.cpp:83:19:83:26 | (int)... | Use of explicit c-style cast to int. | +| test.cpp:84:27:84:34 | (int)... | Use of explicit c-style cast to int. | +| test.cpp:112:10:112:13 | (int)... | Use of explicit c-style cast to int. | +| test.cpp:147:12:147:26 | (unsigned int)... | Use of explicit c-style cast to unsigned int. | diff --git a/cpp/misra/test/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.qlref b/cpp/misra/test/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.qlref new file mode 100644 index 0000000000..cbd07ad124 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.qlref @@ -0,0 +1 @@ +rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-2-2/test.cpp b/cpp/misra/test/rules/RULE-8-2-2/test.cpp new file mode 100644 index 0000000000..3d57d7f3c8 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-2/test.cpp @@ -0,0 +1,158 @@ +#include +#include +#include +int foo() { return 1; } +// A copy of A5-2-2 test.cpp, but with different cases compliant/non-compliant +void test_c_style_cast() { + double f = 3.14; + std::uint32_t n1 = (std::uint32_t)f; // NON_COMPLIANT - C-style cast + std::uint32_t n2 = unsigned(f); // NON_COMPLIANT - functional notation + + std::uint8_t n3 = 1; + std::uint8_t n4 = 1; + std::uint8_t n5 = n3 + n4; // ignored, implicit casts + + (void)foo(); // COMPLIANT - permitted by MISRA C++ +} + +class A { +public: + virtual void f1() {} +}; + +class B : A { +public: + virtual void f1() {} +}; + +class C { + void f1() {} +}; + +void test_cpp_style_cast() { + // These cases may contravene other rules, but are marked as COMPLIANT for + // this rule + A a1; + const A *a2 = &a1; + A *a3 = const_cast(a2); // COMPLIANT + B *b = dynamic_cast(a3); // COMPLIANT + C *c = reinterpret_cast(a3); // COMPLIANT + std::int16_t n8 = 0; + std::int32_t n9 = static_cast(n8); // COMPLIANT + static_cast(foo()); // COMPLIANT +} + +class A5_2_2a { +public: + template + static void Foo(const std::string &name, As &&...rest) { + Fun(Log(std::forward( + rest)...)); // COMPLIANT - previously reported as a false positive + } + + template static std::string Log(As &&...tail) { + return std::string(); + } + + static void Fun(const std::string &message) {} +}; + +class A5_2_2 final { +public: + void f(const std::string &s) const { A5_2_2a::Foo("name", "x", "y", "z"); } +}; + +void a5_2_2_test() { + A5_2_2 a; + a.f(""); +} + +#define ADD_ONE(x) ((int)x) + 1 // NON_COMPLIANT +#define NESTED_ADD_ONE(x) ADD_ONE(x) // Not reported - reported at ADD_ONE +#define NO_CAST_ADD_ONE(x) x + 1 // COMPLIANT + +#include "macro_c_style_casts.h" + +void test_macro_cast() { + ADD_ONE(1); // Reported at macro definition site + NESTED_ADD_ONE(1); // reported at macro definition site + LIBRARY_ADD_TWO(1); // COMPLIANT - macro generating the cast is defined in a + // library, and is not modifiable by the user + LIBRARY_NESTED_ADD_TWO(1); // COMPLIANT - macro generating the cast is defined + // in a library, and is not modifiable by the user + NO_CAST_ADD_ONE((int)1.0); // NON_COMPLIANT - cast in argument to macro + LIBRARY_NO_CAST_ADD_TWO((int)1.0); // NON_COMPLIANT - library macro with + // c-style cast in argument, written by + // user so should be reported +} + +class D { +public: + D(int x) : fx(x), fy(0) {} + D(int x, int y) : fx(x), fy(y) {} + +private: + int fx; + int fy; +}; + +D testNonFunctionalCast() { + return (D)1; // COMPLIANT +} + +D testFunctionalCast() { + return D(1); // COMPLIANT +} + +D testFunctionalCastMulti() { + return D(1, 2); // COMPLIANT +} + +template T testFunctionalCastTemplate() { + return T(1); // NON_COMPLIANT - used with an int +} + +template T testFunctionalCastTemplateMulti() { + return T(1, 2); // COMPLIANT +} + +void testFunctionalCastTemplateUse() { + testFunctionalCastTemplate(); + testFunctionalCastTemplate(); + testFunctionalCastTemplateMulti(); +} + +template class E { +public: + class F { + public: + F(int x) : fx(x), fy(0) {} + F(int x, int y) : fx(x), fy(y) {} + + private: + int fx; + int fy; + }; + + F f() { + return F(1); // COMPLIANT + } + + D d() { + return D(1); // COMPLIANT + } + + int i() { + double f = 3.14; + return (unsigned int)f; // NON_COMPLIANT + } +}; + +class G {}; + +void testE() { + E e; + e.f(); + e.d(); + e.i(); +} diff --git a/cpp/misra/test/rules/RULE-8-2-3/CastRemovesConstOrVolatileFromPointerOrReference.testref b/cpp/misra/test/rules/RULE-8-2-3/CastRemovesConstOrVolatileFromPointerOrReference.testref new file mode 100644 index 0000000000..000469493a --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-3/CastRemovesConstOrVolatileFromPointerOrReference.testref @@ -0,0 +1 @@ +cpp/common/test/rules/removeconstorvolatilequalification/RemoveConstOrVolatileQualification.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-2-4/CastsBetweenAPointerToFunctionAndAnyOtherType.testref b/cpp/misra/test/rules/RULE-8-2-4/CastsBetweenAPointerToFunctionAndAnyOtherType.testref new file mode 100644 index 0000000000..e7bde2ea08 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-4/CastsBetweenAPointerToFunctionAndAnyOtherType.testref @@ -0,0 +1 @@ +cpp/common/test/rules/castsbetweenapointertofunctionandanyothertype/CastsBetweenAPointerToFunctionAndAnyOtherType.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-2-5/ReinterpretCastShallNotBeUsed.testref b/cpp/misra/test/rules/RULE-8-2-5/ReinterpretCastShallNotBeUsed.testref new file mode 100644 index 0000000000..81f18c2d9c --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-5/ReinterpretCastShallNotBeUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/reinterpretcastused/ReinterpretCastUsed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-2-6/IntToPointerCastProhibited.expected b/cpp/misra/test/rules/RULE-8-2-6/IntToPointerCastProhibited.expected new file mode 100644 index 0000000000..18accdc95e --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-6/IntToPointerCastProhibited.expected @@ -0,0 +1,11 @@ +| test.cpp:15:20:15:53 | reinterpret_cast... | Cast from integral type 'int32_t' to pointer type 'TestStruct *'. | +| test.cpp:16:20:16:53 | reinterpret_cast... | Cast from integral type 'int64_t' to pointer type 'TestStruct *'. | +| test.cpp:17:22:17:57 | reinterpret_cast... | Cast from integral type 'int64_t' to pointer type 'int32_t *'. | +| test.cpp:24:20:24:53 | reinterpret_cast... | Cast from enumerated type 'TestEnum' to pointer type 'TestStruct *'. | +| test.cpp:25:22:25:57 | reinterpret_cast... | Cast from enumerated type 'TestEnum' to pointer type 'int32_t *'. | +| test.cpp:32:20:32:48 | static_cast... | Cast from pointer to void type 'void *' to pointer type 'TestStruct *'. | +| test.cpp:33:20:33:53 | reinterpret_cast... | Cast from pointer to void type 'void *' to pointer type 'TestStruct *'. | +| test.cpp:34:22:34:52 | static_cast... | Cast from pointer to void type 'void *' to pointer type 'int32_t *'. | +| test.cpp:35:22:35:57 | reinterpret_cast... | Cast from pointer to void type 'void *' to pointer type 'int32_t *'. | +| test.cpp:43:14:43:41 | reinterpret_cast... | Cast from integral type 'int32_t' to pointer type 'void *'. | +| test.cpp:44:14:44:41 | reinterpret_cast... | Cast from integral type 'int64_t' to pointer type 'void *'. | diff --git a/cpp/misra/test/rules/RULE-8-2-6/IntToPointerCastProhibited.qlref b/cpp/misra/test/rules/RULE-8-2-6/IntToPointerCastProhibited.qlref new file mode 100644 index 0000000000..c6f30b00f6 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-6/IntToPointerCastProhibited.qlref @@ -0,0 +1 @@ +rules/RULE-8-2-6/IntToPointerCastProhibited.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-2-6/test.cpp b/cpp/misra/test/rules/RULE-8-2-6/test.cpp new file mode 100644 index 0000000000..5abd52242e --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-6/test.cpp @@ -0,0 +1,90 @@ +#include + +struct TestStruct { + std::int32_t m1; + std::int32_t m2; +}; + +enum TestEnum { VALUE1, VALUE2 }; + +void test_integral_to_pointer_cast() { + std::int32_t l1 = 42; + std::int64_t l2 = 0x1000; + + // Casting integral types to pointer types + TestStruct *l4 = reinterpret_cast(l1); // NON_COMPLIANT + TestStruct *l5 = reinterpret_cast(l2); // NON_COMPLIANT + std::int32_t *l7 = reinterpret_cast(l2); // NON_COMPLIANT +} + +void test_enumerated_to_pointer_cast() { + TestEnum l1 = VALUE1; + + // Casting enumerated types to pointer types + TestStruct *l3 = reinterpret_cast(l1); // NON_COMPLIANT + std::int32_t *l5 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_void_pointer_to_object_pointer_cast() { + void *l1 = nullptr; + + // Casting void pointer to object pointer types + TestStruct *l2 = static_cast(l1); // NON_COMPLIANT + TestStruct *l3 = reinterpret_cast(l1); // NON_COMPLIANT + std::int32_t *l4 = static_cast(l1); // NON_COMPLIANT + std::int32_t *l5 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_integral_to_void_pointer_cast() { + std::int32_t l1 = 42; + std::int64_t l2 = 0x1000; + + // Casting integral types to void pointer + void *l3 = reinterpret_cast(l1); // NON_COMPLIANT + void *l4 = reinterpret_cast(l2); // NON_COMPLIANT +} + +void test_compliant_void_pointer_casts() { + void *l1 = nullptr; + const void *l2 = nullptr; + + // Casts between void pointers are allowed + const void *l3 = const_cast(l1); // COMPLIANT + void *l4 = const_cast(l2); // COMPLIANT + volatile void *l5 = static_cast(l1); // COMPLIANT +} + +void f1() {} +void f2(int) {} + +void test_compliant_function_pointer_exceptions() { + std::int64_t l1 = 0x1000; + + // Function pointer casts are exceptions to this rule + void (*l2)() = reinterpret_cast(l1); // COMPLIANT + void (*l3)(int) = reinterpret_cast(l1); // COMPLIANT +} + +struct TestClass { + void memberFunc(); + std::int32_t m1; +}; + +void test_compliant_member_function_pointer_exceptions() { + void *l1 = nullptr; + + // Member function pointer casts are technically exceptions to this rule, but + // are prohibited by the compiler. + // void (TestClass::*l2)() = + // reinterpret_cast(l1); // COMPLIANT +} + +void test_compliant_regular_pointer_operations() { + TestStruct l1; + TestStruct *l2 = &l1; + std::int32_t *l3 = &l1.m1; + + // Regular pointer operations that don't involve forbidden casts + TestStruct *l4 = l2; // COMPLIANT + std::int32_t *l5 = l3; // COMPLIANT +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-2-7/NoPointerToIntegralCast.expected b/cpp/misra/test/rules/RULE-8-2-7/NoPointerToIntegralCast.expected new file mode 100644 index 0000000000..7a5f729206 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-7/NoPointerToIntegralCast.expected @@ -0,0 +1,17 @@ +| test.cpp:22:22:22:59 | reinterpret_cast... | Cast converts pointer type to integral type 'long'. | +| test.cpp:23:23:23:61 | reinterpret_cast... | Cast converts pointer type to integral type 'unsigned long'. | +| test.cpp:24:20:24:55 | reinterpret_cast... | Cast converts pointer type to integral type 'signed char'. | +| test.cpp:25:21:25:57 | reinterpret_cast... | Cast converts pointer type to integral type 'unsigned char'. | +| test.cpp:26:21:26:57 | reinterpret_cast... | Cast converts pointer type to integral type 'signed short'. | +| test.cpp:27:22:27:59 | reinterpret_cast... | Cast converts pointer type to integral type 'unsigned short'. | +| test.cpp:28:21:28:59 | reinterpret_cast... | Cast converts pointer type to integral type 'signed int'. | +| test.cpp:29:22:29:61 | reinterpret_cast... | Cast converts pointer type to integral type 'unsigned int'. | +| test.cpp:30:22:30:61 | reinterpret_cast... | Cast converts pointer type to integral type 'signed long'. | +| test.cpp:32:7:32:47 | reinterpret_cast... | Cast converts pointer type to integral type 'unsigned long'. | +| test.cpp:33:14:33:42 | reinterpret_cast... | Cast converts pointer type to integral type 'long'. | +| test.cpp:34:23:34:60 | reinterpret_cast... | Cast converts pointer type to integral type 'unsigned long'. | +| test.cpp:35:13:35:40 | reinterpret_cast... | Cast converts pointer type to integral type 'int'. | +| test.cpp:36:22:36:58 | reinterpret_cast... | Cast converts pointer type to integral type 'unsigned int'. | +| test.cpp:64:7:64:47 | reinterpret_cast... | Cast converts pointer type to integral type 'long'. | +| test.cpp:66:7:66:48 | reinterpret_cast... | Cast converts pointer type to integral type 'unsigned long'. | +| test.cpp:67:14:67:45 | reinterpret_cast... | Cast converts pointer type to integral type 'long'. | diff --git a/cpp/misra/test/rules/RULE-8-2-7/NoPointerToIntegralCast.qlref b/cpp/misra/test/rules/RULE-8-2-7/NoPointerToIntegralCast.qlref new file mode 100644 index 0000000000..c46a48360b --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-7/NoPointerToIntegralCast.qlref @@ -0,0 +1 @@ +rules/RULE-8-2-7/NoPointerToIntegralCast.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-2-7/test.cpp b/cpp/misra/test/rules/RULE-8-2-7/test.cpp new file mode 100644 index 0000000000..6f89118c21 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-7/test.cpp @@ -0,0 +1,76 @@ +#include + +struct S { + int m1; +}; + +class C { +public: + int m1; +}; + +void test_pointer_to_integral_casts() { + S s; + S *s_ptr = &s; + C c; + C *c_ptr = &c; + int l1 = 42; + int *int_ptr = &l1; + void *void_ptr = &l1; + + // Non-compliant cases - pointer to integral type casts + std::intptr_t l2 = reinterpret_cast(s_ptr); // NON_COMPLIANT + std::uintptr_t l3 = reinterpret_cast(s_ptr); // NON_COMPLIANT + std::int8_t l4 = reinterpret_cast(s_ptr); // NON_COMPLIANT + std::uint8_t l5 = reinterpret_cast(s_ptr); // NON_COMPLIANT + std::int16_t l6 = reinterpret_cast(c_ptr); // NON_COMPLIANT + std::uint16_t l7 = reinterpret_cast(c_ptr); // NON_COMPLIANT + std::int32_t l8 = reinterpret_cast(int_ptr); // NON_COMPLIANT + std::uint32_t l9 = reinterpret_cast(int_ptr); // NON_COMPLIANT + std::int64_t l10 = reinterpret_cast(void_ptr); // NON_COMPLIANT + std::uint64_t l11 = + reinterpret_cast(void_ptr); // NON_COMPLIANT + long l12 = reinterpret_cast(s_ptr); // NON_COMPLIANT + unsigned long l13 = reinterpret_cast(s_ptr); // NON_COMPLIANT + int l14 = reinterpret_cast(s_ptr); // NON_COMPLIANT + unsigned int l15 = reinterpret_cast(s_ptr); // NON_COMPLIANT +} + +void test_compliant_pointer_operations() { + S s; + S *s_ptr = &s; + C c; + C *c_ptr = &c; + int l1 = 42; + int *int_ptr = &l1; + + // Compliant cases - pointer to pointer casts + void *l16 = static_cast(s_ptr); // COMPLIANT + S *l17 = static_cast(static_cast(s_ptr)); // COMPLIANT + C *l18 = reinterpret_cast(s_ptr); // COMPLIANT + + // Compliant cases - using pointers without casting to integral + S *l19 = s_ptr; // COMPLIANT + if (s_ptr != nullptr) { // COMPLIANT + s_ptr->m1 = 10; // COMPLIANT + } +} + +void test_function_pointer_to_integral() { + void (*func_ptr)() = nullptr; + + // Non-compliant cases - function pointer to integral type casts + std::intptr_t l20 = + reinterpret_cast(func_ptr); // NON_COMPLIANT + std::uintptr_t l21 = + reinterpret_cast(func_ptr); // NON_COMPLIANT + long l22 = reinterpret_cast(func_ptr); // NON_COMPLIANT +} + +void test_member_pointer_to_integral() { + // Member pointer to integral type casts are forbidden by the rule, but also + // prohibited by the compiler, e.g. + // int S::*member_ptr = &S::m1; + // std::intptr_t l23 = reinterpret_cast(member_ptr); + // std::uintptr_t l24 = reinterpret_cast(member_ptr); +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-2-8/PointerToIntegralCast.expected b/cpp/misra/test/rules/RULE-8-2-8/PointerToIntegralCast.expected new file mode 100644 index 0000000000..dd85d003c2 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-8/PointerToIntegralCast.expected @@ -0,0 +1,13 @@ +| test.cpp:35:13:35:47 | reinterpret_cast... | Cast of object pointer type to integral type 'unsigned long' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:35:13:35:47 | reinterpret_cast... | | +| test.cpp:40:13:40:46 | reinterpret_cast... | Cast of object pointer type to integral type 'unsigned int' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:40:13:40:46 | reinterpret_cast... | | +| test.cpp:45:13:45:38 | reinterpret_cast... | Cast of object pointer type to integral type 'long' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:45:13:45:38 | reinterpret_cast... | | +| test.cpp:50:13:50:45 | reinterpret_cast... | Cast of object pointer type to integral type 'size_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:50:13:50:45 | reinterpret_cast... | | +| test.cpp:55:13:55:43 | reinterpret_cast... | Cast of object pointer type to integral type 'hashPtr_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:55:13:55:43 | reinterpret_cast... | | +| test.cpp:60:13:60:42 | reinterpret_cast... | Cast of object pointer type to integral type 'MyIntPtr' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:60:13:60:42 | reinterpret_cast... | | +| test.cpp:65:13:65:35 | reinterpret_cast... | Cast of object pointer type to integral type inside $@. | test.cpp:94:3:94:50 | call to test_non_compliant_template_cast | call to instantiated template f of test_non_compliant_template_cast | +| test.cpp:67:13:67:47 | reinterpret_cast... | Cast of object pointer type to integral type 'uint64_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:67:13:67:47 | reinterpret_cast... | | +| test.cpp:72:13:72:47 | reinterpret_cast... | Cast of object pointer type to integral type 'uint64_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:72:13:72:47 | reinterpret_cast... | | +| test.cpp:77:13:77:46 | reinterpret_cast... | Cast of object pointer type to integral type 'int64_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:77:13:77:46 | reinterpret_cast... | | +| test.cpp:84:15:84:37 | reinterpret_cast... | Cast of object pointer type to integral type inside $@. | test.cpp:95:48:95:48 | definition of x | instantiation of class TestNonCompliantTemplateCast | +| test.cpp:86:15:86:49 | reinterpret_cast... | Cast of object pointer type to integral type 'uint64_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:86:15:86:49 | reinterpret_cast... | | +| test.cpp:91:23:91:45 | reinterpret_cast... | Cast of object pointer type to integral type inside $@. | test.cpp:96:3:96:35 | variable_template | reference to instantiated template variable variable_template | diff --git a/cpp/misra/test/rules/RULE-8-2-8/PointerToIntegralCast.qlref b/cpp/misra/test/rules/RULE-8-2-8/PointerToIntegralCast.qlref new file mode 100644 index 0000000000..ed46d08aeb --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-8/PointerToIntegralCast.qlref @@ -0,0 +1 @@ +rules/RULE-8-2-8/PointerToIntegralCast.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-2-8/test.cpp b/cpp/misra/test/rules/RULE-8-2-8/test.cpp new file mode 100644 index 0000000000..6b3dbd7685 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-8/test.cpp @@ -0,0 +1,97 @@ +#include +#include +struct S {}; +class C {}; + +S *g1 = nullptr; + +using hashPtr_t = std::uintptr_t; +using MyIntPtr = std::intptr_t; + +void test_compliant_uintptr_t_cast() { + S *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // COMPLIANT +} + +void test_compliant_intptr_t_cast() { + C *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // COMPLIANT +} + +void test_compliant_void_pointer_cast() { + void *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // COMPLIANT + auto l3 = reinterpret_cast(l1); // COMPLIANT +} + +void test_compliant_const_pointer_cast() { + const int *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // COMPLIANT + auto l3 = reinterpret_cast(l1); // COMPLIANT +} + +void test_non_compliant_unsigned_long_cast() { + S *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_non_compliant_unsigned_int_cast() { + S *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_non_compliant_long_cast() { + C *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_non_compliant_size_t_cast() { + void *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_non_compliant_typedef_cast() { + S *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_non_compliant_using_alias_cast() { + C *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT +} + +template void test_non_compliant_template_cast() { + S *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT + auto l3 = reinterpret_cast(l1); // COMPLIANT + auto l4 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_non_compliant_uint64_t_cast() { + S *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_non_compliant_int64_t_cast() { + void *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT +} + +template class TestNonCompliantTemplateCast { +public: + TestNonCompliantTemplateCast() { + S *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT + auto l3 = reinterpret_cast(l1); // COMPLIANT + auto l4 = reinterpret_cast(l1); // NON_COMPLIANT + } +}; + +template +T variable_template = reinterpret_cast(g1); // NON_COMPLIANT + +void test_instantiate_template() { + test_non_compliant_template_cast(); + TestNonCompliantTemplateCast x{}; + variable_template; +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-20-1/UnsignedOperationWithConstantOperandsWraps.testref b/cpp/misra/test/rules/RULE-8-20-1/UnsignedOperationWithConstantOperandsWraps.testref new file mode 100644 index 0000000000..148997676e --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-20-1/UnsignedOperationWithConstantOperandsWraps.testref @@ -0,0 +1 @@ +cpp/common/test/rules/unsignedoperationwithconstantoperandswraps/UnsignedOperationWithConstantOperandsWraps.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-3-1/BuiltInUnaryOperatorAppliedToUnsignedExpression.testref b/cpp/misra/test/rules/RULE-8-3-1/BuiltInUnaryOperatorAppliedToUnsignedExpression.testref new file mode 100644 index 0000000000..bd12c39fbd --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-3-1/BuiltInUnaryOperatorAppliedToUnsignedExpression.testref @@ -0,0 +1 @@ +cpp/common/test/rules/builtinunaryoperatorappliedtounsignedexpression/BuiltInUnaryOperatorAppliedToUnsignedExpression.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.expected b/cpp/misra/test/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.expected new file mode 100644 index 0000000000..eb58109070 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.expected @@ -0,0 +1,7 @@ +| test.cpp:20:3:20:35 | ExprStmt | Explicit type conversion used as expression statement creates temporary object that is immediately discarded. | +| test.cpp:21:3:21:23 | ExprStmt | Explicit type conversion used as expression statement creates temporary object that is immediately discarded. | +| test.cpp:22:3:22:27 | ExprStmt | Explicit type conversion used as expression statement creates temporary object that is immediately discarded. | +| test.cpp:23:3:23:34 | ExprStmt | Explicit type conversion used as expression statement creates temporary object that is immediately discarded. | +| test.cpp:42:8:42:40 | ExprStmt | Explicit type conversion used as expression statement creates temporary object that is immediately discarded. | +| test.cpp:66:3:66:17 | ExprStmt | Explicit type conversion used as expression statement creates temporary object that is immediately discarded. | +| test.cpp:67:3:67:17 | ExprStmt | Explicit type conversion used as expression statement creates temporary object that is immediately discarded. | diff --git a/cpp/misra/test/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.qlref b/cpp/misra/test/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.qlref new file mode 100644 index 0000000000..5aec9cdada --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.qlref @@ -0,0 +1 @@ +rules/RULE-9-2-1/NoStandaloneTypeCastExpression.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-2-1/test.cpp b/cpp/misra/test/rules/RULE-9-2-1/test.cpp new file mode 100644 index 0000000000..75aed0a90e --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-2-1/test.cpp @@ -0,0 +1,74 @@ +#include +#include +#include + +std::mutex g1; +std::mutex g2; + +void f1(std::unique_lock l1) { + // Function parameter for testing compliant cases +} + +void test_explicit_type_conversion_expression_statement() { + // Compliant cases - declarations + std::unique_lock l1(g1); // COMPLIANT + std::unique_lock l2{g1}; // COMPLIANT + std::unique_lock(l3); // COMPLIANT - declaration with redundant + // parentheses around variable name + + // Non-compliant cases - explicit type conversions as expression statements + std::unique_lock{g1}; // NON_COMPLIANT + std::scoped_lock{g1}; // NON_COMPLIANT + std::scoped_lock(g1, g2); // NON_COMPLIANT + std::lock_guard{g1}; // NON_COMPLIANT + + // Compliant cases - type conversions not as expression statements + f1(std::unique_lock(g1)); // COMPLIANT + f1(std::unique_lock{g1}); // COMPLIANT + auto l4 = std::unique_lock(g1); // COMPLIANT + auto l5 = std::unique_lock{g1}; // COMPLIANT + + // The extractor has a bug as of 2.20.7 which means it does not parse + // these two cases separately. We choose to ignore if statements, which + // can cause false negatives, but will prevent false positives + if (std::unique_lock(g1); true) { // COMPLIANT - init-statement + } + if (std::unique_lock{g1}; true) { // NON_COMPLIANT[FALSE_NEGATIVE] + } + + for (std::unique_lock(g1);;) { // COMPLIANT - init-statement + break; + } + for (std::unique_lock{g1};;) { // NON_COMPLIANT - init-statement + break; + } +} + +void test_primitive_type_conversions() { + // Non-compliant cases with primitive types + std::int32_t(42); // NON_COMPLIANT + float(3.14); // NON_COMPLIANT + double(2.71); // NON_COMPLIANT + bool(true); // NON_COMPLIANT + + // Compliant cases + auto l1 = std::int32_t(42); // COMPLIANT + auto l2 = float(3.14); // COMPLIANT + std::int32_t l3(42); // COMPLIANT - declaration + std::int32_t l4{42}; // COMPLIANT - declaration +} + +struct CustomType { + CustomType(std::int32_t) {} +}; +void test_custom_types() { + // Non-compliant cases + CustomType(42); // NON_COMPLIANT + CustomType{42}; // NON_COMPLIANT + + // Compliant cases + CustomType l1(42); // COMPLIANT - declaration + CustomType l2{42}; // COMPLIANT - declaration + auto l3 = CustomType(42); // COMPLIANT + auto l4 = CustomType{42}; // COMPLIANT +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-3-1/LoopBodyCompoundCondition.testref b/cpp/misra/test/rules/RULE-9-3-1/LoopBodyCompoundCondition.testref new file mode 100644 index 0000000000..84dc7caf76 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-3-1/LoopBodyCompoundCondition.testref @@ -0,0 +1 @@ +cpp/common/test/rules/loopcompoundcondition/LoopCompoundCondition.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-3-1/SwitchBodyCompoundCondition.testref b/cpp/misra/test/rules/RULE-9-3-1/SwitchBodyCompoundCondition.testref new file mode 100644 index 0000000000..f02b02ba85 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-3-1/SwitchBodyCompoundCondition.testref @@ -0,0 +1 @@ +cpp/common/test/rules/switchcompoundcondition/SwitchCompoundCondition.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-4-1/IfElseIfEndCondition.testref b/cpp/misra/test/rules/RULE-9-4-1/IfElseIfEndCondition.testref new file mode 100644 index 0000000000..d7ca04a26e --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-4-1/IfElseIfEndCondition.testref @@ -0,0 +1 @@ +cpp/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected b/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected new file mode 100644 index 0000000000..673e570631 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected @@ -0,0 +1,12 @@ +| test.cpp:28:3:37:3 | switch (...) ... | Switch statement contains a statement that is not a simple declaration. | +| test.cpp:51:3:60:3 | switch (...) ... | Switch statement contains a switch label that is not directly within the switch body. | +| test.cpp:62:3:71:3 | switch (...) ... | Switch statement contains a switch label that is not directly within the switch body. | +| test.cpp:75:3:85:3 | switch (...) ... | Switch statement contains a statement label that is not a case label. | +| test.cpp:89:3:97:3 | switch (...) ... | Switch statement has a statement that is not a case label as its first element. | +| test.cpp:147:3:154:3 | switch (...) ... | Switch statement is missing a terminator that moves the control out of its body. | +| test.cpp:188:3:192:3 | switch (...) ... | Switch statement contains less than two branches. | +| test.cpp:194:3:200:3 | switch (...) ... | Switch statement contains less than two branches. | +| test.cpp:215:3:219:3 | switch (...) ... | Switch statement contains less than two branches. | +| test.cpp:215:3:219:3 | switch (...) ... | Switch statement lacks a default case. | +| test.cpp:223:3:229:3 | switch (...) ... | Switch statement lacks a case for one of its variants. | +| test.cpp:231:3:239:3 | switch (...) ... | Switch statement lacks a case for one of its variants. | diff --git a/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.qlref b/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.qlref new file mode 100644 index 0000000000..9f475afbe1 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.qlref @@ -0,0 +1 @@ +rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-4-2/test.cpp b/cpp/misra/test/rules/RULE-9-4-2/test.cpp new file mode 100644 index 0000000000..0e8c2e2ec2 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-4-2/test.cpp @@ -0,0 +1,253 @@ +#include + +int i = 0; + +/** + * Test the initializer of a switch statement. + */ +void testInitializer(int expr) { + switch (expr) { // COMPLIANT: No initializer + case 1: + i++; + break; + default: + i--; + break; + } + + switch (int j = 0; + expr) { // COMPLIANT: Only declaration statement can be an initializer + case 1: + j++; + break; + default: + j--; + break; + } + + switch ( + i = 1; + expr) { // NON_COMPLIANT: Only declaration statement can be an initializer + case 1: + i++; + break; + default: + i--; + break; + } +} + +void testNestedCaseLabels(int expr) { + switch (expr) { // COMPLIANT: Consecutive case labels are allowed + case 1: + case 2: + i++; + break; + default: + i--; + break; + } + + switch (expr) { // NON_COMPLIANT: Statements with case labels should all be at + // the same level + case 1: { + case 2: + i++; + break; + } + default: + break; + } + + switch (expr) { // NON_COMPLIANT: Statements with case labels should all be at + // the same level + case 1: + i++; + break; + case 2: { + default: + break; + } + } +} + +void testOtherLabelsInBranch(int expr) { + switch (expr) { // NON_COMPLIANT: Non-case labels appearing in a switch branch + case 1: { + i++; + goto someLabel; + someLabel: + i++; + break; + } + default: + break; + } +} + +void testLeadingNonCaseStatement(int expr) { + switch (expr) { // NON_COMPLIANT: Non-case statement is the first statement in + // the switch body + int x = 1; + case 1: + i++; + break; + default: + break; + } +} + +[[noreturn]] void f() { exit(0); } +void g() {} + +void testSwitchBranchTerminator(int expr) { + switch (expr) { // COMPLIANT: Break is allowed as a branch terminator + case 1: + i++; + break; + default: + break; + } + + for (int j = 0; j++; j < 10) { + switch (expr) { // COMPLIANT: Continue is allowed as a branch terminator + case 1: + i++; + continue; + default: + continue; + } + } + + switch (expr) { // COMPLIANT: Goto is allowed as a branch terminator + case 1: + i++; + goto error; + default: + goto error; + } + + switch (expr) { // COMPLIANT: Throw is allowed as a branch terminator + case 1: + i++; + throw; + default: + throw; + } + + switch (expr) { // COMPLIANT: Call to a `[[noreturn]]` function is allowed as + // a branch terminator + case 1: + i++; + f(); + default: + f(); + } + + switch (expr) { // NON_COMPLIANT: Branch ends with a call to a function that + // is not `[[noreturn]]` + case 1: + i++; + g(); + default: + g(); + } + + switch (expr) { // COMPLIANT: Return is allowed as a branch terminator + case 1: + i++; + return; + default: + return; + } + + switch (expr) { // COMPLIANT: Empty statement with `[[fallthrough]]` is + // allowed as a branch terminator + case 1: + i++; + [[fallthrough]]; + default: + i++; + break; + } + +error: + return; +} + +void testSwitchBranchCount(int expr) { + switch (expr) { // COMPLIANT: Branch count is 2 + case 1: + i++; + break; + default: + i++; + break; + } + + switch (expr) { // NON_COMPLIANT: Branch count is 1 + default: + i++; + break; + } + + switch (expr) { // NON_COMPLIANT: Branch count is 1 + case 1: + case 2: + default: + i++; + break; + } +} + +enum E { V1, V2, V3 }; + +void testDefaultLabelPresence(int expr) { + switch (expr) { // COMPLIANT: There is a default branch + case 1: + i++; + break; + default: + i++; + break; + } + + switch (expr) { // NON_COMPLIANT: Default branch is missing + case 1: + i++; + break; + } + + E e; + + switch (e) { // COMPLIANT: There is a default branch + case V1: + i++; + break; + default: + break; + } + + switch (e) { // NON_COMPLIANT: Default branch is missing on a non-exhaustive + // enum switch + case V1: + i++; + break; + case V2: + i++; + break; + } + + switch (e) { // COMPLIANT: Default branch can be omitted on an exhaustive enum + // switch + case V1: + i++; + break; + case V2: + i++; + break; + case V3: + i++; + break; + } +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected b/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected new file mode 100644 index 0000000000..16a43b6d49 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected @@ -0,0 +1,62 @@ +| test.cpp:33:3:35:3 | for(...;...;...) ... | The $@ is not of an integer type. | test.cpp:33:14:33:14 | i | counter variable | test.cpp:33:14:33:14 | i | N/A | +| test.cpp:42:3:44:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:42:19:42:25 | ... == ... | loop condition | test.cpp:42:19:42:25 | ... == ... | N/A | +| test.cpp:46:3:48:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:46:19:46:24 | ... < ... | loop condition | test.cpp:46:19:46:24 | ... < ... | N/A | +| test.cpp:62:3:65:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:62:19:62:28 | ... < ... | loop condition | test.cpp:62:19:62:28 | ... < ... | N/A | +| test.cpp:67:3:70:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:67:19:67:27 | ... < ... | loop condition | test.cpp:67:19:67:27 | ... < ... | N/A | +| test.cpp:72:3:75:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:72:19:72:27 | ... < ... | loop condition | test.cpp:72:19:72:27 | ... < ... | N/A | +| test.cpp:72:3:75:3 | for(...;...;...) ... | The $@ may be mutated in $@ other than its update expression. | test.cpp:72:12:72:12 | i | counter variable | test.cpp:72:19:72:21 | ... ++ | a location | +| test.cpp:72:3:75:3 | for(...;...;...) ... | The $@ may be mutated in $@ other than its update expression. | test.cpp:72:12:72:12 | i | counter variable | test.cpp:72:19:72:27 | ... < ... | a location | +| test.cpp:114:3:116:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:114:12:114:12 | i | counter variable | test.cpp:115:8:115:13 | ... *= ... | expression | +| test.cpp:128:3:131:3 | for(...;...;...) ... | The $@ has a smaller type than that of the $@. | test.cpp:128:21:128:21 | i | counter variable | test.cpp:128:25:128:53 | call to max | loop bound | +| test.cpp:153:3:156:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:154:13:154:13 | j | loop step | test.cpp:155:5:155:5 | j | mutated | +| test.cpp:158:3:160:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:159:13:159:13 | j | loop step | test.cpp:159:16:159:16 | j | mutated | +| test.cpp:158:3:160:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:158:12:158:12 | i | counter variable | test.cpp:159:8:159:18 | ... , ... | expression | +| test.cpp:170:3:173:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:170:23:170:23 | j | loop bound | test.cpp:172:5:172:5 | j | mutated | +| test.cpp:175:3:177:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:175:23:175:25 | ... ++ | loop bound | test.cpp:175:23:175:25 | ... ++ | non-const expression | +| test.cpp:175:3:177:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:175:23:175:23 | j | loop bound | test.cpp:175:23:175:23 | j | mutated | +| test.cpp:179:3:181:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:179:19:179:27 | ... < ... | loop condition | test.cpp:179:19:179:27 | ... < ... | N/A | +| test.cpp:179:3:181:3 | for(...;...;...) ... | The $@ may be mutated in $@ other than its update expression. | test.cpp:179:12:179:12 | i | counter variable | test.cpp:179:19:179:21 | ... ++ | a location | +| test.cpp:179:3:181:3 | for(...;...;...) ... | The $@ may be mutated in $@ other than its update expression. | test.cpp:179:12:179:12 | i | counter variable | test.cpp:179:19:179:27 | ... < ... | a location | +| test.cpp:185:3:188:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:185:23:185:23 | k | loop bound | test.cpp:187:15:187:15 | k | mutated | +| test.cpp:190:3:193:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:191:13:191:13 | l | loop step | test.cpp:192:15:192:15 | l | mutated | +| test.cpp:195:3:197:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:195:23:195:24 | call to h1 | loop bound | test.cpp:195:23:195:24 | call to h1 | non-const expression | +| test.cpp:203:3:205:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:204:13:204:14 | call to h1 | loop step | test.cpp:204:13:204:14 | call to h1 | non-const expression | +| test.cpp:218:3:221:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:218:19:218:19 | i | loop counter | test.cpp:220:14:220:14 | i | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:223:3:226:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:223:19:223:19 | i | loop counter | test.cpp:225:14:225:15 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:238:3:241:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:238:19:238:19 | i | loop counter | test.cpp:240:20:240:21 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:243:3:246:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:243:23:243:23 | k | loop bound | test.cpp:245:14:245:14 | k | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:248:3:251:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:248:23:248:23 | k | loop bound | test.cpp:250:14:250:15 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:263:3:266:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:263:23:263:23 | k | loop bound | test.cpp:265:20:265:21 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:268:3:271:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:268:31:268:31 | l | loop step | test.cpp:270:14:270:14 | l | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:273:3:276:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:273:31:273:31 | l | loop step | test.cpp:275:14:275:15 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:288:3:291:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:288:31:288:31 | l | loop step | test.cpp:290:20:290:21 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:293:3:296:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:293:19:293:19 | i | loop counter | test.cpp:295:8:295:8 | i | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:293:3:296:3 | for(...;...;...) ... | The $@ may be mutated in $@ other than its update expression. | test.cpp:293:12:293:12 | i | counter variable | test.cpp:295:5:295:6 | call to f1 | a location | +| test.cpp:298:3:301:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:298:19:298:19 | i | loop counter | test.cpp:300:8:300:9 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:298:3:301:3 | for(...;...;...) ... | The $@ may be mutated in $@ other than its update expression. | test.cpp:298:12:298:12 | i | counter variable | test.cpp:300:5:300:6 | call to g1 | a location | +| test.cpp:313:3:316:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:313:19:313:19 | i | loop counter | test.cpp:315:8:315:9 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:313:3:316:3 | for(...;...;...) ... | The $@ may be mutated in $@ other than its update expression. | test.cpp:313:12:313:12 | i | counter variable | test.cpp:315:5:315:6 | call to f3 | a location | +| test.cpp:318:3:321:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:318:19:318:19 | i | loop counter | test.cpp:320:8:320:9 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:318:3:321:3 | for(...;...;...) ... | The $@ may be mutated in $@ other than its update expression. | test.cpp:318:12:318:12 | i | counter variable | test.cpp:320:5:320:6 | call to f4 | a location | +| test.cpp:328:3:331:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:328:19:328:19 | i | loop counter | test.cpp:330:8:330:8 | i | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:328:3:331:3 | for(...;...;...) ... | The $@ may be mutated in $@ other than its update expression. | test.cpp:328:12:328:12 | i | counter variable | test.cpp:330:5:330:6 | call to g4 | a location | +| test.cpp:338:3:341:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:338:23:338:23 | k | loop bound | test.cpp:340:8:340:8 | k | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:338:3:341:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:338:23:338:23 | k | loop bound | test.cpp:340:8:340:8 | k | mutated | +| test.cpp:343:3:346:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:343:23:343:23 | k | loop bound | test.cpp:345:8:345:9 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:343:3:346:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:343:23:343:23 | k | loop bound | test.cpp:345:9:345:9 | k | mutated | +| test.cpp:359:3:362:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:359:23:359:23 | k | loop bound | test.cpp:361:8:361:9 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:359:3:362:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:359:23:359:23 | k | loop bound | test.cpp:361:9:361:9 | k | mutated | +| test.cpp:364:3:367:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:364:23:364:23 | k | loop bound | test.cpp:366:8:366:9 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:364:3:367:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:364:23:364:23 | k | loop bound | test.cpp:366:9:366:9 | k | mutated | +| test.cpp:374:3:377:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:374:23:374:23 | k | loop bound | test.cpp:376:8:376:8 | k | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:374:3:377:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:374:23:374:23 | k | loop bound | test.cpp:376:8:376:8 | k | mutated | +| test.cpp:384:3:387:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:384:31:384:31 | l | loop step | test.cpp:386:8:386:8 | l | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:384:3:387:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:384:31:384:31 | l | loop step | test.cpp:386:8:386:8 | l | mutated | +| test.cpp:389:3:392:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:389:31:389:31 | l | loop step | test.cpp:391:8:391:9 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:389:3:392:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:389:31:389:31 | l | loop step | test.cpp:391:9:391:9 | l | mutated | +| test.cpp:404:3:407:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:404:31:404:31 | l | loop step | test.cpp:406:8:406:9 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:404:3:407:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:404:31:404:31 | l | loop step | test.cpp:406:9:406:9 | l | mutated | +| test.cpp:409:3:412:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:409:31:409:31 | l | loop step | test.cpp:411:8:411:9 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:409:3:412:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:409:31:409:31 | l | loop step | test.cpp:411:9:411:9 | l | mutated | +| test.cpp:419:3:422:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:419:31:419:31 | l | loop step | test.cpp:421:8:421:8 | l | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:419:3:422:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:419:31:419:31 | l | loop step | test.cpp:421:8:421:8 | l | mutated | diff --git a/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.qlref b/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.qlref new file mode 100644 index 0000000000..bf443d6d68 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.qlref @@ -0,0 +1 @@ +rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-5-1/test.cpp b/cpp/misra/test/rules/RULE-9-5-1/test.cpp new file mode 100644 index 0000000000..eaddd9644a --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-5-1/test.cpp @@ -0,0 +1,428 @@ +#include +#include +#include + +void f1(int &x) {} // Function that takes a non-const integer reference +void g1(int *x) {} // Function that takes a non-const integer pointer +void f2(const int &x) {} // Function that takes a non-const integer reference +void g2(const int *x) {} // Function that takes a non-const integer pointer +void f3(int *const x) {} +void f4(int *x...) {} // Function that takes a non-const integer pointer +void g4(int &x...) {} // Function that takes a non-const integer pointer +void f5(const int *x...) {} // Function that takes a non-const integer pointer +void g5(const int &x...) {} // Function that takes a non-const integer pointer + +int h1() { return 1; } +constexpr int h2() { return 1; } + +int h3(int x) { return x; } + +void h4(int &args...) {} +void h5(const int &args...) {} + +int main() { + int j = 5; + int k = 10; + int l = 2; + + /* ========== 1. Type of the initialized counter variable ========== */ + + for (int i = 0; i < 10; i++) { // COMPLIANT: `i` has an integer type + } + + for (float i = 0.0; i < 10; + i++) { // NON_COMPLIANT: `i` has a non-integer type + } + + /* ========== 2. Termination condition ========== */ + + for (int i = 0; i < 10; i++) { // COMPLIANT: `<` is a relational operator + } + + for (int i = 0; i == 10; + i++) { // NON_COMPLIANT: `==` is not a relational operator + } + + for (int i = 0; j < 10; i++) { // NON_COMPLIANT: `j` is not the loop counter + j++; + } + + /* + * The following test cases in this section document our stance on arithmetic + * operations on loop counters appearing as an operand of the loop condition. + * Our stance is that such conditions are non-compliant cases according to + * this part of the rule. + * + * Why we think they are non-compliant is as follows: We interpret the rule as + * having the loop counter be an index that are meant to be used directly as + * is, by their value. Therefore, performing arithmetic and comparing the + * result to a loop bound goes against the interpretation. + */ + + for (int i = 0; i + 10 < j; + ++i) { // NON_COMPLIANT: The loop condition does not directly compare + // loop counter `i` to the loop bound `j` + } + + for (int i = 0; h3(i) < j; + ++i) { // NON_COMPLIANT: The loop condition does not directly compare + // loop counter `i` to the loop bound `j` + } + + for (int i = 0; i++ < j++; + i++) { // NON_COMPLIANT: The loop condition does not directly compare + // loop counter `i` to the loop bound `j` + } + + /* ========== 3. Updating expression ========== */ + + for (int i = 0; i < 10; + ++i) { // COMPLIANT: Pre-increment operator used as the update expression + } + + for (int i = 0; i < 10; i++) { // COMPLIANT: Post-increment operator used as + // the update expression + } + + for (int i = 20; i > 10; + --i) { // COMPLIANT: Pre-increment operator used as the update expression + } + + for (int i = 20; i > 10; i--) { // COMPLIANT: Post-increment operator used as + // the update expression + } + + for (int i = 0; i < 10; i += 3) { // COMPLIANT: Add-and-assign operator used + // as the update expression with loop step 3 + } + + for (int i = 20; i > 10; + i -= 3) { // COMPLIANT: Add-and-assign operator used + // as the update expression with loop step 3 + } + + for (int i = 0; i < 10; + i = i + + 3) { // COMPLIANT: Direct assignment with addition with loop step 3 + } + + for (int i = 20; i < 10; + i = i - + 3) { // COMPLIANT: Direct assignment with addition with loop step 3 + } + + for (int i = 0; i < 10; + i *= 2) { // NON_COMPLIANT: Mutiplication is not incrementing + } + + /* ========== 4. Type of the loop counter and the loop bound ========== */ + + for (int i = 0; i < 10; i++) { // COMPLIANT: 0 and 10 are of same type + } + + for (unsigned long long int i = 0; i < 10; + i++) { // COMPLIANT: The loop counter has type bigger than that of the + // loop bound + } + + for (short i = 0; i < std::numeric_limits::max(); + i++) { // NON_COMPLIANT: The type of the loop counter is not bigger + // than that of the loop bound + } + + for (int i = 0; i < j; + i++) { // COMPLIANT: The loop step and the loop bound has the same type + } + + /* ========== 5. Immutability of the loop bound and the loop step ========== + */ + + for (int i = 0; i < 10; + i++) { // COMPLIANT: The update expression is an post-increment operation + // and its loop step is always 1 + } + + for (int i = 0; i < 10; i += 2) { // COMPLIANT: The loop step is always 2 + } + + for (int i = 0; i < 10; + i += + j) { // COMPLIANT: The loop step `j` is not mutated anywhere in the loop + } + + for (int i = 0; i < 10; + i += j) { // NON_COMPLIANT: The loop step `j` is mutated in the loop + j++; + } + + for (int i = 0; i < 10; + i += j, j++) { // NON_COMPLIANT: The loop step `j` is mutated in the loop + } + + for (int i = 0; i < j; i++) { // COMPLIANT: The loop bound `j` is not mutated + // anywhere in the loop + } + + for (int i = 0; i < j; i++) { // COMPLIANT: The loop bound `j` is not mutated + // anywhere in the loop + } + + for (int i = 0; i < j; + i++) { // NON_COMPLIANT: The loop bound `j` is mutated in the loop + j++; + } + + for (int i = 0; i < j++; + i++) { // NON_COMPLIANT: The loop bound `j` is mutated in the loop + } + + for (int i = 0; i++ < j++; + i++) { // NON_COMPLIANT: The loop bound `j` is mutated in the loop + } + + int n = 0; + + for (int i = 0; i < k; + i += l) { // NON_COMPLIANT: The loop bound is mutated through an address + *(true ? &k : &n) += 1; + } + + for (int i = 0; i < k; + i += l) { // NON_COMPLIANT: The loop step is mutated through an address + *(true ? &l : &n) += 1; + } + + for (int i = 0; i < h1(); + i++) { // NON_COMPLIANT: The loop bound is not a constant expression + } + + for (int i = 0; i < h2(); + i++) { // COMPLIANT: The loop bound is a constant expression + } + + for (int i = 0; i < j; + i += h1()) { // NON_COMPLIANT: The loop step is not a constant expression + } + + for (int i = 0; i < j; + i += h2()) { // COMPLIANT: The loop step is a constant expression + } + + /* ========== 6. Existence of pointers to the loop counter, loop bound, and + * loop step ========== */ + + for (int i = 0; i < k; i += l) { // COMPLIANT: The loop counter, bound, and + // step are not taken addresses of + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is taken + // as a non-const reference + int &m = i; + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is taken + // as a non-const pointer + int *m = &i; + } + + for (int i = j; i < k; i += l) { // COMPLIANT: The loop counter is taken + // as a const reference + const int &m = i; + } + + for (int i = j; i < k; i += l) { // COMPLIANT: The loop counter is taken + // as a const pointer + const int *m = &i; + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is taken + // as a const but mutable pointer + int *const m = &i; + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop bound is taken as + // a non-const reference + int &m = k; + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop bound is taken as + // a non-const pointer + int *m = &k; + } + + for (int i = j; i < k; i += l) { // COMPLIANT: The loop bound is taken + // as a const reference + const int &m = k; + } + + for (int i = j; i < k; i += l) { // COMPLIANT: The loop bound is taken + // as a const pointer + const int *m = &k; + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop bound is taken as + // a const but mutable pointer + int *const m = &k; + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is taken as + // a non-const reference + int &m = l; + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is taken as + // a non-const pointer + int *m = &l; + } + + for (int i = j; i < k; i += l) { // COMPLIANT: The loop step is taken as + // a const reference + const int &m = l; + } + + for (int i = j; i < k; i += l) { // COMPLIANT: The loop step is taken as + // a const pointer + const int *m = &l; + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is taken as + // a const but mutable pointer + int *const m = &l; + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed + // to a non-const reference parameter + f1(i); + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed + // to a non-const pointer parameter + g1(&i); + } + + for (int i = j; i < k; i += l) { // COMPLIANT: The loop counter is passed + // to a const reference parameter + f2(i); + } + + for (int i = j; i < k; i += l) { // COMPLIANT: The loop counter is passed + // to a const pointer parameter + g2(&i); + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed + // to a const but mutable pointer parameter + f3(&i); + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed + // to a non-const variadic reference argument + f4(&i); + } + + for (int i = j; i < k; i += l) { // COMPLIANT: The loop counter is passed to a + // const variadic reference argument + f5(&i); + } + + for (int i = 0; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed + // to a non-const variadic reference argument + g4(i); + } + + for (int i = 0; i < k; i += l) { // COMPLIANT: The loop counter is passed to a + // const variadic reference argument + g5(i); + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop bound is passed to + // a non-const reference parameter + f1(k); + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop bound is passed to + // a non-const pointer parameter + g1(&k); + } + + for (int i = j; i < k; i += l) { // COMPLIANT: The loop bound is passed to a + // const reference parameter + f2(k); + } + + for (int i = j; i < k; + i += + l) { // COMPLIANT: The loop bound is passed to a const pointer parameter + g2(&k); + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop bound is passed to + // a const but mutable pointer parameter + f3(&k); + } + + for (int i = 0; i < k; i += l) { // NON_COMPLIANT: The loop bound is passed to + // a non-const variadic reference argument + f4(&k); + } + + for (int i = 0; i < k; i += l) { // COMPLIANT: The loop bound is passed to a + // const variadic reference argument + f5(&k); + } + + for (int i = 0; i < k; i += l) { // NON_COMPLIANT: The loop bound is passed to + // a non-const variadic reference argument + g4(k); + } + + for (int i = 0; i < k; i += l) { // COMPLIANT: The loop bound is passed to a + // const variadic reference argument + g5(k); + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is passed to + // a non-const reference parameter + f1(l); + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is passed to + // a non-const pointer parameter + g1(&l); + } + + for (int i = j; i < k; i += l) { // COMPLIANT: The loop step is passed to + // a const reference parameter + f2(l); + } + + for (int i = j; i < k; i += l) { // COMPLIANT: The loop step is passed to + // a const pointer parameter + g2(&l); + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is passed to + // a const but mutable pointer parameter + f3(&l); + } + + for (int i = 0; i < k; i += l) { // NON_COMPLIANT: The loop step is passed to + // a non-const variadic reference argument + f4(&l); + } + + for (int i = 0; i < k; i += l) { // COMPLIANT: The loop step is passed to a + // const variadic reference argument + f5(&l); + } + + for (int i = 0; i < k; i += l) { // NON_COMPLIANT: The loop step is passed to + // a non-const variadic reference argument + g4(l); + } + + for (int i = 0; i < k; i += l) { // COMPLIANT: The loop step is passed to a + // const variadic reference argument + g5(l); + } +} diff --git a/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected b/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected new file mode 100644 index 0000000000..fdd088bf35 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected @@ -0,0 +1,8 @@ +| test.cpp:48:3:49:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:48:17:48:27 | call to processData | initializer | +| test.cpp:56:3:59:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:56:17:57:19 | call to vector | initializer | +| test.cpp:71:3:73:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:71:17:72:21 | call to MyContainer | initializer | +| test.cpp:95:3:97:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:95:26:95:26 | call to operator+ | initializer | +| test.cpp:99:3:101:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:99:31:99:31 | call to operator+ | initializer | +| test.cpp:103:3:107:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:104:18:104:18 | call to operator+ | initializer | +| test.cpp:116:3:119:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:117:8:117:25 | call to convertToIntVector | initializer | +| test.cpp:121:3:124:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:122:8:122:25 | call to convertToIntVector | initializer | diff --git a/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.qlref b/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.qlref new file mode 100644 index 0000000000..be7fc0ef10 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.qlref @@ -0,0 +1 @@ +rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-5-2/test.cpp b/cpp/misra/test/rules/RULE-9-5-2/test.cpp new file mode 100644 index 0000000000..bc8c6c6acf --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-5-2/test.cpp @@ -0,0 +1,133 @@ +#include +#include + +/* Helper functions */ +std::vector getData() { return {1, 2, 3}; } +std::vector processData(const std::vector &input) { return input; } +std::vector getContainer() { return {4, 5, 6}; } + +class MyContainer { +public: + MyContainer() = default; + MyContainer(std::vector data) : data_(data) {} + std::vector::iterator begin() { return data_.begin(); } + std::vector::iterator end() { return data_.end(); } + +private: + std::vector data_{7, 8, 9}; +}; + +class ConvertibleToVector { +public: + operator std::vector() const { return {7, 8, 9}; } + std::array::iterator begin() { return data_.begin(); } + std::array::iterator end() { return data_.end(); } + std::array::const_iterator begin() const { return data_.cbegin(); } + std::array::const_iterator end() const { return data_.cend(); } + +private: + std::array data_{7, 8, 9}; +}; + +std::vector operator+(std::vector a, std::vector b) { + std::vector result = a; + result.insert(result.end(), b.begin(), b.end()); + return result; +} + +std::vector convertToIntVector(std::vector vector) { return vector; } + +int main() { + std::vector localVec = {1, 2, 3}; + + /* ========== 1. EXPLICIT FUNCTION CALLS ========== */ + + for (auto x : getContainer()) { // COMPLIANT: 1 function call only + } + + for (auto x : processData(getData())) { // NON_COMPLIANT: 2 function calls + } + + /* ========== 2. OBJECT CREATION (CONSTRUCTOR CALLS) ========== */ + + for (auto x : std::vector(3)) { // COMPLIANT: 1 constructor call only + } + + for (auto x : std::vector{ + 1, 2, 3}) { // NON_COMPLIANT: 2 constructor call to + // `vector` and `initializer_list`, respectively + } + + for (auto x : MyContainer()) { // COMPLIANT: 1 constructor call only + } + + for (auto x : std::string("hello")) { // COMPLIANT: 1 constructor call only + } + + for (auto x : std::vector( + getData())) { // NON-COMPLIANT: 1 constructor + 1 function call + } + + for (auto x : MyContainer(processData( + localVec))) { // NON-COMPLIANT: 1 constructor + 1 function call + } + + auto data = std::vector(getData()); + for (auto x : data) { // NON-COMPLIANT: 1 constructor + 1 function call + } + + MyContainer myContainer = MyContainer(processData(localVec)); + for (auto x : myContainer) { // NON-COMPLIANT: 1 constructor + 1 function call + } + + /* ========== 3. OPERATOR OVERLOADING ========== */ + + std::vector vec1 = {1}, vec2 = {2}, vec3 = {3}; + std::vector appendedVector = (vec1 + vec2) + vec3; + for (auto x : appendedVector) { // COMPLIANT: 0 calls + } + + std::vector appendedVector2 = getData() + processData(localVec); + for (auto x : appendedVector2) { // COMPLIANT: 0 calls + } + + std::vector anotherVec = {4, 5, 6}; + for (auto x : localVec + anotherVec) { // NON_COMPLIANT: 2 calls to vector's + // constructor, 1 operator+ call + } + + for (auto x : (vec1 + vec2) + vec3) { // NON-COMPLIANT: 3 calls to vector's + // constructor, 2 operator+ calls + } + + for (auto x : + getData() + + processData( + localVec)) { // NON-COMPLIANT: 2 function calls + 1 operator call + } + + /* ========== 4. IMPLICIT CONVERSIONS ========== */ + + ConvertibleToVector convertible; + for (int x : + ConvertibleToVector()) { // COMPLIANT: 1 conversion operator call only + } + + for (int x : + convertToIntVector(convertible)) { // NON_COMPLIANT: 1 function call + 1 + // conversion operator call + } + + for (int x : + convertToIntVector(convertible)) { // NON_COMPLIANT: 1 function call + 1 + // conversion operator call + } + + std::vector intVector1 = convertToIntVector(convertible); + for (int x : intVector1) { // COMPLIANT: 0 function calls + } + + std::vector intVector2 = convertToIntVector(convertible); + for (int x : intVector2) { // COMPLIANT: 0 function calls + } +} \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-6-1/GotoStatementShouldNotBeUsed.testref b/cpp/misra/test/rules/RULE-9-6-1/GotoStatementShouldNotBeUsed.testref new file mode 100644 index 0000000000..44d306f80c --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-6-1/GotoStatementShouldNotBeUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/gotostatementshouldnotbeused/GotoStatementShouldNotBeUsed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-6-2/GotoReferenceALabelInSurroundingBlock.testref b/cpp/misra/test/rules/RULE-9-6-2/GotoReferenceALabelInSurroundingBlock.testref new file mode 100644 index 0000000000..7502d9431c --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-6-2/GotoReferenceALabelInSurroundingBlock.testref @@ -0,0 +1 @@ +cpp/common/test/rules/gotoreferencealabelinsurroundingblock/GotoReferenceALabelInSurroundingBlock.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-6-3/GotoShallJumpToLabelDeclaredLaterInTheFunction.testref b/cpp/misra/test/rules/RULE-9-6-3/GotoShallJumpToLabelDeclaredLaterInTheFunction.testref new file mode 100644 index 0000000000..b4f807e8e2 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-6-3/GotoShallJumpToLabelDeclaredLaterInTheFunction.testref @@ -0,0 +1 @@ +cpp/common/test/rules/gotostatementcondition/GotoStatementCondition.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-6-4/FunctionDeclaredWithTheNoreturnAttributeReturn.testref b/cpp/misra/test/rules/RULE-9-6-4/FunctionDeclaredWithTheNoreturnAttributeReturn.testref new file mode 100644 index 0000000000..dec8006f15 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-6-4/FunctionDeclaredWithTheNoreturnAttributeReturn.testref @@ -0,0 +1 @@ +cpp/common/test/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-6-5/NonVoidFunctionShallReturnAValueOnAllPaths.testref b/cpp/misra/test/rules/RULE-9-6-5/NonVoidFunctionShallReturnAValueOnAllPaths.testref new file mode 100644 index 0000000000..ef9b3c1fc2 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-6-5/NonVoidFunctionShallReturnAValueOnAllPaths.testref @@ -0,0 +1 @@ +cpp/common/test/rules/nonvoidfunctiondoesnotreturn/NonVoidFunctionDoesNotReturn.ql \ No newline at end of file diff --git a/cpp/options b/cpp/options index 1f8961ecda..44267e9323 100644 --- a/cpp/options +++ b/cpp/options @@ -1 +1 @@ -semmle-extractor-options:--clang -std=c++14 -nostdinc++ -I../../../../common/test/includes/standard-library -I../../../../common/test/includes/custom-library \ No newline at end of file +semmle-extractor-options:--clang -std=c++14 -nostdinc++ -I../../../../common/test/includes/standard-library -I../../../../common/test/includes/custom-library diff --git a/cpp/report/src/Diagnostics/ExtractionErrors.qll b/cpp/report/src/Diagnostics/ExtractionErrors.qll index 55e1c96461..58757ca544 100644 --- a/cpp/report/src/Diagnostics/ExtractionErrors.qll +++ b/cpp/report/src/Diagnostics/ExtractionErrors.qll @@ -60,10 +60,10 @@ class ExtractionError extends TExtractionError { /** Gets the error message for this error. */ string getErrorMessage() { none() } - /** Gets the file this error occured in. */ + /** Gets the file this error occurred in. */ File getFile() { none() } - /** Gets the location this error occured in. */ + /** Gets the location this error occurred in. */ Location getLocation() { none() } /** Gets the SARIF severity of this error. */ diff --git a/cpp/report/src/codeql-pack.lock.yml b/cpp/report/src/codeql-pack.lock.yml index 514e6963d0..a45ea8f438 100644 --- a/cpp/report/src/codeql-pack.lock.yml +++ b/cpp/report/src/codeql-pack.lock.yml @@ -2,13 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.9.3 + version: 4.0.3 codeql/dataflow: - version: 0.0.4 + version: 2.0.3 + codeql/mad: + version: 1.0.19 + codeql/rangeanalysis: + version: 1.0.19 codeql/ssa: - version: 0.1.5 + version: 1.0.19 codeql/tutorial: - version: 0.1.5 + version: 1.0.19 + codeql/typeflow: + version: 1.0.19 + codeql/typetracking: + version: 2.0.3 codeql/util: - version: 0.1.5 + version: 2.0.6 + codeql/xml: + version: 1.0.19 compiled: false diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index d9a8beff97..9f4064e4c6 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.32.0-dev +version: 2.52.0-dev license: MIT dependencies: - codeql/cpp-all: 0.9.3 + codeql/cpp-all: 4.0.3 diff --git a/docs/design/detection_of_genenated_infinities_and_nans.md b/docs/design/detection_of_genenated_infinities_and_nans.md new file mode 100644 index 0000000000..62396eea99 --- /dev/null +++ b/docs/design/detection_of_genenated_infinities_and_nans.md @@ -0,0 +1,294 @@ +# Coding Standards: Detection of generated Infinities and NaNs + +- [Coding Standards: Detection of generated Infinities and NaNs](#coding-standards-detection-of-generated-infinities-and-nans) + - [Document management](#document-management) + - [Background](#background) + - [Critical problems](#critical-problems) + - [TL;DR](#tldr) + - [Range / Source Analysis, In Detail](#range-source-analysis-in-detail) + - [Mathematical Operations](#mathematical-operations) + - [Range / Source Proposal #1 (Recommended)](#range-source-proposal-1-recommended) + - [Range / Source Proposal #2 (Not Recommended)](#range-source-proposal-2-not-recommended) + - [Range / Source Proposal #3 (Not Recommended)](#range-source-proposal-3-not-recommended) + - [Range / Source Proposal #4 (Not Recommended)](#range-source-proposal-4-not-recommended) + - [Detection / Sink Analysis, In Detail](#detection-sink-analysis-in-detail) + - [Detection / Sink Proposal #1 (Recommended)](#range-source-proposal-1-recommended) + - [Detection / Sink Proposal #2 (Not Recommended)](#range-source-proposal-2-not-recommended) + - [Case study examples](#case-study-examples) + +## Document management + +**ID**: codeql-coding-standards/design/detection-infinities-nans
+**Status**: Draft + +| Version | Date | Author(s) | Reviewer (s) | +| ------- | ---------- | -------------- | ---------------------------------------------------------------------------------------------- | +| 0.1 | 12/13/2024 | Mike Fairhurst | Robert C. Seacord, J.F. Bastien, Luke Cartey, Vincent Mailhol, Fernando Jose, Rakesh Pothengil | + +## Background + +Directive 4-15 of MISRA-C 2023 states that a program shall not have undetected generation of Infinities and NaNs. It also states that infinities and NaNs may propagate across various FLOPs, but may not propagate into sections of code not designed to handle infinities and NaNs. + +This directive is intentionally open to a large degree of interpretation. This document is intended to help guide the decision making for how to implement this directive in the most useful way. + +## Critical problems + +There are two fundamental problems to decide on before implementing this directive: +- **Range / source analysis**, even a simple expression like `a + b` can be a source of infinity or NaN if there is no estimated value for `a` and/or `b`, which violates developer expectations and produces false positives. +- **Detection / sink analysis**, how we decide which sources need to be reported to users. This can be flow analysis with sinks, or it can be modeled as a resource leak analysis where certain actions (`isnan(x), x < 10`) are handled as freeing the NaN/infinite value. + +## TL;DR + +This document proposes to create a float-specialized copy of standard range analysis which assumes most values are in the range of +/-1e15, which covers most valid program use cases, and allows `a * b` without generating `Infinity`. Then standard flow analysis will be used to detect when these values flow into underflowing operations (`x / infinity` and `x % infinity`, etc.), and when NaNs flow into comparison operations (`>`, `>=`, `<`, `<=`). If the query is noisy, we may ignore NaNs and/or infinities that come from the mostly safe basic operations (`+`, `-`, `*`). + +## Range / Source Analysis, In Detail: + +Default CodeQL range analysis is limited for performance reasons (etc): + +- Range analysis is local, not interprocedural +- Global variables are assumed to be in the range of [-Infinity, Infinity] +- Struct members, array values are assumed to be in the range of [-Infinity, Infinity] +- Guards (e.g. `x != 0 ? y / x : ...`) are not always tracked + +This creates a scenario where even `a + b` can be `Infinity` or `NaN`; if either `a` or `b` is `Inf` then the expression is `Inf`, and if `a` is `+Inf` while `b` is `-Inf` then the result is `NaN`. + +Perhaps the flaw is in assuming `a` or `b` may be an infinite value. However, if the analysis considered `a` and `b` to be between the largest positive and negative finite floating values, then still `a + b` can produce an infinity, and only offers a single step of protection from false positives and negatives. + +There are a few proposals to handle this. + +#### Mathematical Operations + +IEEE 754-1985 specifies floating point semantics for “add, subtract, multiply, divide, square root, remainder, and compare operations,” including invalid use of these operators that produce NaN, propagating NaNs, and overflows that produce +/- Infinity. These semantics shall be used in the analysis. + +The C17 standard states that implementations compiling with IEEE 754-1985 shall define `__STDC_IEC_559__`. Under this proposal we will detect compilations where this macro is not defined and report a warning. + +Beyond the standard binary operators defined by IEEE 754-1985, programs may generate Infinity and/or NaN in the standard library mathematical functions. Note that technically, the c spec is vague in certain ways about when range errors, pole errors, and invalid operation errors in the standard math functions produce infinities or NaNs. We propose to assume IEEE 754-2019 behavior in this regard as a practical matter, though there is no guarantee that is the case. An alternative approach which we do not plan to take would be to broadly assume that all range errors, pole errors, invalid operation errors produce both Infinities and NaNs. This alternative would increase false positives. + +### Range / Source Proposal #1 (Recommended): + +We will create a new float-specific version of range analysis. The actual values stored in floating point variables in real programs are very unlikely to be close to the limits of finite floating point numbers (+/- 3.4e38 for floats, 1.8e308 for doubles). This proposal is that we, for the purposes of this rule, create a new range analysis for floats where otherwise undeterminable values are assumed to be a very large range that is small compared to the range of floating point values, such as +/-1e15. + +Creating a new version of float analysis rather than extending previous analysis is likely to have better performance than extending standard range analysis. When floats and integers interact, the integer from standard range analysis can be used. + +Implications of this approach (assuming values `a` and `b` have no estimated range): +- `a + b` will be finite +- `a * b` will be finite +- `a * b * c` will be possibly infinite +- `a / b` will be possibly infinite, as the range includes small values such as 1e-30, as well as zero +- `acos(a)` will be considered out of domain + +**Additional option**: If this query is still noisy, we may simply exclude reporting NaN’s and Infinities that come from a basic float operation such as `+`, `-`, or `*`. We would most likely still choose to report `/`, as divide-by-zero errors are the most common and most important to catch. + +### Range / Source Proposal #2 (Not Recommended): + +This proposal mirrors Proposal #1 except that otherwise undeterminable values will be treated as the max finite value +/-3.4e38 (floats) or 1.7e308 (doubles). + +The implications are as above except: +- `a + b` will be possibly infinite +- `a * b` will be possibly infinite + +### Range / Source Proposal #3 (Not Recommended): + +Under this proposal, standard CodeQL range analysis is used to detect generation of NaN/Infinity. All uses of a global or otherwise undeterminable value will be considered possibly infinite. + +### Range / Source Proposal #4 (Recommended): + +Under this proposal, standard CodeQL range analysis is extended to provide the support of proposal #1. While this should mostly have the same results, it will likely create performance problems, as it would rerun all range analysis code on every expression in order to have different findings in a subset of them. + +## Detection / Sink Analysis, In Detail: + +The directive states that: + +- Generated Infinities and NaNs may not be unchecked +- Infinities and NaNs may propagate to delay NaN/Infinity checking for performance reasons +- Infinities and NaNs may not reach sections of code not designed to handle them + +This leaves open some questions. For instance, is `printf("%f", a * b)` possibly sending an infinity to code prepared to handle it? + +### Detection / Sink Proposal #1 (recommended): + +This proposal is to identify sinks that should not accept Infinity or NaN, and then rely on standard flow analysis as the backbone of supporting this directive. + +If a valid propagation of a NaN or an Infinity can be distinguished from cases where a program was not prepared to receive a NaN or Infinity, then flow analysis is the only thing that is needed, and a resource-leak approach is not necessary. This proposes that the following cases are detected as sinks, such that if NaN or Infinity flows into them they are reported. + +**Case 1**: _NaNs shall not be compared, except to themselves_ +```c +void f(float x, float y) { + float z = x / y; // Could be 0.0 / 0.0 which produces NaN + + if (x < 10) { ... } // Not allowed + if (x != x) { ... } // OK +} +``` + +**Case 2**: _NaNs and infinities shall not be cast to integers_ +```c +void f(float x, float y) { + int z = x / y; // 0.0 / 0.0 may produce Infinity or NaN +} +``` + +**Case 3**: _Infinite values shall not underflow or otherwise produce finite values_ +```c +float f(void) { + float x = ...; // Could be a positive number / 0.0, which produces Infinity + 1 / x; // If x is Infinity, this underflows to 0.0 + 1 % x; // If x is Infinity, this is defined to produce 1. +} +``` + +**Case 4**: _Functions shall not return NaNs and infinities_ +```c +void f(float* p) { + float local1 = ...; // Could be infinity + + return local1; +} +``` + +**Case 5**: _NaNs and infinities shall only be stored in local stack variables_ +```c +float global; +void f(float* p) { + float local1 = ...; // Could be infinity + + // The following assignments could store an infinity in the heap: + global = local1; + extern_function(local1); + *p = local1; + + // The following cases should be possible to analyze correctly as well + // with modest effort: + float arr[10] = ...; + struct my_struct = ...; + arr[0] = local2; + my_struct.member = local1; +} +``` + +**Case 6 (not planned, compiler specific)**: _Functions can use assume() to declare they are not prepared for Infinity or NaN_ +```c +void f(float x, float[] y, struct foo z) { + assume(!isnan(x)); // May be supportable, not planned + assert(!isnan(y[0])); // Not supportable + assert(!isnan(z.member)); // Not supportable +} +``` + +With these cases specified, we can detect invalid usage of Infinity and NaN with simple flow analysis. + +## Detection / Sink Proposal #2 (not recommended): + +This proposed solution takes inspiration from resource leak detection. In this metaphor, a generated infinity or NaN is treated like a resource that must be disposed. [There is a draft WIP of this approach here.](https://github.com/github/codeql-coding-standards/compare/main...michaelrfairhurst/implement-floatingtype-package) + +The advantage of this solution is that we do not need to define every way in which a NaN or an Infinity could be misused. Rather, we only need to define a few ways that a NaN or Infinity can be checked, and then find possible Infinities and NaNs that are not checked (or propagated to a value that is checked). + +Under this proposal, the following are echecks for infinity and NaN: + +- The macros `isnan(x)`, `isinf(x)`, `isfinite(x)` should be considered checks for infinity. +- Reflexive equality checks (`x == x` or `x != x`) should be considered checks for NaN. +- Any comparison operation (`>`, `>=`, `<`, and `<=`) should be considered a check on both positive and negative and positive infinities for an operand if the other is finite. + - If `a` may only be positive infinity, `a < b` and `a > b` both create a branch of the code where `a` is not positive infinity. + - If `a` may only be negative infinity, the same as above is the case for negative infinity cases. + - If `a` may be both positive or negative infinity, then a single check is not sufficient, however detecting an appropriate pair of checks would be a much more difficult implementation + +Only local leak detection analysis is feasible at this time. Therefore, this proposal suggests that an infinite or NaN value should be flagged if it goes out of scope before it is checked. _(In other leak detection problems, this would typically be considered a free event to avoid false positives, and that is an option here as well)_. + +```c +float g; +void f(void) { + float l = 1 / 0; // Must be checked + g = l; // May send Infinity to code not prepared to handle it + isinf(l); // check occurs too late +} +``` + +Overall, this option is not recommended for the following reasons: + +- Slower performance than Proposal #1 +- Limited benefits over Proposal #1 +- Detecting out-of-scope cases heavily resembles Proposal #1 +- Unused values will be flagged, which is not useful to developers +- Intraprocedural analysis will be difficult to support +- High false positive rate if too few checks are detected, as opposed to the alternative where missing sinks do not create false positives + +In this analysis, a method or function call which can generate an infinity, such as `x / y` is treated somewhat like opening a file descriptor, and calls to `isinf(x)` or `isnan(x)` are treated as closing that file descriptor. _There are some differences between how we would approach this and how an actual resource leak detection would be modeled. For instance, we are not searching for use-after-free or double-free bugs, in this metaphor._ + +Note that resource leak detection is not the same as standard CodeQL flow analysis. For instance, if the below example is analyzed with flow analysis, CodeQL will detect that the result of `fopen` flows into a call to `fclose`. However, this only means it is possible that the program will close the file, it does not mean the file descriptor cannot leak. + +```c +void f(bool p) { + FILE* fd = fopen(...); + if (p) { + fclose(fd); + } +} +``` + +The drafted leak detection algorithm follows [this paper](https://arxiv.org/html/2312.01912v2/#S2.SS2). In this approach, the program flow from the exit of `f()` is walked backwards. The walk stops upon reaching a call to `fclose()`, and if a call to `fopen()` is reached by this iterative process then that resource could leak. + +_Note that this approach still uses flow analysis to determine that fclose(fd) is referring to an initial fopen() call. In the paper, flow analysis is used to find aliases of resources, so that disposing an alias of a resource is handled correctly._ + +This approach is still neither 100% accurate nor precise. It can generate both false positives and false negatives, though it is hopefully accurate and precise enough for our purposes: + +```c +// FALSE POSITIVE: See fprintf call marked (1). Not all successors from (1) + // call fclose(), and not all predecessors of (1) call fclose() either. + // All paths dispose fd, but this algorithm does not see that. + fd = fopen(...); + if (!cond) { + fclose(fd); + } + fprintf(...); // (1) + if (cond) { + fclose(fd); + } + + // FALSE NEGATIVE: The file descriptor opened at (2) flows into the dispose + // call at (3) if the values of x and y are not known. However, the resource + // is only closed when x == y, which is not necessarily the case. + fds[x] = fopen(...); // (2) + fclose(fds[y]); // (3) +``` + +Nevertheless, their approach is sensible and likely good enough. + +Lastly, this approach has the unfortunate downside that unused float values which could be NaN or Infinity will be reported, when they do not have any negative effect on a program (as opposed to the negative effects of leaking unused file descriptors, or unused memory, etc). + +## Case study examples + +The following is an interesting set of examples and code snippets that come from the open source project [pandas](https://github.com/commaai/panda), which aims to be MISRA compliant and is used for self-driving cars. + +These examples are hand picked results from a query that selected expressions with a floating point type along with their upper and lower bounds. + +**Example 1**: +```c +float filtered_pcm_speed = + ((to_push->data[6] << 8) | to_push->data[7]) + * 0.01 / 3.6; +// Disable controls if speeds from ABS and PCM ECUs are too far apart. +bool is_invalid_speed = ABS(filtered_pcm_speed + - ((float)vehicle_speed.values[0] / VEHICLE_SPEED_FACTOR)) + > FORD_MAX_SPEED_DELTA; +``` + +While `filter_pcm_speed` cannot be infinity or NaN, it is interesting to see how this value is sanity checked. If this code were refactored such that it could produce NaN, the greater-than check would return false, resulting in a bug. If the condition were flipped (check inside valid range, rather than outside), it would handle NaN correctly. This cannot be captured via static analysis. + +**Example 2**: +```c + float x0 = xy.x[i]; + float y0 = xy.y[i]; + float dx = xy.x[i+1] - x0; + float dy = xy.y[i+1] - y0; + // dx should not be zero as xy.x is supposed to be monotonic + dx = MAX(dx, 0.0001); + ret = (dy * (x - x0) / dx) + y0; +``` + +This is an [interpolation function](https://github.com/commaai/panda/blob/dec9223f9726e400e4a4eb91ca19fffcd745f97a/board/safety.h#L538), where `xy` is a struct parameter, with array members `x` and `y` that represent points in the domain and range to interpolate across. + +Range analysis is performed with local information only, and therefore, the expression `xy.x[i]` is given the range [-Infinity, Infinity]. This is not a generated infinity. However, the computations of `dx` and `dy` could generate a positive or negative infinity (if both numbers are finite and the result exceeds the maximum float value), they could propagate a positive or negative infinity, and/or they could generate a NaN (if an infinite value is subtracted from itself). + +The call to `MAX()` will not check if `dx` = positive infinity, and is unsafe to use with NaN. It prevents a divide-by-zero error, but `ret` could still propagate or generate a NaN or one of the infinities since we know so little about `dy`, `x0`, and `y0`. + +It’s worth noting that if `dx` is positive Infinity, then `(x - x0) / dx` will produce zero, rather than propagating the infinity. This may be worth flagging. \ No newline at end of file diff --git a/docs/design/guideline_recategorization.md b/docs/design/guideline_recategorization.md index f520869f39..e488cf88de 100644 --- a/docs/design/guideline_recategorization.md +++ b/docs/design/guideline_recategorization.md @@ -101,7 +101,7 @@ The *effective category* is the category whose policy is applied during the eval The policy of a category dictates if a result can be deviated from and implements the effect described in the design section. The existing exclusion mechanism implemented in the predicate `isExcluded` defined in the `Exclusions.qll` library will be updated to consider the applicable policy of a guideline. -Note: This changes the behavior of deviations which will no longer have an impact on Mandatory guidelines! However, this will only affect MISRA C rules because there are no MISRA C++ Guidelines with a Mandatory category. +Note: This changes the behavior of deviations which will no longer have an impact on Mandatory MISRA guidelines! ### Specification validation diff --git a/docs/development_handbook.md b/docs/development_handbook.md index 10ad1637a5..83670dbbc8 100644 --- a/docs/development_handbook.md +++ b/docs/development_handbook.md @@ -40,6 +40,9 @@ | 0.30.0 | 2023-11-14 | Remco Vermeulen | Clarify release steps in case of a hotfix release. | | 0.31.0 | 2024-02-23 | Remco Vermeulen | Clarify the required use of Python version 3.9 | | 0.32.0 | 2024-05-01 | Luke Cartey | Refer to the user manual for the list of supported standards. | +| 0.33.0 | 2024-07-30 | Kristen Newbury | Remove out dated references to codeql modules directory usage. | +| 0.34.0 | 2024-08-22 | Kristen Newbury | Remove out dated references to git submodules usage. | +| 0.35.0 | 2025-01-15 | Mike Fairhurst | Add guidance for the addition of 'strict' queries. | ## Scope of work @@ -49,6 +52,8 @@ Each coding standard consists of a list of "guidelines", however not all the gui For some of the rules which are not amenable to static analysis, we may opt to provide a query which aids with "auditing" the rules. For example, AUTOSAR includes a rule (A10-0-1) "Public inheritance shall be used to implement 'is-a' relationship.". This is not directly amenable to static analysis, because it requires external context around the concept being modeled. However, we can provide an "audit" rule which reports all the public and private inheritance relationships in the program, so they can be manually verified. +For other rules, there may be means of indicating that a contravention is intentional, and where requiring a _devation report_ may be extra burdensome on developers and require double-entry. These results should be reported under a "strict" query. For instance, `RULE-2-8` "A project should not contain unused object definitions," where adding `__attribute__((unused))` may be preferable in order to suppress compiler warnings (which _deviation reports_ do not do) and are highly indicative of an intentional contravention by a developer. + For each rule which will be implemented with a query we have assigned a "rule package". Rule packages represent sets of rules, possibly across standards, that will be implemented together. Examples of rule packages include "Exceptions", "Naming", "Pointers" and so forth. By implementing queries for related rules together, we intend to maximize the amount of code shared between queries, and to ensure query developers can gain a deep understanding of that specific topic. The canonical list of rules, with implementation categorization and assigned rule packages, are stored in this repository in the `rules.csv` file. @@ -494,12 +499,11 @@ There are two external dependencies required for running the coding standards qu For the purpose of this repository, and any tool qualification, we consider these external dependencies to be "black boxes" which require verification when upgrading. -To (a) clearly specify the supported versions of these external dependencies and to (b) enable automation around them, the repository contains a `supported_codeql_configs.json` which lists the sets of supported configurations. There are four fields: +To (a) clearly specify the supported versions of these external dependencies and to (b) enable automation around them, the repository contains a `supported_codeql_configs.json` which lists the sets of supported configurations under the `supported_environments` property. There are three fields: - `codeql_cli` - this is the plain version number of the supported CodeQL CLI, e.g. `2.6.3`. - `codeql_standard_library` - this is the name of a tag on the `github.com/github/codeql` repository. The tag should be compatible with the CodeQL CLI given above. This would typically use the `codeql-cli/v` tag for the release, although any tag which is compatible is allowed. - `codeql_cli_bundle` - (optional) - if present, describes the CodeQL CLI bundle version that is compatible. The bundle should include precisely the CodeQL CLI version and CodeQL Standard Library versions specified in the two mandatory fields. -- `ghes` - (optional) - if present describes the GitHub Enterprise Server release whose integrated copy of the CodeQL Action points to the CodeQL CLI bundle specified in the `codeql_cli_bundle` field. #### Upgrading external dependencies @@ -507,34 +511,41 @@ To upgrade the CodeQL external dependencies: 1. Determine appropriate versions of the CodeQL CLI and `github/codeql` repository, according to the release schedule and customer demands. 2. Determine if there is a compatible CodeQL CLI bundle version by looking at the releases specified at [CodeQL Action releases](https://github.com/github/codeql-action/releases). The bundle always includes the standard library at the version specified by the `codeql-cli/v` tag in the `github/codeql` repository. -3. If you find a compatible CodeQL CLI bundle, determine whether that bundle was released in a GitHub Enterprise server release, by inspecting the `defaults.json` file at https://github.com/github/codeql-action/blob/main/lib/defaults.json#L2 for the CodeQL Action submitted with -4. Populated the `supported_codeql_configs.json` file with the given values, ensuring to delete the optional fields if they are not populated. -5. Update the `codeql_modules/codeql` submodule pointer to the `codeql_standard_library` tag identified. -6. Submit a Pull Request to the `github/codeql-coding-standards` repository with the title `Upgrade `github/codeql` dependency to `. Use this template for the description, filling : - ```md - This PR updates the `supported_codeql_configs.json` file to target: +If all components are being upgraded to a consistent veresion (e.g. CodeQL CLI v2.15.5, with `github/codeql` tag `codeql-cli/v2.15.5` and bundle `codeql-cli-bundle-v2.15.5`) then the following process can be used: - - CodeQL CLI - - CodeQL Standard Library - - GHES - - CodeQL CLI Bundle +1. Run the [upgrade_codeql_dependencies.yml](./github/workflows/upgrade_codeql_dependencies.yml) workflow, with the plain version number, e.g. `2.15.5`. This will: + - Download the specified version of the CodeQL CLI + - Run the [upgrade-codeql-dependencies.py](scripts/release/upgrade-codeql-dependencies.py) script, which + - Validates the version selected exists in all relevant places + - Updates the `supported_codeql_configs.json` file. + - Updates each `qlpack.yml` in the repository with an appropriate value for the `codeql/cpp-all` pack, consistent with the selected CodeQL CLI version. + - Updates each `codeql-lock.yml` file to upgrade to the new version. +2. Follow the dependency upgrade checklist, confirming each step. The `.github/workflows/standard_library_upgrade_tests.yml` will trigger automation for running the `github/codeql` unit tests with the appropriate CLI version. +3. Once all the automate tests have passed, and the checklist is complete, the PR can be merged. +4. An internal notification should be shared with the development team. - > - +If the upgrade is of mismatched versions you will need to manually create the upgrade following this process: + +1. Populate the `supported_codeql_configs.json` file with the given values, ensuring to delete the optional fields if they are not populated. +2. Submit a Pull Request to the `github/codeql-coding-standards` repository with the title `Upgrade `github/codeql` dependency to `. Use this template for the description, filling: + + ```md + This PR updates the `supported_codeql_configs.json` file to target CodeQL CLI . ## CodeQL dependency upgrade checklist: - - [ ] Reformat our CodeQL using the latest version (if required) + - [ ] Confirm the code has been correctly reformatted according to the new CodeQL CLI. - [ ] Identify any CodeQL compiler warnings and errors, and update queries as required. - [ ] Validate that the `github/codeql` test cases succeed. - [ ] Address any CodeQL test failures in the `github/codeql-coding-standards` repository. - - [ ] Validate performance vs pre-upgrade + - [ ] Validate performance vs pre-upgrade, using /test-performance ``` -7. Follow the dependency upgrade checklist, confirming each step. The `.github/workflows/standard_library_upgrade_tests.yml` will trigger automation for running the `github/codeql` unit tests with the appropriate CLI version. -8. Once all the automate tests have passed, and the checklist is complete, the PR can be merged. -9. An internal notification should be shared with the development team. +3. Follow the dependency upgrade checklist, confirming each step. The `.github/workflows/standard_library_upgrade_tests.yml` will trigger automation for running the `github/codeql` unit tests with the appropriate CLI version. +4. Once all the automate tests have passed, and the checklist is complete, the PR can be merged. +5. An internal notification should be shared with the development team. + ### Release process @@ -735,14 +746,3 @@ codeql test run --show-extractor-output \ # The actual output can be accepted via codeql test accept (which moves some files): codeql test accept \ cpp/cert/test/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.qlref - - -``` - -### Troubleshooting: Unrecoverable mismatch between extractor and library dbschemes - -The following error could be indicative of the Git submodule *codeql-coding-standards/github_modules* being out-of-date: - ->Could not upgrade the dataset in /path/to/codeql-coding-standards/cpp/autosar/test/rules/...: Unrecoverable mismatch between extractor and library dbschemes. - -To resolve the problem, update the submodule by executing `git submodule update`. diff --git a/docs/iso_26262_tool_qualification.md b/docs/iso_26262_tool_qualification.md index 22de2f5a21..3c1442b1a7 100644 --- a/docs/iso_26262_tool_qualification.md +++ b/docs/iso_26262_tool_qualification.md @@ -11,7 +11,9 @@ | 0.3.0 | 2021-09-08 | Luke Cartey | Update the customer table. | | 0.4.0 | 2021-09-19 | Luke Cartey | Add more detail on approach to V&V. Update section around increased confidence from use. | | 0.5.0 | 2021-11-29 | Remco Vermeulen | Add document management section. | -| 0.6.0 | 2023-08-14 | Luke Cartey | Update use and testing statement after LGTM.com deprecation. | +| 0.6.0 | 2023-08-14 | Luke Cartey | Update use and testing statement after LGTM.com deprecation. | +| 0.7.0 | 2024-07-23 | Luke Cartey | Fix development handbook link | +| 0.8.0 | 2025-08-29 | Luke Cartey | Update Safety Manager | ## Introduction @@ -60,7 +62,7 @@ For the CodeQL Coding Standard queries, we intend to apply the following qualifi #### 1b. Evaluation of the tool development process in accordance with 11.4.8 -The development process is described in the [development handbook](../development_handbook.md). +The development process is described in the [development handbook](development_handbook.md). The project planning and requirements processes are described in our internal repository. @@ -80,7 +82,7 @@ In combination, these techniques ensure that the tool complies with the requirem - Rule review with subject matter experts ensures our interpretation of the rule is appropriate in uncertain cases. - Real world testing and external feedback ensures the interpretation of the rule is producing appropriate and reasonable results on real world code. -The development processes related to validation and verification are described in detail the [development handbook](../development_handbook.md). +The development processes related to validation and verification are described in detail the [development handbook](development_handbook.md). ### Qualification methods for CodeQL CLI and the CodeQL Standard Library for C++ @@ -137,7 +139,7 @@ In addition to this black box testing of the components, we also provide validat ## Safety manager - - **Safety Manager**: @lcartey - - **Deputy Safety Manager**: @rvermeulen + - **Safety Manager**: @michaelrfairhurst + - **Deputy Safety Manager**: @nicolaswill In the event of the Safety Manager being on leave, the Deputy Safety Manager will be responsible for all duties. diff --git a/docs/user_manual.md b/docs/user_manual.md index c9e3db53a9..201fb76ad5 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -26,17 +26,24 @@ | 0.18.0 | 2024-01-30 | Luke Cartey | Update product description and coverage table. | | 0.19.0 | 2024-02-23 | Remco Vermeulen | Clarify the required use of Python version 3.9. | | 0.20.0 | 2024-02-23 | Remco Vermeulen | Add table describing the permitted guideline re-categorizations. | -| 0.21.0 | 2024-05-01 | Luke Cartey | Add MISRA C++ 2023 as under development, and clarify MISRA C 2012 coverage. | +| 0.21.0 | 2024-05-01 | Luke Cartey | Add MISRA C++ 2023 as under development, and clarify MISRA C 2012 coverage. | +| 0.22.0 | 2024-10-02 | Luke Cartey | Add MISRA C 2023 as under development, and clarify MISRA C 2012 coverage. | +| 0.23.0 | 2024-10-21 | Luke Cartey | Add assembly as a hazard. | +| 0.24.0 | 2024-10-22 | Luke Cartey | Add CodeQL packs as a usable output, update release artifacts list. | +| 0.25.0 | 2025-01-15 | Mike Fairhurst | Add guidance for the usage of 'strict' queries. | +| 0.26.0 | 2025-02-12 | Luke Cartey | Describe support for new deviation code identifier formats | +| 0.27.0 | 2025-05-15 | Luke Cartey | Documented completed support for MISRA C 2023. | ## Release information -This user manual documents release `2.32.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.52.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: -- `code-scanning-cpp-query-pack-2.32.0-dev.zip`: coding standard 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.32.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.32.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.32.0-dev.md`: This user manual. +- `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.52.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.52.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.52.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.52.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. @@ -53,13 +60,16 @@ A _coding standard_ is a set of rules or guidelines which restrict or prohibit t The _CodeQL Coding Standards_ product is a set of CodeQL queries for identifying contraventions of rules in the following coding standards: -| Standard | Version | Rules | Supportable rules | Implemented rules | Status | -| -------------------------------------------------------------------------------------------------------------------- | ------- | ----------- | ----------------------- | ----------------- | ------- | -| AUTOSAR C++ | [^1] [R22-11](https://www.autosar.org/fileadmin/standards/R22-11/AP/AUTOSAR_RS_CPP14Guidelines.pdf), R21-11, R20-11, R19-11, R19-03 | 397 | 372 | 370[^2] | Implemented | -| CERT-C++ | [2016](https://resources.sei.cmu.edu/downloads/secure-coding/assets/sei-cert-cpp-coding-standard-2016-v01.pdf) | 83 | 82 | 82 | Implemented | -| CERT C | [2016](https://resources.sei.cmu.edu/downloads/secure-coding/assets/sei-cert-c-coding-standard-2016-v01.pdf) | 99 | 97 | 97 | Implemented | -| MISRA C | [2012 Third Edition, First Revision](](https://www.misra.org.uk/product/misra-c2012-third-edition-first-revision/)), and [Amendment 2](https://misra.org.uk/app/uploads/2021/06/MISRA-C-2012-AMD2.pdf) and TC2 | 175 | 164 | 162[^3] | Implemented | -| MISRA C++ | [2023](https://misra.org.uk/product/misra-cpp2023/) | 179 | 176[^4] | 0 | Under development | +| Standard | Version | Rules | Supportable rules | Implemented rules | Status | +| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | ----------------- | ----------------- | ----------------- | +| AUTOSAR C++ | [^1] [R22-11](https://www.autosar.org/fileadmin/standards/R22-11/AP/AUTOSAR_RS_CPP14Guidelines.pdf), R21-11, R20-11, R19-11, R19-03 | 397 | 372 | 370[^2] | Implemented | +| CERT-C++ | [2016](https://resources.sei.cmu.edu/downloads/secure-coding/assets/sei-cert-cpp-coding-standard-2016-v01.pdf) | 83 | 82 | 82 | Implemented | +| CERT C | [2016](https://resources.sei.cmu.edu/downloads/secure-coding/assets/sei-cert-c-coding-standard-2016-v01.pdf) | 99 | 97 | 97 | Implemented | +| MISRA C | [2012 Third Edition, First Revision](https://www.misra.org.uk/product/misra-c2012-third-edition-first-revision/), [Amendment 2](https://misra.org.uk/app/uploads/2021/06/MISRA-C-2012-AMD2.pdf) and TC2 | 175 | 164 | 162[^3] | Implemented | +| | [2012 Amendment 3](https://misra.org.uk/app/uploads/2021/06/MISRA-C-2012-AMD3.pdf) | 24 | 24 | 24 | Implemented | +| | [2012 Amendment 4](https://misra.org.uk/app/uploads/2021/06/MISRA-C-2012-AMD4.pdf) | 22 | 22 | 21[^4] | Implemented | +| | [2023 Third Edition, Second Revision](https://misra.org.uk/product/misra-c2023/) | 221 | 210 | 207[^5] | Implemented | +| MISRA C++ | [2023](https://misra.org.uk/product/misra-cpp2023/) | 179 | 176[^6] | - | Under development | Not all rules in these standards are amenable to static analysis by CodeQL - some rules require external or domain specific knowledge to validate, or refer to properties which are not present in our representation of the codebase under analysis. In addition, some rules are natively enforced by the supported compilers. As CodeQL requires that the program under analysis compiles, we are unable to implement queries for these rules, and doing so would be redundant. @@ -67,6 +77,7 @@ For each rule we therefore identify whether it is supportable or not. Furthermor - **Automated** - the queries for the rule find contraventions directly. - **Audit only** - the queries for the rule does not find contraventions directly, but instead report a list of _candidates_ that can be used as input into a manual audit. For example, `A10-0-1` (_Public inheritance shall be used to implement 'is-a' relationship_) is not directly amenable to static analysis, but CodeQL can be used to produce a list of all the locations that use public inheritance so they can be manually reviewed. +- **Strict only** - the queries for the rule find contraventions directly, but find results which are strongly indicated to be intentional, and where adding a _deviation report_ may be extra burden on developers. For example, in `RULE-2-8` (_A project should not contain unused object definitions_), declaring objects with `__attribute__((unused))` may be preferable to a _deviation report_, which will not suppress relevant compiler warnings, and therefore would otherwise require developer double-entry. Each supported rule is implemented as one or more CodeQL queries, with each query covering an aspect of the rule. In many coding standards, the rules cover non-trivial semantic properties of the codebase under analysis. @@ -74,8 +85,10 @@ The datasheet _"CodeQL Coding Standards: supported rules"_, provided with each r [^1]: AUTOSAR C++ versions R22-11, R21-11, R20-11, R19-11 and R19-03 are all identical as indicated in the document change history. [^2]: The unimplemented supportable AUTOSAR rules are `A7-1-8` and `A8-2-1`. These rules require additional support in the CodeQL CLI to ensure the required information is available in the CodeQL database to identify violations of these rules. -[^3]: The unimplemented supportable MISRA C 2012 rules are `Rule 9.5` and `Dir 4.14`. `Rule 9.5` requires additional support in the CodeQL CLI to ensure the required information is available in the CodeQL database to identify violations of these rules. `Dir 4.14` is covered by the default CodeQL queries, which identify potential security vulnerabilities caused by not validating external input. -[^4]: The rules 5.13.7, 19.0.1 and 19.1.2 are not planned to be implemented by CodeQL as they are compiler checked in all supported compilers. +[^3]: The unimplemented supportable MISRA C 2012 rules are `Rule 9.5`, `Rule 17.13`. `Rule 9.5` and `Rule 17.13` require additional support in the CodeQL CLI to ensure the required information is available in the CodeQL database to identify violations of these rules. Note: `Dir 4.14` is covered by the default CodeQL queries, which identify potential security vulnerabilities caused by not validating external input. +[^4]: The unimplemented supportable MISRA C 2012 Amendment 4 rule is `Rule 9.6`. `Rule 9.6` requires additional support in the CodeQL CLI to ensure the required information is available in the CodeQL database to identify violations of this rule. +[^5]: The unimplemented supportable MISRA C 2023 rules are `Rule 9.5`, `Rule 9.6`, `Rule 17.13`. `Rule 9.5`, `Rule 9.6` and `Rule 17.13` require additional support in the CodeQL CLI to ensure the required information is available in the CodeQL database to identify violations of these rules. Note: `Dir 4.14` is covered by the default CodeQL queries, which identify potential security vulnerabilities caused by not validating external input. +[^6]: The rules `5.13.7`, `19.0.1` and `19.1.2` are not planned to be implemented by CodeQL as they are compiler checked in all supported compilers. ## Supported environment @@ -153,22 +166,52 @@ This section describes how to operate the "CodeQL Coding Standards". #### Pre-requisite: downloading the CodeQL CLI -You must download a compatible version of the CodeQL CLI and CodeQL Standard Library for C++. +You must download a compatible version of the CodeQL CLI, as specified in the release notes for the release you are using. -**Option 1:** Use the CodeQL CLI bundle, which includes both required components: +**Option 1:** Use the CodeQL CLI bundle, which includes both the CodeQL CLI and GitHub's default security queries: 1. Download the CodeQL CLI bundle from the [`github/codeql-action` releases page](https://github.com/github/codeql-action/releases). 2. Expand the compressed archive to a specified location on your machine. 3. [Optional] Add the CodeQL CLI to your user or system path. -**Option 2:** Fetch the components separately: +This approach is recommended if you wish to use the default queries provided by GitHub in addition to the Coding Standards queries. + +**Option 2:** Use the CodeQL CLI binary: 1. Download the CodeQL CLI from the [`github/codeql-cli-binaries` releases page](https://github.com/github/codeql-cli-binaries/releases) 2. Expand the compressed archive to a specified location on your machine. - 3. Using `git`, clone the [`github/codeql`](https://github.com/github/codeql) repository to a sibling directory of the CodeQL CLI. The `github/codeql` repository contains the CodeQL Standard Library for C++. - 4. [Optional] Add the CodeQL CLI to your user or system path. +3. [Optional] Add the CodeQL CLI to your user or system path. + +#### Pre-requisite: downloading the Coding Standards queries + +The Coding Standards packs can be downloaded into the local CodeQL package cache using the following command: + +```bash +codeql pack download codeql/--coding-standards@ +``` + +The supported standards and languages are: + * `codeql/misra-c-coding-standards` - a CodeQL query pack for reporting violations of MISRA C. + * `codeql/cert-c-coding-standards` - a CodeQL query pack for reporting violations of CERT C. + * `codeql/misra-cpp-coding-standards` - a CodeQL query pack for reporting violations of MISRA C++. + * `codeql/cert-cpp-coding-standards` - a CodeQL query pack for reporting violations of CERT C++. + * `codeql/autosar-cpp-coding-standards` - - a CodeQL query pack for reporting violations of AUTOSAR for C++. + +Ensure that the `@` string matches the desired Coding Standards version. + +Alternatively, the packs can be downloaded directly from a release on the `github/codeql-coding-standards` repository by choosing the `coding-standards-codeql-packs.zip`, which contains the following files: -The release notes for the "CodeQL Coding Standards" pack you are using will specify the appropriate versions to use. + * `misra-c-coding-standards.tgz` - a CodeQL query pack for reporting violations of MISRA C. + * `cert-c-coding-standards.tgz` - a CodeQL query pack for reporting violations of CERT C. + * `cert-cpp-coding-standards.tgz` - a CodeQL query pack for reporting violations of CERT C++. + * `autosar-cpp-coding-standards.tgz` - a CodeQL query pack for reporting violations of AUTOSAR for C++. + * `common-cpp-coding-standards.tgz` - a CodeQL library pack, used if you are writing your own C++ queries against Coding Standards. + * `common-c-coding-standards.tgz` - a CodeQL library pack, used if you are writing your own C queries against Coding Standards. + * `report-coding-standards.tgz` - a CodeQL query pack for running diagnostics on databases. + +Each pack will need to be decompressed using the `tar` program, and placed in a known location. + +Finally, we provide a legacy single zip containing all the artifacts from a release, named `code-scanning-cpp-query-pack.zip`. This also contains the CodeQL packs listed above. #### Creating a CodeQL database @@ -189,36 +232,81 @@ Reference: [CodeQL CLI: Creating a CodeQL database](https://codeql.github.com/do #### Running the default analysis for one or more Coding Standards -Once you have a CodeQL database for your project, you can run the "default" query suite. This will run all the "automated" queries for each implemented rule in the specified Coding Standards. +Once you have a CodeQL database for your project you can run the default analysis for a specified Coding Standard using the `codeql database analyze` command by specifying the names of the QL packs which you want to run as arguments, along with a version specifier: + +```bash +codeql database analyze --format=sarifv2.1.0 --output=.sarif path/to/ codeql/--coding-standard@version +``` + +For example, this command would run MISRA C and CERT C with the default query sets: + +```bash +codeql database analyze --format=sarifv2.1.0 --output=results.sarif path/to/ codeql/misra-c-coding-standard@version codeql/cert-c-coding-standard@version +``` +The output of this command will be a [SARIF file](https://sarifweb.azurewebsites.net/) called `.sarif`. + +##### Locating the Coding Standards CodeQL packs + +If you have downloaded a release artifact containing the packs, you will need to provide the `--search-path` parameter, pointing to each of the uncompressed query packs. +``` +--search-path path/to/pack1:path/to/pack2 +``` + +Alternatively, the packs can be made available to CodeQL without specification on the comamnd line by placing them inside the distribution under the `qlpacks/codeql/` directory, or placed inside a directory adjacent to the folder containing the distribution. + +##### Alternative query sets + +Each supported standard includes a variety of query suites, which enable the running of different sets of queries based on specified properties. In addition, a custom query suite can be defined as specified by the CodeQL CLI documentation, in order to select any arbitrary sets of queries in this repository. To run + +```bash +codeql database analyze --format=sarifv2.1.0 --output=.sarif path/to/ codeql/--coding-standard@version:codeql-suites/.qls +``` -The query suites can be run by using the `codeql database analyze` command: +If modifying the query suite, ensure that all Rules you expect to be covered by CodeQL in your Guideline Enforcement Plan (or similar) are included in the query suite, by running: ```bash -codeql database analyze --format=sarifv2.1.0 --output=.sarif path/to/ path/to/codeql-coding-standards/cpp//src/codeql-suites/-default.qls... +codeql resolve queries codeql/--coding-standard@version:codeql-suites/.qls ``` -For each Coding Standard you want to run, add a trailing entry in the following format: `path/to/codeql-coding-standards/cpp//src/codeql-suites/-default.qls`. +##### Supported SARIF versions The only supported SARIF version for use in a functional safety environment is version 2.1.0. To select this SARIF version you **must** specify the flag `--format=sarifv2.1.0` when invoking the database analyze command `codeql database analyze ...` as shown in the above example. -Running the default analysis for one or more Coding Standards may require further performance customizations for larger codebases. -The following flags may be passed to the `database analyze` command to adjust the performance: +##### Performance optimizations -- `--ram` - to specify the maximum amount of RAM to use during the analysis as [documented](https://codeql.github.com/docs/codeql-cli/manual/database-analyze/#options-to-control-ram-usage) in the CodeQL CLI manual. -- `--thread` - to specify number of threads to use while evaluating as [documented](https://codeql.github.com/docs/codeql-cli/manual/database-analyze/#cmdoption-codeql-database-analyze-j) in the CodeQL CLI manual. +Running the default analysis for one or more Coding Standards may require further performance customizations for larger codebases. The following flags may be passed to the `database analyze` command to adjust the performance: -The output of this command will be a [SARIF file](https://sarifweb.azurewebsites.net/) called `.sarif`. +- `--ram` - to specify the maximum amount of RAM to use during the analysis as [documented](https://docs.github.com/en/code-security/codeql-cli/codeql-cli-manual/database-analyze#options-to-control-ram-usage) in the CodeQL CLI manual. +- `--thread` - to specify number of threads to use while evaluating as [documented](https://docs.github.com/en/code-security/codeql-cli/codeql-cli-manual/database-analyze#-j---threadsnum) in the CodeQL CLI manual. + +##### Legacy approach + +If you have downloaded the legacy release artifact `code-scanning-query-pack.zip`, you can run the default query suite using the `codeql database analyze` command as follows: + +```bash +codeql database analyze --format=sarifv2.1.0 --output=.sarif path/to/ path/to/codeql-coding-standards///src/codeql-suites/-default.qls... +``` + +For each Coding Standard you want to run, add a trailing entry in the following format: `path/to/codeql-coding-standards///src/codeql-suites/-default.qls`. Custom query suites can be run by specifying the appropriate paths. -#### Running the analysis for audit level queries +All other options discussed above are valid. -Optionally, you may want to run the "audit" level queries. These queries produce lists of results that do not directly highlight contraventions of the rule. Instead, they identify locations in the code that can be manually audited to verify the absence of problems for that particular rule. +#### Running the analysis for strict and/or audit level queries + +Optionally, you may want to run the "strict" or "audit" level queries. + +Audit queries produce lists of results that do not directly highlight contraventions of the rule. Instead, they identify locations in the code that can be manually audited to verify the absence of problems for that particular rule. ```bash codeql database analyze --format=sarifv2.1.0 --output=.sarif path/to/ path/to/codeql-coding-standards/cpp//src/codeql-suites/-audit.qls... ``` -For each Coding Standard you want to run, add a trailing entry in the following format: `path/to/codeql-coding-standards/cpp//src/codeql-suites/-default.qls`. +Strict queries identify contraventions in the code that strongly suggest they are deliberate, and where adding an explicit _deviation report_ may be extra burden on developers. + +```bash +codeql database analyze --format=sarifv2.1.0 --output=.sarif path/to/ path/to/codeql-coding-standards/cpp//src/codeql-suites/-strict.qls... +``` #### Producing an analysis report @@ -331,7 +419,7 @@ The example describes three ways of scoping a deviation: 1. The deviation for `A18-1-1` applies to any source file in the same or a child directory of the directory containing the example `coding-standards.yml`. 2. The deviation for `A18-5-1` applies to any source file in the directory `foo/bar` or a child directory of `foo/bar` relative to the directory containing the `coding-standards.yml`. -3. The deviation for `A0-4-2` applies to any source element that has a comment residing on **the same line** containing the identifier specified in `code-identifier`. +3. The deviation for `A0-4-2` applies to any source element that marked by a comment containing the identifier specified in `code-identifier`. The different acceptable formats are discussed in the next section. The activation of the deviation mechanism requires an extra step in the database creation process. This extra step is the invocation of the Python script `path/to/codeql-coding-standards/scripts/configuration/process_coding_standards_config.py` that is part of the coding standards code scanning pack. @@ -346,7 +434,90 @@ The `process_coding_standards_config.py` has a dependency on the package `pyyaml `pip3 install -r path/to/codeql-coding-standards/scripts/configuration/requirements.txt` -##### Deviation permit +##### Deviation code identifier attributes + +A code identifier specified in a deviation record can be applied to certain results in the code by adding a C or C++ attribute of the following format: + +``` +[[codeql::_deviation("code-identifier")]] +``` + +For example `[[codeql::autosar_deviation("a1-2-4")]]` would apply a deviation of a rule in the AUTOSAR standard, using the code identifier `a1-2-4`. The supported standard names are `misra`, `autosar` and `cert`. + +This attribute may be added to the following program elements: + + * Functions + * Statements + * Variables + +Deviation attributes are inherited from parents in the code structure. For example, a deviation attribute applied to a function will apply the deviation to all code within the function. + +Multiple code identifiers may be passed in a single attribute to apply multiple deviations, for example: + +``` +[[codeql::misra_deviation("code-identifier-1", "code-identifier-2")]] +``` + +Note - considation should be taken to ensure the use of custom attributes for deviations is compatible with your chosen language version, compiler, compiler configuration and coding standard. + +**Use of attributes in C Coding Standards**: The C Standard introduces attributes in C23, however some compilers support attributes as a language extension in prior versions. You should: + * Confirm that your compiler supports attributes for your chosen compiler configuration, if necessary as a language extension. + * Confirm that unknown attributes are ignored by the compiler. + * For MISRA C, add a project deviation against "Rule 1.2: Language extensions should not be used", if attribute support is a language extension in your language version. + +**Use of attributes in C++ Coding Standards**: The C++ Standard supports attributes in C++14, however the handling of unknown attributes is implementation defined. From C++17 onwards, unknown attributes are mandated to be ignored. Unknown attributes will usually raise an "unknown attribute" warning. You should: + * If using C++14, confirm that your compiler ignores unknown attributes. + * If using AUTOSAR and a compiler which produces warnings on unknown attributes, the compiler warning should be disabled (as per `A1-1-2: A warning level of the compilation process shall be set in compliance with project policies`), to ensure compliance with `A1-4-3: All code should compiler free of compiler warnings`. + +If you cannot satisfy these condition, please use the deviation code identifier comment format instead. + +##### Deviation code identifier comments + +As an alternative to attributes, a code identifier specified in a deviation record can be applied to certain results in the code by adding a comment marker consisting of a `code-identifier` with some optional annotations. The supported marker annotation formats are: + + - `` - the deviation applies to results on the current line. + - `codeql::_deviation()` - the deviation applies to results on the current line. + - `codeql::_deviation_next_line()` - this deviation applies to results on the next line. + - `codeql::_deviation_begin()` - marks the beginning of a range of lines where the deviation applies. + - `codeql::_deviation_end()` - marks the end of a range of lines where the deviation applies. + +Here are some examples, using the deviation record with the `a-0-4-2-deviation` code-identifier specified above: +```cpp + long double x1; // NON_COMPLIANT + + long double x2; // a-0-4-2-deviation - COMPLIANT + long double x3; // COMPLIANT - a-0-4-2-deviation + + long double x4; // codeql::autosar_deviation(a-0-4-2-deviation) - COMPLIANT + long double x5; // COMPLIANT - codeql::autosar_deviation(a-0-4-2-deviation) + + // codeql::autosar_deviation_next_line(a-0-4-2-deviation) + long double x6; // COMPLIANT + + // codeql::autosar_deviation_begin(a-0-4-2-deviation) + long double x7; // COMPLIANT + // codeql::autosar_deviation_end(a-0-4-2-deviation) +``` + +`codeql::_deviation_end` markers will pair with the closest unmatched `codeql::_deviation_begin` for the same `code-identifier`. Consider this example: +```cpp +1 | // codeql::autosar_deviation_begin(a-0-4-2-deviation) +2 | +3 | // codeql::autosar_deviation_begin(a-0-4-2-deviation) +4 | +5 | // codeql::autosar_deviation_end(a-0-4-2-deviation) +6 | +7 | // codeql::autosar_deviation_end(a-0-4-2-deviation) +``` +Here, Line 1 will pair with Line 7, and Line 3 will pair with Line 5. + +A `codeql::_deviation_end` without a matching `codeql::_deviation_begin`, or `codeql::_deviation_begin` without a matching `codeql::_deviation_end` is invalid and will be ignored. + +`codeql::_deviation_begin` and `ccodeql::_deviation_end` markers only apply within a single file. Markers cannot be paired across files, and deviations do not apply to included files. + +Note: deviation comment markers cannot be applied to the body of a macro. Please apply the deviation to macro expansion, or use the attribute deviation format. + +##### Deviation permits The current implementation supports _deviation permits_ as described in the [MISRA Compliance:2020](https://www.misra.org.uk/app/uploads/2021/06/MISRA-Compliance-2020.pdf) section _4.3 Deviation permits_. @@ -496,14 +667,15 @@ This section describes known failure modes for "CodeQL Coding Standards" and des | | Use of incorrect build command | Less output. Some files may be only be partially analyzed, or not analyzed at all. | Analysis integrity report lists all analyzed files, and must be crossed referenced with the list of files that are expected to be analyzed. | Ensure the build command corresponds to the build command that is used to build the release artifacts. | | | Incorrect build environment (e.g., concurrent builds writing to same file, overwriting translation unit/object file with different content) | Less or more output. Results are reported that are not violations of the guidelines or guideline violations are not reported | All reported results must be reviewed. | Ensure the build environment is configured to not use shared resources such as caches or artifact providers that can introduce race conditions. Report inconsistent results via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | Source root misspecification | Less output. The results cannot be correctly correlated to source files when viewing the resulting Sarif file in a Sarif viewer. | Verify that the reported results are display on the correct files in the Sarif viewer | Ensure the CodeQL CLI configured to use the correct source root that correspond to the root of the repository under consideration. | -| | Ouf 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). | +| | 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.32.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.52.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. | | | Incorrect database. The information extracted by the CodeQL extractor deviates from what the compiler extracts resulting in an incorrect model of the source-code. | More or less output. Incorrect extraction can result in false positives or false negatives. | Combinations of supported compilers and CodeQL CLIs are tested against a [provided](https://github.com/github/codeql/tree/main/cpp/ql/test/library-tests) suite of test cases and a coding standards specific test suite to determine if the extracted information deviates from the expected information. | Report incorrect database issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | +| | Use of assembly language instructions, which are not inspected by CodeQL. | More or less output. Can result in false positives or false negatives. | Avoid the use of assembly language instructions where possible. Where unavoidable, encapasulate and isolate the use of assembly language in separate functions to limit impact. Careful manual review of all functions that use assembly language. | Ensure that all functions which use assembly language instructions are manually reviewed for compliance. | ## Reporting bugs diff --git a/rule_packages/c/Alignment.json b/rule_packages/c/Alignment.json new file mode 100644 index 0000000000..edf06a09ca --- /dev/null +++ b/rule_packages/c/Alignment.json @@ -0,0 +1,79 @@ +{ + "MISRA-C-2012": { + "RULE-8-15": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "An object declared with an explicit alignment shall be explicitly aligned in all declarations.", + "kind": "problem", + "name": "Alignment should match between all declarations of an object", + "precision": "very-high", + "severity": "error", + "short_name": "RedeclarationOfObjectWithoutAlignment", + "tags": [ + "external/misra/c/2012/amendment3", + "readability", + "maintainability" + ] + }, + { + "description": "All declarations of an object with an explicit alignment specification shall specify the same alignment.", + "kind": "problem", + "name": "Alignment should match between all declarations of an object", + "precision": "very-high", + "severity": "error", + "short_name": "RedeclarationOfObjectWithUnmatchedAlignment", + "tags": [ + "external/misra/c/2012/amendment3", + "readability", + "maintainability" + ] + } + ], + "title": "All declarations of an object with an explicit alignment specification shall specify the same alignment" + }, + "RULE-8-16": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "A declaration shall not have an alignment of size zero.", + "kind": "problem", + "name": "The alignment specification of zero should not appear in an object declaration", + "precision": "very-high", + "severity": "error", + "short_name": "AlignmentWithSizeZero", + "tags": [ + "external/misra/c/2012/amendment3", + "readability", + "maintainability" + ] + } + ], + "title": "The alignment specification of zero should not appear in an object declaration" + }, + "RULE-8-17": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "While C permits the usage of multiple alignment specifiers, doing so reduces readability and may obscure the intent of the declaration.", + "kind": "problem", + "name": "At most one explicit alignment specifier should appear in an object declaration", + "precision": "very-high", + "severity": "error", + "short_name": "MoreThanOneAlignmentSpecifierOnDeclaration", + "tags": [ + "external/misra/c/2012/amendment3", + "readability" + ] + } + ], + "title": "At most one explicit alignment specifier should appear in an object declaration" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/Banned.json b/rule_packages/c/Banned.json index 42decbb3e3..265a41de51 100644 --- a/rule_packages/c/Banned.json +++ b/rule_packages/c/Banned.json @@ -13,7 +13,12 @@ "severity": "error", "short_name": "DoNotCallSystem", "tags": [ - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ] } ], @@ -35,7 +40,8 @@ "short_name": "CommaOperatorShouldNotBeUsed", "shared_implementation_short_name": "CommaOperatorUsed", "tags": [ - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -54,7 +60,8 @@ "severity": "error", "short_name": "FeaturesOfStdarghUsed", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -73,7 +80,8 @@ "severity": "warning", "short_name": "UnionKeywordShouldNotBeUsed", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -92,7 +100,8 @@ "severity": "error", "short_name": "StandardLibraryTimeAndDateFunctionsUsed", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -100,7 +109,7 @@ }, "RULE-21-11": { "properties": { - "obligation": "required" + "obligation": "advisory" }, "queries": [ { @@ -111,7 +120,8 @@ "severity": "error", "short_name": "StandardHeaderFileTgmathhUsed", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -130,7 +140,8 @@ "severity": "warning", "short_name": "ExceptionHandlingFeaturesOfFenvhUsed", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/amendment2" ] } ], @@ -149,7 +160,8 @@ "severity": "error", "short_name": "SystemOfStdlibhUsed", "tags": [ - "security" + "security", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -169,7 +181,8 @@ "short_name": "MemoryAllocDeallocFunctionsOfStdlibhUsed", "tags": [ "correctness", - "security" + "security", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -188,7 +201,8 @@ "severity": "error", "short_name": "StandardHeaderFileUsedSetjmph", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -207,7 +221,8 @@ "severity": "error", "short_name": "StandardHeaderFileUsedSignalh", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -227,7 +242,8 @@ "short_name": "StandardLibraryInputoutputFunctionsUsed", "tags": [ "security", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -245,8 +261,10 @@ "precision": "very-high", "severity": "error", "short_name": "AtofAtoiAtolAndAtollOfStdlibhUsed", + "shared_implementation_short_name": "AtofAtoiAtolAndAtollUsed", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -266,7 +284,8 @@ "short_name": "TerminationFunctionsOfStdlibhUsed", "tags": [ "correctness", - "security" + "security", + "external/misra/c/2012/third-edition-first-revision" ] }, { @@ -278,7 +297,8 @@ "short_name": "TerminationMacrosOfStdlibhUsed", "tags": [ "correctness", - "security" + "security", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -298,7 +318,8 @@ "short_name": "BsearchAndQsortOfStdlibhUsed", "tags": [ "security", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -319,7 +340,8 @@ "tags": [ "security", "correctness", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -337,10 +359,12 @@ "precision": "very-high", "severity": "error", "short_name": "OctalConstantsUsed", + "shared_implementation_short_name": "UseOfNonZeroOctalLiteral", "tags": [ "readability", "correctness", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -360,7 +384,8 @@ "short_name": "RestrictTypeQualifierUsed", "tags": [ "correctness", - "security" + "security", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/Banned2.json b/rule_packages/c/Banned2.json new file mode 100644 index 0000000000..3898125d73 --- /dev/null +++ b/rule_packages/c/Banned2.json @@ -0,0 +1,24 @@ +{ + "MISRA-C-2012": { + "RULE-21-24": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "The standard functions rand() and srand() will not give high quality random results in all implementations and are therefore banned.", + "kind": "problem", + "name": "The random number generator functions of shall not be used", + "precision": "very-high", + "severity": "warning", + "short_name": "CallToBannedRandomFunction", + "tags": [ + "security", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "The random number generator functions of shall not be used" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/BitfieldTypes.json b/rule_packages/c/BitfieldTypes.json index 4e93f3371a..43ed42f174 100644 --- a/rule_packages/c/BitfieldTypes.json +++ b/rule_packages/c/BitfieldTypes.json @@ -12,7 +12,10 @@ "precision": "very-high", "severity": "error", "short_name": "BitFieldsShallOnlyBeDeclaredWithAnAppropriateType", - "tags": [] + "shared_implementation_short_name": "BitFieldShallHaveAnAppropriateType", + "tags": [ + "external/misra/c/2012/third-edition-first-revision" + ] } ], "title": "Bit-fields shall only be declared with an appropriate type" @@ -29,7 +32,10 @@ "precision": "very-high", "severity": "error", "short_name": "SingleBitNamedBitFieldsOfASignedType", - "tags": [] + "shared_implementation_short_name": "NamedBitFieldsWithSignedIntegerType", + "tags": [ + "external/misra/c/2012/third-edition-first-revision" + ] } ], "title": "Single-bit named bit fields shall not be of a signed type" diff --git a/rule_packages/c/BitfieldTypes2.json b/rule_packages/c/BitfieldTypes2.json new file mode 100644 index 0000000000..957e9bb729 --- /dev/null +++ b/rule_packages/c/BitfieldTypes2.json @@ -0,0 +1,24 @@ +{ + "MISRA-C-2012": { + "RULE-6-3": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Type punning on a union with bit fields relies on implementation-specific alignment behavior.", + "kind": "problem", + "name": "A bit field shall not be declared as a member of a union", + "precision": "very-high", + "severity": "warning", + "short_name": "BitFieldDeclaredAsMemberOfAUnion", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "A bit field shall not be declared as a member of a union" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/Concurrency1.json b/rule_packages/c/Concurrency1.json index 15e38e941d..9daa2a83be 100644 --- a/rule_packages/c/Concurrency1.json +++ b/rule_packages/c/Concurrency1.json @@ -15,7 +15,12 @@ "shared_implementation_short_name": "GuardAccessToBitFields", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -35,7 +40,12 @@ "short_name": "RaceConditionsWhenUsingLibraryFunctions", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -55,7 +65,12 @@ "short_name": "DoNotCallSignalInMultithreadedProgram", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/low", + "external/cert/priority/p6", + "external/cert/level/l2" ], "implementation_scope": { "description": "This implementation does not consider threads created function pointers." diff --git a/rule_packages/c/Concurrency2.json b/rule_packages/c/Concurrency2.json index d9102a07df..d9e364d046 100644 --- a/rule_packages/c/Concurrency2.json +++ b/rule_packages/c/Concurrency2.json @@ -15,7 +15,12 @@ "shared_implementation_short_name": "PreventDeadlockByLockingInPredefinedOrder", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -36,7 +41,12 @@ "shared_implementation_short_name": "WrapSpuriousFunctionInLoop", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/Concurrency3.json b/rule_packages/c/Concurrency3.json index a57b73f034..6328f6b43c 100644 --- a/rule_packages/c/Concurrency3.json +++ b/rule_packages/c/Concurrency3.json @@ -15,7 +15,12 @@ "shared_implementation_short_name": "DoNotAllowAMutexToGoOutOfScopeWhileLocked", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "This implementation does not allow for thread synchronization to be performed in subroutines. All synchronization must be performed within the context of the other thread management functions." @@ -31,7 +36,12 @@ "shared_implementation_short_name": "DoNotDestroyAMutexWhileItIsLocked", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -52,7 +62,12 @@ "shared_implementation_short_name": "PreserveSafetyWhenUsingConditionVariables", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ], "implementation_scope": { "description": "This implementation does not attempt to identify unique condition variables and instead advocates for the usage of `cnd_broadcast`." @@ -75,7 +90,12 @@ "short_name": "WrapFunctionsThatCanFailSpuriouslyInLoop", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ], "implementation_scope": { "description": "This implementation does not attempt to identify a relationship between the condition variable and the atomic operation." diff --git a/rule_packages/c/Concurrency4.json b/rule_packages/c/Concurrency4.json index 65a17ed2d7..b981ebaa8b 100644 --- a/rule_packages/c/Concurrency4.json +++ b/rule_packages/c/Concurrency4.json @@ -14,19 +14,23 @@ "short_name": "CleanUpThreadSpecificStorage", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "This query does not attempt to ensure that the deallocation function in fact deallocates memory and instead assumes the contract is valid. Additionally, this query requires that all `tss_create` calls are bookended by calls to `tss_delete`, even if a thread is not created." } - } ], "title": "Clean up thread-specific storage" }, "CON34-C": { "properties": { - "obligation": "rule" + "obligation": "rule" }, "queries": [ { @@ -38,7 +42,12 @@ "short_name": "AppropriateThreadObjectStorageDurations", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "This query does not consider Windows implementations or OpenMP implementations. This query is primarily about excluding cases wherein the storage duration of a variable is appropriate. As such, this query is not concerned if the appropriate synchronization mechanisms are used, such as sequencing calls to `thrd_join` and `free`. An audit query is supplied to handle some of those cases." @@ -54,7 +63,12 @@ "tags": [ "external/cert/audit", "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/Concurrency5.json b/rule_packages/c/Concurrency5.json index 67707201fd..d1a685dd34 100644 --- a/rule_packages/c/Concurrency5.json +++ b/rule_packages/c/Concurrency5.json @@ -12,9 +12,15 @@ "precision": "high", "severity": "error", "short_name": "ThreadWasPreviouslyJoinedOrDetached", + "shared_implementation_short_name": "JoinOrDetachThreadOnlyOnce", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ], "implementation_scope": { "description": "This query considers problematic usages of join and detach irrespective of the execution of the program and other synchronization and interprocess communication mechanisms that may be used." @@ -37,7 +43,12 @@ "short_name": "AtomicVariableTwiceInExpression", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/c/Concurrency6.json b/rule_packages/c/Concurrency6.json new file mode 100644 index 0000000000..cfb793877e --- /dev/null +++ b/rule_packages/c/Concurrency6.json @@ -0,0 +1,132 @@ +{ + "MISRA-C-2012": { + "DIR-5-2": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Circular waits leading to thread deadlocks may be avoided by locking in a predefined order.", + "kind": "problem", + "name": "There shall be no deadlocks between threads", + "precision": "very-high", + "severity": "error", + "short_name": "NotNoDeadlocksBetweenThreads", + "shared_implementation_short_name": "PreventDeadlockByLockingInPredefinedOrder", + "tags": [ + "external/misra/c/2012/amendment4", + "correctness", + "concurrency" + ] + } + ], + "title": "There shall be no deadlocks between threads" + }, + "DIR-5-3": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Creating threads within threads creates uncertainty in program behavior and concurrency overhead costs.", + "kind": "problem", + "name": "Threads shall not be created by other threads", + "precision": "high", + "severity": "error", + "short_name": "ThreadCreatedByThread", + "tags": [ + "external/misra/c/2012/amendment4", + "correctness", + "maintainability", + "concurrency", + "performance" + ] + }, + { + "description": "Creating threads outside of a well-defined program start-up phase creates uncertainty in program behavior and concurrency overhead costs.", + "kind": "problem", + "name": "There shall be no dynamic thread creation", + "precision": "low", + "severity": "error", + "short_name": "BannedDynamicThreadCreation", + "tags": [ + "external/misra/c/2012/amendment4", + "external/misra/c/audit", + "correctness", + "maintainability", + "concurrency", + "performance" + ] + } + ], + "title": "There shall be no dynamic thread creation" + }, + "RULE-12-6": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Accessing a member of an atomic structure or union results in undefined behavior.", + "kind": "problem", + "name": "Structure and union members of atomic objects shall not be directly accessed", + "precision": "very-high", + "severity": "error", + "short_name": "AtomicAggregateObjectDirectlyAccessed", + "tags": [ + "external/misra/c/2012/amendment4", + "correctness", + "concurrency" + ] + } + ], + "title": "Structure and union members of atomic objects shall not be directly accessed" + }, + "RULE-21-25": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Only the memory ordering of 'memory_order_seq_cst' is fully portable and consistent.", + "kind": "path-problem", + "name": "All memory synchronization operations shall be executed in sequentially consistent order", + "precision": "very-high", + "severity": "error", + "short_name": "InvalidMemoryOrderArgument", + "tags": [ + "external/misra/c/2012/amendment4", + "correctness", + "concurrency" + ] + } + ], + "title": "All memory synchronization operations shall be executed in sequentially consistent order" + }, + "RULE-22-11": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Joining or detaching a previously joined or detached thread can lead to undefined program behavior.", + "kind": "problem", + "name": "A thread that was previously either joined or detached shall not be subsequently joined nor detached", + "precision": "high", + "severity": "error", + "short_name": "ThreadPreviouslyJoinedOrDetached", + "shared_implementation_short_name": "JoinOrDetachThreadOnlyOnce", + "tags": [ + "external/misra/c/2012/amendment4", + "correctness", + "concurrency" + ], + "implementation_scope": { + "description": "This query considers problematic usages of join and detach irrespective of the execution of the program and other synchronization and interprocess communication mechanisms that may be used." + } + } + ], + "title": "A thread that was previously either joined or detached shall not be subsequently joined nor detached" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/Concurrency7.json b/rule_packages/c/Concurrency7.json new file mode 100644 index 0000000000..bda8881934 --- /dev/null +++ b/rule_packages/c/Concurrency7.json @@ -0,0 +1,49 @@ +{ + "MISRA-C-2012": { + "RULE-9-7": { + "properties": { + "obligation": "mandatory" + }, + "queries": [ + { + "description": "Atomic objects that do not have static storage duration shall be initialized with a value or by using 'atomic_init()'.", + "kind": "problem", + "name": "Atomic objects shall be appropriately initialized before being accessed", + "precision": "high", + "severity": "warning", + "short_name": "UninitializedAtomicObject", + "tags": [ + "concurrency", + "external/misra/c/2012/amendment4" + ], + "implementation_scope": { + "description": "This query tracks which functions may start threads, either indirectly or directly (\"thread spawning functions\"), and checks for local atomic variables that are not passed by address into `atomic_init` or other function calls, before such a thread spawning function is called.", + "items": [] + } + } + ], + "title": "Atomic objects shall be appropriately initialized before being accessed" + }, + "RULE-21-26": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "The Standard Library function mtx_timedlock() shall only be invoked on mutex objects of appropriate mutex type.", + "kind": "path-problem", + "name": "The Standard Library function mtx_timedlock() shall only be invoked on mutexes of type mtx_timed", + "precision": "high", + "severity": "error", + "short_name": "TimedlockOnInappropriateMutexType", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "The Standard Library function mtx_timedlock() shall only be invoked on mutex objects of appropriate mutex type" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/Concurrency8.json b/rule_packages/c/Concurrency8.json new file mode 100644 index 0000000000..2dc5d48042 --- /dev/null +++ b/rule_packages/c/Concurrency8.json @@ -0,0 +1,115 @@ +{ + "MISRA-C-2012": { + "RULE-22-12": { + "properties": { + "obligation": "mandatory" + }, + "queries": [ + { + "description": "Thread objects, thread synchronization objects, and thread-specific storage pointers shall only be accessed by the appropriate Standard Library functions.", + "kind": "problem", + "name": "Standard library threading objects (mutexes, threads, etc.) shall only be accessed by the appropriate Standard Library functions", + "precision": "very-high", + "severity": "error", + "short_name": "NonstandardUseOfThreadingObject", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "Thread objects, thread synchronization objects, and thread-specific storage pointers shall only be accessed by the appropriate Standard Library functions" + }, + "RULE-22-13": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Thread objects, thread synchronization objects, and thread specific storage pointers shall have appropriate storage duration.", + "kind": "problem", + "name": "Threading objects (mutexes, threads, etc). shall have not have automatic or thread storage duration", + "precision": "very-high", + "severity": "error", + "short_name": "ThreadingObjectWithInvalidStorageDuration", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "Thread objects, thread synchronization objects, and thread specific storage pointers shall have appropriate storage duration" + }, + "RULE-22-14": { + "properties": { + "obligation": "mandatory" + }, + "queries": [ + { + "description": "Mutex and condition objects shall be initialized with the standard library functions before using them.", + "kind": "problem", + "name": "Thread synchronization objects shall be initialized before being accessed", + "precision": "high", + "severity": "error", + "short_name": "MutexNotInitializedBeforeUse", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + }, + { + "description": "Mutex and condition objects initialized inside of threads may result in indeterministic state.", + "kind": "problem", + "name": "Thread synchronization objects shall be initialized deterministically", + "precision": "high", + "severity": "recommendation", + "short_name": "MutexInitializedInsideThread", + "tags": [ + "readability", + "maintainability", + "concurrency", + "external/misra/c/2012/amendment4" + ] + }, + { + "description": "Mutexes shall be initialized with a valid mutex type.", + "kind": "problem", + "name": "Mutexes shall be initialized with a valid mutex type", + "precision": "high", + "severity": "error", + "short_name": "MutexInitWithInvalidMutexType", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "Thread synchronization objects shall be initialized before being accessed" + }, + "RULE-22-16": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Mutex not unlocked by thread on all execution paths in current thread after being locked.", + "kind": "problem", + "name": "All mutex objects locked by a thread shall be explicitly unlocked by the same thread", + "precision": "high", + "severity": "error", + "short_name": "MutexObjectsNotAlwaysUnlocked", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "All mutex objects locked by a thread shall be explicitly unlocked by the same thread" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/Concurrency9.json b/rule_packages/c/Concurrency9.json new file mode 100644 index 0000000000..6ae1df8173 --- /dev/null +++ b/rule_packages/c/Concurrency9.json @@ -0,0 +1,158 @@ +{ + "MISRA-C-2012": { + "DIR-5-1": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Threads shall not access the same memory location concurrently without utilization of thread synchronization objects.", + "kind": "problem", + "name": "There shall be no data races between threads", + "precision": "medium", + "severity": "error", + "short_name": "PossibleDataRaceBetweenThreads", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "There shall be no data races between threads" + }, + "RULE-22-15": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Thread synchronization objects and thread-specific storage pointers shall not be destroyed until after all threads accessing them have terminated.", + "kind": "problem", + "name": "Thread synchronization objects and thread-specific storage pointers shall not be disposed unsafely", + "precision": "medium", + "severity": "error", + "short_name": "ThreadResourceDisposedBeforeThreadsJoined", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "Thread synchronization objects and thread-specific storage pointers shall not be destroyed until after all threads accessing them have terminated" + }, + "RULE-22-17": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it has not locked before.", + "kind": "problem", + "name": "No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it has not locked", + "precision": "high", + "severity": "error", + "short_name": "InvalidOperationOnUnlockedMutex", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it has not locked before" + }, + "RULE-22-18": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Mutexes initialized with mtx_init() without mtx_recursive shall not be locked by a thread that has previously locked it.", + "kind": "problem", + "name": "Non-recursive mutexes shall not be recursively locked", + "precision": "very-high", + "severity": "error", + "short_name": "NonRecursiveMutexRecursivelyLocked", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + }, + { + "description": "Mutexes that may be initialized without mtx_recursive shall not be locked by a thread that may have previously locked it.", + "kind": "problem", + "name": "(Audit) Non-recursive mutexes shall not be recursively locked", + "precision": "high", + "severity": "error", + "short_name": "NonRecursiveMutexRecursivelyLockedAudit", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4", + "external/misra/audit" + ] + } + ], + "title": "Non-recursive mutexes shall not be recursively locked" + }, + "RULE-22-19": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Standard library functions cnd_wait() and cnd_timedwait() shall specify the same mutex object for each condition object in all calls.", + "kind": "problem", + "name": "A condition variable shall be associated with at most one mutex object", + "precision": "very-high", + "severity": "error", + "short_name": "ConditionVariableUsedWithMultipleMutexes", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "A condition variable shall be associated with at most one mutex object" + }, + "RULE-22-20": { + "properties": { + "obligation": "mandatory" + }, + "queries": [ + { + "description": "Thread specific storage pointers shall be initialized with the standard library functions before using them.", + "kind": "problem", + "name": "Thread-specific storage pointers shall be created before being accessed", + "precision": "high", + "severity": "error", + "short_name": "ThreadStorageNotInitializedBeforeUse", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + }, + { + "description": "Thread specific storage pointers initialized inside of threads may result in indeterministic state.", + "kind": "problem", + "name": "Thread specific storage pointers shall be initialized deterministically", + "precision": "very-high", + "severity": "recommendation", + "short_name": "ThreadStoragePointerInitializedInsideThread", + "tags": [ + "readability", + "maintainability", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "Thread-specific storage pointers shall be created before being accessed" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/Contracts.json b/rule_packages/c/Contracts.json new file mode 100644 index 0000000000..0d2e0a97bd --- /dev/null +++ b/rule_packages/c/Contracts.json @@ -0,0 +1,94 @@ +{ + "CERT-C": { + "MSC40-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Inlined external functions are prohibited by the language standard from defining modifiable static or thread storage objects, or referencing identifiers with internal linkage.", + "kind": "problem", + "name": "Do not violate inline linkage constraints", + "precision": "very-high", + "severity": "error", + "short_name": "DoNotViolateInLineLinkageConstraints", + "tags": [ + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" + ], + "implementation_scope": { + "description": "This query only considers the constraints related to inline extern functions." + } + } + ], + "title": "Do not violate constraints" + } + }, + "MISRA-C-2012": { + "DIR-4-11": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Range, domain or pole errors in math functions may return unexpected values, trigger floating-point exceptions or set unexpected error modes.", + "kind": "problem", + "name": "The validity of values passed to `math.h` library functions shall be checked", + "precision": "high", + "severity": "error", + "short_name": "CheckMathLibraryFunctionParameters", + "shared_implementation_short_name": "UncheckedRangeDomainPoleErrors", + "tags": [ + "correctness", + "external/misra/c/2012/third-edition-first-revision" + ], + "implementation_scope": { + "description": "This query identifies possible domain, pole and range errors on a selection of C standard library fuctions from math.h." + } + }, + { + "description": "Trigonometric periodic functions have significantly less precision when called with large floating-point values.", + "kind": "problem", + "name": "The validity of values passed to trigonometric functions shall be checked", + "precision": "high", + "severity": "warning", + "short_name": "LowPrecisionPeriodicTrigonometricFunctionCall", + "tags": [ + "correctness", + "external/misra/c/2012/third-edition-first-revision", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "The validity of values passed to library functions shall be checked" + }, + "DIR-4-7": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "A function (whether it is part of the standard library, a third party library or a user defined function) may provide some means of indicating the occurrence of an error. This may be via a global error flag, a parametric error flag, a special return value or some other means. Whenever such a mechanism is provided by a function the calling program shall check for the indication of an error as soon as the function returns.", + "kind": "problem", + "name": "If a function generates error information, then that error information shall be tested", + "precision": "very-high", + "severity": "recommendation", + "short_name": "FunctionErrorInformationUntested", + "shared_implementation_short_name": "FunctionErroneousReturnValueNotTested", + "tags": [ + "maintainability", + "external/misra/c/2012/third-edition-first-revision" + ], + "implementation_scope": { + "description": "This query enforces checking on some C standard library functions that may return error codes." + } + } + ], + "title": "If a function returns error information, then that error information shall be tested" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/Contracts1.json b/rule_packages/c/Contracts1.json index 2882bb617f..65ffdc5e71 100644 --- a/rule_packages/c/Contracts1.json +++ b/rule_packages/c/Contracts1.json @@ -4,38 +4,52 @@ "properties": { "obligation": "rule" }, - "queries": [{ - "description": "Modification of return values of getenv and similar functions results in undefined behaviour.", - "kind": "path-problem", - "name": "Do not modify the return value of certain functions", - "precision": "very-high", - "severity": "warning", - "short_name": "DoNotModifyTheReturnValueOfCertainFunctions", - "shared_implementation_short_name": "ConstLikeReturnValue", - "tags": [ - "correctness" - ] - }], + "queries": [ + { + "description": "Modification of return values of getenv and similar functions results in undefined behaviour.", + "kind": "path-problem", + "name": "Do not modify the return value of certain functions", + "precision": "very-high", + "severity": "warning", + "short_name": "DoNotModifyTheReturnValueOfCertainFunctions", + "shared_implementation_short_name": "ConstLikeReturnValue", + "tags": [ + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" + ] + } + ], "title": "Do not modify the object referenced by the return value of certain functions" }, "ENV31-C": { "properties": { "obligation": "rule" }, - "queries": [{ - "description": "Using the envp pointer after environment modifications can result in undefined behavior.", - "kind": "problem", - "name": "Do not rely on an env pointer following an operation that may invalidate it", - "precision": "high", - "severity": "error", - "short_name": "EnvPointerIsInvalidAfterCertainOperations", - "tags": [ - "correctness" - ], - "implementation_scope": { - "description": "The rule is enforced in the context of a single function." + "queries": [ + { + "description": "Using the envp pointer after environment modifications can result in undefined behavior.", + "kind": "problem", + "name": "Do not rely on an env pointer following an operation that may invalidate it", + "precision": "high", + "severity": "error", + "short_name": "EnvPointerIsInvalidAfterCertainOperations", + "tags": [ + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" + ], + "implementation_scope": { + "description": "The rule is enforced in the context of a single function." + } } - }], + ], "title": "Do not rely on an environment pointer following an operation that may invalidate it" } } diff --git a/rule_packages/c/Contracts2.json b/rule_packages/c/Contracts2.json index b4845fc2be..6c1bf77de2 100644 --- a/rule_packages/c/Contracts2.json +++ b/rule_packages/c/Contracts2.json @@ -13,7 +13,12 @@ "severity": "error", "short_name": "ExitHandlersMustReturnNormally", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ] } ], @@ -33,7 +38,12 @@ "short_name": "DoNotStorePointersReturnedByEnvFunctions", "shared_implementation_short_name": "InvalidatedEnvStringPointers", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -45,7 +55,12 @@ "short_name": "DoNotStorePointersReturnedByEnvironmentFunWarn", "shared_implementation_short_name": "InvalidatedEnvStringPointersWarn", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -67,7 +82,8 @@ "short_name": "ValuesReturnedByLocaleSettingUsedAsPtrToConst", "shared_implementation_short_name": "ConstLikeReturnValue", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -87,7 +103,8 @@ "short_name": "CallToSetlocaleInvalidatesOldPointers", "shared_implementation_short_name": "InvalidatedEnvStringPointers", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] }, { @@ -99,7 +116,8 @@ "short_name": "CallToSetlocaleInvalidatesOldPointersWarn", "shared_implementation_short_name": "InvalidatedEnvStringPointersWarn", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/Contracts3.json b/rule_packages/c/Contracts3.json index 8cb997c3b2..0122b858b5 100644 --- a/rule_packages/c/Contracts3.json +++ b/rule_packages/c/Contracts3.json @@ -4,46 +4,61 @@ "properties": { "obligation": "required" }, - "queries": [{ - "description": "The value of errno shall only be tested when the last function to be called was an errno-setting-function. Testing the value in these conditions does not guarantee the absence of an errors.", - "kind": "problem", - "name": "The value of errno shall only be tested when the last called function is errno-setting", - "precision": "high", - "severity": "warning", - "short_name": "OnlyTestErrnoRightAfterErrnoSettingFunction", - "tags": ["correctness"] - }], + "queries": [ + { + "description": "The value of errno shall only be tested when the last function to be called was an errno-setting-function. Testing the value in these conditions does not guarantee the absence of an errors.", + "kind": "problem", + "name": "The value of errno shall only be tested when the last called function is errno-setting", + "precision": "high", + "severity": "warning", + "short_name": "OnlyTestErrnoRightAfterErrnoSettingFunction", + "tags": [ + "correctness", + "external/misra/c/2012/third-edition-first-revision" + ] + } + ], "title": "The value of errno shall only be tested when the last function to be called was an errno-setting-function" }, "RULE-22-8": { "properties": { "obligation": "required" }, - "queries": [{ - "description": "The value of errno shall be set to zero prior to a call to an errno-setting-function. Not setting the value leads to incorrectly identifying errors.", - "kind": "problem", - "name": "The value of errno shall be set to zero prior to a call to an errno-setting-function", - "precision": "very-high", - "severity": "error", - "short_name": "ErrnoSetToZeroPriorToCall", - "tags": ["correctness"] - }], + "queries": [ + { + "description": "The value of errno shall be set to zero prior to a call to an errno-setting-function. Not setting the value leads to incorrectly identifying errors.", + "kind": "problem", + "name": "The value of errno shall be set to zero prior to a call to an errno-setting-function", + "precision": "very-high", + "severity": "error", + "short_name": "ErrnoSetToZeroPriorToCall", + "tags": [ + "correctness", + "external/misra/c/2012/third-edition-first-revision" + ] + } + ], "title": "The value of errno shall be set to zero prior to a call to an errno-setting-function" }, "RULE-22-9": { "properties": { "obligation": "required" }, - "queries": [{ - "description": "The value of errno shall be tested against zero after calling an errno-setting-function. Not testing the value leads to unidentified errors.", - "kind": "problem", - "name": "The value of errno shall be tested against zero after calling an errno-setting-function", - "precision": "very-high", - "severity": "error", - "short_name": "ErrnoSetToZeroAfterCall", - "tags": ["correctness"] - }], + "queries": [ + { + "description": "The value of errno shall be tested against zero after calling an errno-setting-function. Not testing the value leads to unidentified errors.", + "kind": "problem", + "name": "The value of errno shall be tested against zero after calling an errno-setting-function", + "precision": "very-high", + "severity": "error", + "short_name": "ErrnoSetToZeroAfterCall", + "tags": [ + "correctness", + "external/misra/c/2012/third-edition-first-revision" + ] + } + ], "title": "The value of errno shall be tested against zero after calling an errno-setting-function" } } -} +} \ No newline at end of file diff --git a/rule_packages/c/Contracts4.json b/rule_packages/c/Contracts4.json index 90568bec98..a62e9d1762 100644 --- a/rule_packages/c/Contracts4.json +++ b/rule_packages/c/Contracts4.json @@ -4,22 +4,38 @@ "properties": { "obligation": "rule" }, - "queries": [{ + "queries": [ + { "description": "Do not rely solely on errno to determine if en error occurred in setlocale.", "kind": "problem", "name": "Do not rely solely on errno to determine if en error occurred in setlocale", "precision": "high", "severity": "error", "short_name": "SetlocaleMightSetErrno", - "tags": ["correctness"] - }, { + "tags": [ + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" + ] + }, + { "description": "Do not check errno before the function return value. Failing to do so might invalidate the error detection.", "kind": "problem", "name": "Do not check errno before the function return value", "precision": "high", "severity": "error", "short_name": "ErrnoReadBeforeReturn", - "tags": ["correctness"] + "tags": [ + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" + ] }, { "description": "After calling an errno-setting function, check errno before calling any other function. Failing to do so might end in errno being overwritten.", @@ -28,7 +44,14 @@ "precision": "high", "severity": "error", "short_name": "FunctionCallBeforeErrnoCheck", - "tags": ["correctness"] + "tags": [ + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" + ] }, { "description": "Set errno to zero prior to each call to an errno-setting function. Failing to do so might end in spurious errno values.", @@ -37,7 +60,14 @@ "precision": "high", "severity": "error", "short_name": "ErrnoNotSetToZero", - "tags": ["correctness"] + "tags": [ + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" + ] } ], "title": "Take care when reading errno" diff --git a/rule_packages/c/Contracts5.json b/rule_packages/c/Contracts5.json index 1032e0546e..d4b38b5756 100644 --- a/rule_packages/c/Contracts5.json +++ b/rule_packages/c/Contracts5.json @@ -4,36 +4,54 @@ "properties": { "obligation": "rule" }, - "queries": [{ - "description": "Do not rely on indeterminate values of errno. This may result in undefined behavior.", - "kind": "problem", - "name": "Do not rely on indeterminate values of errno", - "precision": "high", - "severity": "error", - "short_name": "DoNotRelyOnIndeterminateValuesOfErrno", - "tags": ["correctness"], - "implementation_scope": { - "description": "The rule is enforced in the context of a single function." + "queries": [ + { + "description": "Do not rely on indeterminate values of errno. This may result in undefined behavior.", + "kind": "problem", + "name": "Do not rely on indeterminate values of errno", + "precision": "high", + "severity": "error", + "short_name": "DoNotRelyOnIndeterminateValuesOfErrno", + "tags": [ + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" + ], + "implementation_scope": { + "description": "The rule is enforced in the context of a single function." + } } - }], + ], "title": "Do not rely on indeterminate values of errno" }, "ERR33-C": { "properties": { "obligation": "rule" }, - "queries": [{ - "description": "Detect and handle standard library errors. Undetected failures can lead to unexpected or undefined behavior.", - "kind": "problem", - "name": "Detect and handle standard library errors", - "precision": "high", - "severity": "error", - "short_name": "DetectAndHandleStandardLibraryErrors", - "tags": ["correctness"], - "implementation_scope": { - "description": "The rule is enforced in the context of a single function." + "queries": [ + { + "description": "Detect and handle standard library errors. Undetected failures can lead to unexpected or undefined behavior.", + "kind": "problem", + "name": "Detect and handle standard library errors", + "precision": "high", + "severity": "error", + "short_name": "DetectAndHandleStandardLibraryErrors", + "tags": [ + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" + ], + "implementation_scope": { + "description": "The rule is enforced in the context of a single function." + } } - }], + ], "title": "Detect and handle standard library errors" } } diff --git a/rule_packages/c/Contracts6.json b/rule_packages/c/Contracts6.json index bc707f19f4..d89617d6dc 100644 --- a/rule_packages/c/Contracts6.json +++ b/rule_packages/c/Contracts6.json @@ -12,7 +12,14 @@ "precision": "high", "severity": "error", "short_name": "DoNotModifyConstantObjects", - "tags": ["correctness"], + "tags": [ + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" + ], "implementation_scope": { "description": "The implementation does not consider pointer aliasing via multiple indirection." } @@ -24,7 +31,7 @@ "MISRA-C-2012": { "RULE-17-5": { "properties": { - "obligation": "advisory" + "obligation": "required" }, "queries": [ { @@ -34,7 +41,10 @@ "precision": "high", "severity": "error", "short_name": "ArrayFunctionArgumentNumberOfElements", - "tags": ["correctness"] + "tags": [ + "correctness", + "external/misra/c/2012/third-edition-first-revision" + ] } ], "title": "The function argument corresponding to an array parameter shall have an appropriate number of elements" @@ -51,7 +61,10 @@ "precision": "very-high", "severity": "error", "short_name": "ValueReturnedByAFunctionNotUsed", - "tags": ["correctness"] + "tags": [ + "correctness", + "external/misra/c/2012/third-edition-first-revision" + ] } ], "title": "The value returned by a function having non-void return type shall be used or cast to void" diff --git a/rule_packages/c/Contracts7.json b/rule_packages/c/Contracts7.json index 38a038621e..95df01ca32 100644 --- a/rule_packages/c/Contracts7.json +++ b/rule_packages/c/Contracts7.json @@ -14,7 +14,12 @@ "short_name": "DoNotPassInvalidDataToTheAsctimeFunction", "tags": [ "security", - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p27", + "external/cert/level/l1" ] } ], @@ -33,7 +38,12 @@ "severity": "error", "short_name": "DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], @@ -54,7 +64,8 @@ "severity": "error", "short_name": "RightHandOperandOfAShiftRange", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -73,7 +84,8 @@ "severity": "error", "short_name": "ObjectAssignedToAnOverlappingObject", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] }, { @@ -84,7 +96,8 @@ "severity": "error", "short_name": "ObjectCopiedToAnOverlappingObject", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/DeadCode.json b/rule_packages/c/DeadCode.json index 1de7625225..d8e80d14d1 100644 --- a/rule_packages/c/DeadCode.json +++ b/rule_packages/c/DeadCode.json @@ -14,7 +14,8 @@ "short_name": "UnreachableCode", "tags": [ "readability", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This query reports basic blocks in the program which are unreachable. For basic blocks within templates, the block is only consider unreachable if it is unreachable in all templates. Code generated by macros is ignored for this query, because it may be the case that basic blocks are reachable only in some expansions." @@ -38,22 +39,9 @@ "short_name": "DeadCode", "tags": [ "readability", - "maintainability" - ], - "implementation_scope": { - "description": "This query identifies dead statements in the program of the following kinds:", - "items": [ - "Declarations of a non-static stack variable whose initializing expression is pure (i.e. has no side-effects) and that is never subsequently accessed in live code.", - "Blocks that contain only dead statements.", - "Do loops whose condition is pure, and whose body contains only dead statements.", - "If statements whose condition is pure, and whose then and else clauses (where they exist) only contain dead statements.", - "Label statements to which the code never jumps.", - "While loops whose condition is pure, and whose body contains only dead statements.", - "Expression statements whose expressions are pure.", - "Writes to a non-static stack variable that is never subsequently read in live code." - ] - }, - "shared_implementation_short_name": "DeadCode" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" + ] } ], "title": "There shall be no dead code" @@ -72,7 +60,8 @@ "short_name": "UnusedTypeDeclarations", "tags": [ "readability", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ], "shared_implementation_short_name": "UnusedTypeDeclarations" } @@ -93,7 +82,8 @@ "short_name": "UnusedTagDeclaration", "tags": [ "readability", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -113,7 +103,8 @@ "short_name": "UnusedMacroDeclaration", "tags": [ "readability", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -133,7 +124,8 @@ "short_name": "UnusedLabelDeclaration", "tags": [ "readability", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -153,7 +145,8 @@ "short_name": "UnusedParameter", "tags": [ "readability", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ], "shared_implementation_short_name": "UnusedParameter" } diff --git a/rule_packages/c/DeadCode2.json b/rule_packages/c/DeadCode2.json new file mode 100644 index 0000000000..8b373c31b6 --- /dev/null +++ b/rule_packages/c/DeadCode2.json @@ -0,0 +1,42 @@ +{ + "MISRA-C-2012": { + "RULE-2-8": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "Object definitions which are unused should be removed.", + "kind": "problem", + "name": "A project should not contain unused object definitions", + "precision": "very-high", + "severity": "recommendation", + "short_name": "UnusedObjectDefinition", + "tags": [ + "maintainability", + "performance", + "external/misra/c/2012/amendment4" + ] + }, + { + "description": "A strict query which reports all unused object definitions with '__attribute__((unused))'.", + "kind": "problem", + "name": "A project should not contain '__attribute__((unused))' object definitions", + "precision": "very-high", + "severity": "recommendation", + "short_name": "UnusedObjectDefinitionStrict", + "tags": [ + "maintainability", + "performance", + "external/misra/c/2012/amendment4", + "external/misra/c/strict" + ] + } + ], + "title": "A project should not contain unused object definitions", + "implementation_scope": { + "description": "Unused object definitions marked with `__attribute__((unused))` (and `used`, `maybe_used`, `cleanup`) are separately reported under the 'strict' query suite. This is because these attributes strongly indicate the contravention is intentional, and a deviation report alone will not suppress compiler warnings." + } + } + } +} \ No newline at end of file diff --git a/rule_packages/c/Declarations1.json b/rule_packages/c/Declarations1.json index 217e1e077c..dba6a07eeb 100644 --- a/rule_packages/c/Declarations1.json +++ b/rule_packages/c/Declarations1.json @@ -1,56 +1,66 @@ { "CERT-C": { "DCL31-C": { - "properties": { - "obligation": "rule" - }, - "queries": [ - { - "description": "Omission of type specifiers may not be supported by some compilers.", - "kind": "problem", - "name": "Declare identifiers before using them", - "precision": "very-high", - "severity": "error", - "short_name": "DeclareIdentifiersBeforeUsingThem", - "shared_implementation_short_name": "TypeOmitted", - "tags": [ - "correctness", - "readability" - ], - "implementation_scope": { - "description": "This query does not check for implicitly typed parameters, typedefs or member declarations as this is partially compiler checked.", - "items": [] - } + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Omission of type specifiers may not be supported by some compilers.", + "kind": "problem", + "name": "Declare identifiers before using them", + "precision": "very-high", + "severity": "error", + "short_name": "DeclareIdentifiersBeforeUsingThem", + "shared_implementation_short_name": "TypeOmitted", + "tags": [ + "correctness", + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" + ], + "implementation_scope": { + "description": "This query does not check for implicitly typed parameters, typedefs or member declarations as this is partially compiler checked.", + "items": [] } - ], - "title": "Declare identifiers before using them" + } + ], + "title": "Declare identifiers before using them" + }, + "DCL37-C": { + "properties": { + "obligation": "rule" }, - "DCL37-C": { - "properties": { - "obligation": "rule" - }, - "queries": [ - { - "description": "Declaring a reserved identifier can lead to undefined behaviour.", - "kind": "problem", - "name": "Do not declare or define a reserved identifier", - "precision": "very-high", - "severity": "warning", - "short_name": "DoNotDeclareOrDefineAReservedIdentifier", - "shared_implementation_short_name": "DeclaredAReservedIdentifier", - "tags": [ - "correctness", - "maintainability", - "readability" - ], - "implementation_scope": { - "description": "This query does not consider identifiers described in the future library directions section of the standard. This query also checks for any reserved identifier as declared regardless of whether its header file is included or not.", - "items": [] - } + "queries": [ + { + "description": "Declaring a reserved identifier can lead to undefined behaviour.", + "kind": "problem", + "name": "Do not declare or define a reserved identifier", + "precision": "very-high", + "severity": "warning", + "short_name": "DoNotDeclareOrDefineAReservedIdentifier", + "shared_implementation_short_name": "DeclaredAReservedIdentifier", + "tags": [ + "correctness", + "maintainability", + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" + ], + "implementation_scope": { + "description": "This query does not consider identifiers described in the future library directions section of the standard. This query also checks for any reserved identifier as declared regardless of whether its header file is included or not.", + "items": [] } - ], - "title": "Do not declare or define a reserved identifier" - } + } + ], + "title": "Do not declare or define a reserved identifier" + } }, "MISRA-C-2012": { "RULE-21-2": { @@ -69,7 +79,8 @@ "tags": [ "correctness", "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -91,7 +102,8 @@ "tags": [ "correctness", "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This query considers the first 31 characters of identifiers as significant, as per C99 and reports the case when names are longer than 31 characters and differ in those characters past the 31 first only. This query does not consider universal or extended source characters.", @@ -102,41 +114,43 @@ "title": "External identifiers shall be distinct" }, "RULE-5-4": { - "properties": { - "obligation": "required" + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Declaring multiple macros with the same name leads to undefined behaviour.", + "kind": "problem", + "name": "Macro identifiers shall be distinct", + "precision": "very-high", + "severity": "warning", + "short_name": "MacroIdentifiersNotDistinct", + "tags": [ + "correctness", + "maintainability", + "readability", + "external/misra/c/2012/third-edition-first-revision" + ], + "implementation_scope": { + "description": "This query checks the first 63 characters of macro identifiers as significant, as per C99. Distinctness of parameters within the same function like macro are checked by compiler and therefore not checked by this rule.", + "items": [] + } }, - "queries": [ - { - "description": "Declaring multiple macros with the same name leads to undefined behaviour.", - "kind": "problem", - "name": "Macro identifiers shall be distinct", - "precision": "very-high", - "severity": "warning", - "short_name": "MacroIdentifiersNotDistinct", - "tags": [ - "correctness", - "maintainability", - "readability" - ], - "implementation_scope": { - "description": "This query checks the first 63 characters of macro identifiers as significant, as per C99. Distinctness of parameters within the same function like macro are checked by compiler and therefore not checked by this rule.", - "items": [] - } - }, - { - "description": "Macros with the same name as their parameters are less readable.", - "kind": "problem", - "name": "Macro identifiers shall be distinct from paramters", - "precision": "very-high", - "severity": "warning", - "short_name": "MacroIdentifierNotDistinctFromParameter", - "tags": [ - "maintainability", - "readability" - ] - } - ], - "title": "Macro identifiers shall be distinct" - } + { + "description": "Macros with the same name as their parameters are less readable.", + "kind": "problem", + "name": "Macro identifiers shall be distinct from paramters", + "precision": "very-high", + "severity": "warning", + "short_name": "MacroIdentifierNotDistinctFromParameter", + "tags": [ + "maintainability", + "readability", + "external/misra/c/2012/third-edition-first-revision" + ] + } + ], + "title": "Macro identifiers shall be distinct" + } } } \ No newline at end of file diff --git a/rule_packages/c/Declarations2.json b/rule_packages/c/Declarations2.json index 303965b6b6..c5b827e682 100644 --- a/rule_packages/c/Declarations2.json +++ b/rule_packages/c/Declarations2.json @@ -1,98 +1,123 @@ { "CERT-C": { "DCL38-C": { - "properties": { - "obligation": "rule" - }, - "queries": [ - { - "description": "Structures with flexible array members can be declared in ways that will lead to undefined behaviour.", - "kind": "problem", - "name": "Use the correct syntax when declaring a flexible array member", - "precision": "very-high", - "severity": "error", - "short_name": "DeclaringAFlexibleArrayMember", - "tags": [ - "correctness", - "maintainability", - "readability" - ] - } - ], - "title": "Use the correct syntax when declaring a flexible array member" + "properties": { + "obligation": "rule" }, + "queries": [ + { + "description": "Structures with flexible array members can be declared in ways that will lead to undefined behaviour.", + "kind": "problem", + "name": "Use the correct syntax when declaring a flexible array member", + "precision": "very-high", + "severity": "error", + "short_name": "DeclaringAFlexibleArrayMember", + "tags": [ + "correctness", + "maintainability", + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" + ] + } + ], + "title": "Use the correct syntax when declaring a flexible array member" + }, "DCL40-C": { "properties": { "obligation": "rule" }, "queries": [ { - "description": "Using nondistinct external identifiers results in undefined behaviour.", - "kind": "problem", - "name": "External identifiers shall be distinct", - "precision": "very-high", - "severity": "warning", - "short_name": "ExcessLengthNamesIdentifiersNotDistinct", - "shared_implementation_short_name": "NotDistinctIdentifier", - "tags": [ - "correctness", - "maintainability", - "readability" - ], - "implementation_scope": { - "description": "This query considers the first 31 characters of identifiers as significant, as per C99 and reports the case when names are longer than 31 characters and differ in those characters past the 31 first only. This query does not consider universal or extended source characters.", - "items": [] - } - }, - { - "description": "Declaring incompatible objects, in other words same named objects of different types, then accessing those objects can lead to undefined behaviour.", - "kind": "problem", - "name": "Do not create incompatible declarations of the same function or object", - "precision": "high", - "severity": "error", - "short_name": "IncompatibleObjectDeclarations", - "tags": [ - "correctness", - "maintainability", - "readability" - ] - }, - { - "description": "Declaring incompatible functions, in other words same named function of different return types or with different numbers of parameters or parameter types, then accessing those functions can lead to undefined behaviour.", - "kind": "problem", - "name": "Do not create incompatible declarations of the same function or object", - "precision": "high", - "severity": "error", - "short_name": "IncompatibleFunctionDeclarations", - "tags": [ - "correctness", - "maintainability", - "readability" - ] + "description": "Using nondistinct external identifiers results in undefined behaviour.", + "kind": "problem", + "name": "External identifiers shall be distinct", + "precision": "very-high", + "severity": "warning", + "short_name": "ExcessLengthNamesIdentifiersNotDistinct", + "shared_implementation_short_name": "NotDistinctIdentifier", + "tags": [ + "correctness", + "maintainability", + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" + ], + "implementation_scope": { + "description": "This query considers the first 31 characters of identifiers as significant, as per C99 and reports the case when names are longer than 31 characters and differ in those characters past the 31 first only. This query does not consider universal or extended source characters.", + "items": [] } + }, + { + "description": "Declaring incompatible objects, in other words same named objects of different types, then accessing those objects can lead to undefined behaviour.", + "kind": "problem", + "name": "Do not create incompatible declarations of the same function or object", + "precision": "high", + "severity": "error", + "short_name": "IncompatibleObjectDeclarations", + "tags": [ + "correctness", + "maintainability", + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" + ] + }, + { + "description": "Declaring incompatible functions, in other words same named function of different return types or with different numbers of parameters or parameter types, then accessing those functions can lead to undefined behaviour.", + "kind": "problem", + "name": "Do not create incompatible declarations of the same function or object", + "precision": "high", + "severity": "error", + "short_name": "IncompatibleFunctionDeclarations", + "tags": [ + "correctness", + "maintainability", + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" + ] + } ], "title": "Do not create incompatible declarations of the same function or object" }, "DCL41-C": { - "properties": { - "obligation": "rule" - }, - "queries": [ - { - "description": "Declaring a variable in a switch statement before the first case label can result in reading uninitialized memory which is undefined behaviour.", - "kind": "problem", - "name": "Do not declare variables inside a switch statement before the first case label", - "precision": "very-high", - "severity": "error", - "short_name": "VariablesInsideSwitchStatement", - "tags": [ - "correctness", - "maintainability", - "readability" - ] - } - ], - "title": "Do not declare variables inside a switch statement before the first case label" - } + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Declaring a variable in a switch statement before the first case label can result in reading uninitialized memory which is undefined behaviour.", + "kind": "problem", + "name": "Do not declare variables inside a switch statement before the first case label", + "precision": "very-high", + "severity": "error", + "short_name": "VariablesInsideSwitchStatement", + "tags": [ + "correctness", + "maintainability", + "readability", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" + ] + } + ], + "title": "Do not declare variables inside a switch statement before the first case label" + } } } \ No newline at end of file diff --git a/rule_packages/c/Declarations3.json b/rule_packages/c/Declarations3.json index a22567b237..8c2e0879ff 100644 --- a/rule_packages/c/Declarations3.json +++ b/rule_packages/c/Declarations3.json @@ -14,7 +14,8 @@ "shared_implementation_short_name": "IdentifierHidden", "tags": [ "readability", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This query does not consider C90 or C99 definitions of significant name and instead uses full name matches only.", @@ -38,7 +39,8 @@ "short_name": "IdentifiersNotDistinctFromMacroNames", "tags": [ "readability", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -58,7 +60,8 @@ "short_name": "TypedefNameNotUnique", "tags": [ "readability", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -78,7 +81,8 @@ "short_name": "TagNameNotUnique", "tags": [ "readability", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -99,7 +103,8 @@ "shared_implementation_short_name": "TypeOmitted", "tags": [ "correctness", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This query does not check for implicitly typed parameters, typedefs or member declarations as this is partially compiler checked.", diff --git a/rule_packages/c/Declarations4.json b/rule_packages/c/Declarations4.json index bfd0b18328..dedc6a73d4 100644 --- a/rule_packages/c/Declarations4.json +++ b/rule_packages/c/Declarations4.json @@ -12,8 +12,10 @@ "precision": "medium", "severity": "error", "short_name": "FunctionTypesNotInPrototypeForm", + "shared_implementation_short_name": "FunctionTypesNotInPrototypeFormShared", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This query does not check for implicitly typed parameters and checks function declarations and definitions but not function pointer types. This query cannot determine when the keyword void is used in place of no parameter.", @@ -36,7 +38,8 @@ "severity": "error", "short_name": "DeclarationsOfAnObjectSameNameAndType", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] }, { @@ -47,7 +50,8 @@ "severity": "error", "short_name": "DeclarationsOfAFunctionSameNameAndType", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -68,7 +72,8 @@ "tags": [ "readability", "maintainability", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This query does not check for the recommendation of declarations in headers.", @@ -85,7 +90,8 @@ "tags": [ "readability", "maintainability", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This query does not check for the recommendation of declarations in headers.", @@ -109,7 +115,8 @@ "short_name": "IdentifierWithExternalLinkageOneDefinition", "shared_implementation_short_name": "IdentifierWithExternalLinkageOneDefinitionShared", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/Declarations5.json b/rule_packages/c/Declarations5.json index 705f72791c..36591e575b 100644 --- a/rule_packages/c/Declarations5.json +++ b/rule_packages/c/Declarations5.json @@ -15,7 +15,8 @@ "tags": [ "correctness", "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This query considers the first 63 characters of identifiers as significant, as per C99 for nonexternal identifiers and reports the case when names are longer than 63 characters and differ in those characters past the 63 first only. This query does not consider universal or extended source characters.", @@ -38,7 +39,8 @@ "severity": "warning", "short_name": "ExternalObjectOrFunctionNotDeclaredInOneFile", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -58,7 +60,8 @@ "short_name": "MissingStaticSpecifierFunctionRedeclarationC", "shared_implementation_short_name": "MissingStaticSpecifierFunctionRedeclarationShared", "tags": [ - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] }, { @@ -68,8 +71,10 @@ "precision": "very-high", "severity": "warning", "short_name": "MissingStaticSpecifierObjectRedeclarationC", + "shared_implementation_short_name": "MissingStaticSpecifierObjectRedeclarationShared", "tags": [ - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -89,7 +94,8 @@ "short_name": "UnnecessaryExposedIdentifierDeclarationC", "shared_implementation_short_name": "UnnecessaryExposedIdentifierDeclarationShared", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/Declarations6.json b/rule_packages/c/Declarations6.json index 166d0c568b..198b4e8351 100644 --- a/rule_packages/c/Declarations6.json +++ b/rule_packages/c/Declarations6.json @@ -14,7 +14,8 @@ "short_name": "FunctionDeclaredImplicitly", "tags": [ "correctness", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -33,7 +34,8 @@ "severity": "error", "short_name": "FlexibleArrayMembersDeclared", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -53,7 +55,8 @@ "short_name": "IdentifiersWithExternalLinkageNotUnique", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -73,7 +76,8 @@ "short_name": "IdentifiersWithInternalLinkageNotUnique", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This rule does not explicitly check for the exception of inline functions in header files across multiple translation units as the CodeQL database already represents these as the same entity." @@ -95,7 +99,8 @@ "severity": "error", "short_name": "InlineFunctionNotDeclaredStaticStorage", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -115,7 +120,8 @@ "short_name": "ArrayExternalLinkageSizeExplicitlySpecified", "tags": [ "correctness", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -136,7 +142,8 @@ "tags": [ "correctness", "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/Declarations7.json b/rule_packages/c/Declarations7.json index cd3b3e6b18..86818cdcb5 100644 --- a/rule_packages/c/Declarations7.json +++ b/rule_packages/c/Declarations7.json @@ -14,7 +14,12 @@ "short_name": "InformationLeakageAcrossTrustBoundariesC", "shared_implementation_short_name": "InformationLeakageAcrossBoundaries", "tags": [ - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/high", + "external/cert/priority/p1", + "external/cert/level/l3" ], "implementation_scope": { "description": "The rule does not detect cases where fields may have uninitialized padding but are initialized via an initializer." @@ -39,7 +44,8 @@ "short_name": "VariableLengthArrayTypesUsed", "tags": [ "correctness", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -57,9 +63,11 @@ "precision": "very-high", "severity": "error", "short_name": "ValueImplicitEnumerationConstantNotUnique", + "shared_implementation_short_name": "NonUniqueEnumerationConstant", "tags": [ "correctness", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/Declarations8.json b/rule_packages/c/Declarations8.json index a70523b72f..6275e32595 100644 --- a/rule_packages/c/Declarations8.json +++ b/rule_packages/c/Declarations8.json @@ -14,7 +14,12 @@ "short_name": "AppropriateStorageDurationsStackAdressEscape", "shared_implementation_short_name": "DoNotCopyAddressOfAutoStorageObjectToOtherObject", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ], "implementation_scope": { "description": "The rule checks specifically for pointers to objects with automatic storage duration that are assigned to static storage duration variables." @@ -28,7 +33,12 @@ "severity": "error", "short_name": "AppropriateStorageDurationsFunctionReturn", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ], "implementation_scope": { "description": "The rule checks specifically for pointers to objects with automatic storage duration that are returned by functions or assigned to function output parameters." diff --git a/rule_packages/c/Declarations9.json b/rule_packages/c/Declarations9.json new file mode 100644 index 0000000000..ebfcf7c41f --- /dev/null +++ b/rule_packages/c/Declarations9.json @@ -0,0 +1,25 @@ +{ + "MISRA-C-2012": { + "RULE-11-10": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Conversions between types by using an _Atomic void type may result in undefined behavior.", + "kind": "problem", + "name": "The _Atomic qualifier shall not be applied to the incomplete type void", + "precision": "very-high", + "severity": "error", + "short_name": "AtomicQualifierAppliedToVoid", + "tags": [ + "correctness", + "external/misra/c/2012/third-edition-first-revision", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "The _Atomic qualifier shall not be applied to the incomplete type void" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/EssentialTypes.json b/rule_packages/c/EssentialTypes.json index 57c7ace1ba..a8ae26e8c6 100644 --- a/rule_packages/c/EssentialTypes.json +++ b/rule_packages/c/EssentialTypes.json @@ -13,7 +13,8 @@ "severity": "warning", "short_name": "OperandsOfAnInappropriateEssentialType", "tags": [ - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ] }, { @@ -24,7 +25,8 @@ "severity": "warning", "short_name": "PointerTypeOnLogicalOperator", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -44,7 +46,8 @@ "short_name": "AdditionSubtractionOnEssentiallyCharType", "tags": [ "maintainability", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -64,7 +67,8 @@ "short_name": "AssignmentOfIncompatibleEssentialType", "tags": [ "maintainability", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -84,7 +88,8 @@ "short_name": "OperandsWithMismatchedEssentialTypeCategory", "tags": [ "maintainability", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -104,7 +109,8 @@ "short_name": "InappropriateEssentialTypeCast", "tags": [ "maintainability", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -124,7 +130,8 @@ "short_name": "AssignmentToWiderEssentialType", "tags": [ "maintainability", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -144,7 +151,8 @@ "short_name": "ImplicitConversionOfCompositeExpression", "tags": [ "maintainability", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -164,7 +172,8 @@ "short_name": "InappropriateCastOfCompositeExpression", "tags": [ "maintainability", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -184,7 +193,8 @@ "short_name": "LoopOverEssentiallyFloatType", "tags": [ "maintainability", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -204,7 +214,8 @@ "short_name": "MemcmpUsedToCompareNullTerminatedStrings", "tags": [ "maintainability", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -224,7 +235,8 @@ "short_name": "MemcmpOnInappropriateEssentialTypeArgs", "tags": [ "maintainability", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/EssentialTypes2.json b/rule_packages/c/EssentialTypes2.json new file mode 100644 index 0000000000..5292eccdb8 --- /dev/null +++ b/rule_packages/c/EssentialTypes2.json @@ -0,0 +1,47 @@ +{ + "MISRA-C-2012": { + "RULE-21-22": { + "properties": { + "obligation": "mandatory" + }, + "queries": [ + { + "description": "All operand arguments to any type-generic macros in shall have an appropriate essential type.", + "kind": "problem", + "name": "All operand arguments to type-generic macros in shall have an appropriate essential type", + "precision": "high", + "severity": "error", + "short_name": "TgMathArgumentWithInvalidEssentialType", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + } + ], + "implementation_scope": { + "description": "The CodeQL database may not contain the necessary information to determine the essential type of literal macro arguments such as character literals." + }, + "title": "All operand arguments to any type-generic macros in shall have an appropriate essential type" + }, + "RULE-21-23": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "All operand arguments to any multi-argument type-generic macros in shall have the same standard type.", + "kind": "problem", + "name": "Operand arguments for an invocation of a type-generic macro shall have the same standard type", + "precision": "high", + "severity": "error", + "short_name": "TgMathArgumentsWithDifferingStandardType", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "All operand arguments to any multi-argument type-generic macros in shall have the same standard type" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/Expressions.json b/rule_packages/c/Expressions.json index 9d1f8b16a7..9be722b761 100644 --- a/rule_packages/c/Expressions.json +++ b/rule_packages/c/Expressions.json @@ -13,7 +13,12 @@ "severity": "error", "short_name": "DoNotCallFunctionPointerWithIncompatibleType", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "This query raises a result for a function assigned to a function pointer of an incompatible type even if the function pointer is never eventually called." @@ -27,7 +32,12 @@ "severity": "error", "short_name": "DoNotCallFunctionsWithIncompatibleArguments", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -39,7 +49,12 @@ "short_name": "CallPOSIXOpenWithCorrectArgumentCount", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "The analysis of invalid parameter count passed to POSIX open calls only applies when the value of the flags argument is computed locally." @@ -62,7 +77,12 @@ "short_name": "DoNotUseABitwiseOperatorWithABooleanLikeOperand", "tags": [ "maintainability", - "readability" + "readability", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/c/Expressions2.json b/rule_packages/c/Expressions2.json new file mode 100644 index 0000000000..d639ae2c34 --- /dev/null +++ b/rule_packages/c/Expressions2.json @@ -0,0 +1,28 @@ +{ + "CERT-C": { + "EXP16-C": { + "properties": { + "obligation": "recommendation" + }, + "queries": [ + { + "description": "Comparing function pointers to a constant value is not reliable and likely indicates a programmer error.", + "kind": "problem", + "name": "Do not compare function pointers to constant values", + "precision": "very-high", + "severity": "error", + "short_name": "DoNotCompareFunctionPointersToConstantValues", + "tags": [ + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" + ] + } + ], + "title": "Do not compare function pointers to constant values" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/FloatingTypes.json b/rule_packages/c/FloatingTypes.json index 1dfd663597..17690574e5 100644 --- a/rule_packages/c/FloatingTypes.json +++ b/rule_packages/c/FloatingTypes.json @@ -14,8 +14,16 @@ "short_name": "UncheckedRangeDomainPoleErrors", "shared_implementation_short_name": "UncheckedRangeDomainPoleErrors", "tags": [ - "correctness" - ] + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" + ], + "implementation_scope": { + "description": "This query identifies possible domain, pole and range errors on a selection of C standard library fuctions from math.h." + } } ], "title": "Prevent or detect domain and range errors in math functions" @@ -33,7 +41,12 @@ "severity": "error", "short_name": "UncheckedFloatingPointConversion", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], @@ -52,7 +65,12 @@ "severity": "error", "short_name": "IntToFloatPreservePrecision", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -71,7 +89,12 @@ "severity": "error", "short_name": "MemcmpUsedToCompareFloats", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/FloatingTypes2.json b/rule_packages/c/FloatingTypes2.json new file mode 100644 index 0000000000..a1c02daaf5 --- /dev/null +++ b/rule_packages/c/FloatingTypes2.json @@ -0,0 +1,38 @@ +{ + "MISRA-C-2012": { + "DIR-4-15": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Evaluation of floating-point expressions shall not lead to the undetected generation of infinities.", + "kind": "path-problem", + "name": "Evaluation of floating-point expressions shall not lead to the undetected generation of infinities", + "precision": "medium", + "severity": "warning", + "short_name": "PossibleMisuseOfUndetectedInfinity", + "shared_implementation_short_name": "MisuseOfInfiniteFloatingPointValue", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + }, + { + "description": "Evaluation of floating-point expressions shall not lead to the undetected generation of NaNs.", + "kind": "path-problem", + "name": "Evaluation of floating-point expressions shall not lead to the undetected generation of NaNs", + "precision": "low", + "severity": "warning", + "short_name": "PossibleMisuseOfUndetectedNaN", + "shared_implementation_short_name": "MisuseOfNaNFloatingPointValue", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "Evaluation of floating-point expressions shall not lead to the undetected generation of infinities and NaNs" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/FunctionTypes.json b/rule_packages/c/FunctionTypes.json new file mode 100644 index 0000000000..d9d8b6496d --- /dev/null +++ b/rule_packages/c/FunctionTypes.json @@ -0,0 +1,24 @@ +{ + "MISRA-C-2012": { + "RULE-17-12": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "A function identifier should only be called with a parenthesized parameter list or used with a & (address-of).", + "kind": "problem", + "name": "A function identifier should only be called with a parenthesized parameter list or used with a &", + "precision": "very-high", + "severity": "error", + "short_name": "FunctionAddressesShouldAddressOperator", + "tags": [ + "readability", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "A function identifier should only be called with a parenthesized parameter list or used with a & (address-of)" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/Generics.json b/rule_packages/c/Generics.json new file mode 100644 index 0000000000..02c7cb2364 --- /dev/null +++ b/rule_packages/c/Generics.json @@ -0,0 +1,191 @@ +{ + "MISRA-C-2012": { + "RULE-23-1": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "A generic selection should only be expanded from a macro.", + "kind": "problem", + "name": "A generic selection should only be expanded from a macro", + "precision": "very-high", + "severity": "warning", + "short_name": "GenericSelectionNotExpandedFromAMacro", + "tags": [ + "maintainability", + "external/misra/c/2012/amendment3" + ] + }, + { + "description": "A generic selection should depend on the type of a macro argument.", + "kind": "problem", + "name": "A generic selection should depend on the type of a macro argument", + "precision": "high", + "severity": "warning", + "short_name": "GenericSelectionDoesntDependOnMacroArgument", + "tags": [ + "correctness", + "maintainability", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "A generic selection should only be expanded from a macro" + }, + "RULE-23-2": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "A generic selection that is not expanded from a macro shall not contain potential side effects in the controlling expression.", + "kind": "problem", + "name": "A generic selection shall not contain side-effects if it is not expanded from a macro", + "precision": "high", + "severity": "warning", + "short_name": "GenericSelectionNotFromMacroWithSideEffects", + "tags": [ + "maintainability", + "external/misra/c/2012/amendment3" + ] + } + ], + "implementation_scope": { + "description": + "Due to limited information in the CodeQL database for macro argument expansions, this implementation reports generics not of the form `_Generic((X)` where all invocations of that generic contain a side effect in the controlling expression." + }, + "title": "A generic selection that is not expanded from a macro shall not contain potential side effects in the controlling expression" + }, + "RULE-23-3": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "A generic selection should contain at least one non-default association.", + "kind": "problem", + "name": "A generic selection should contain at least one non-default association", + "precision": "very-high", + "severity": "warning", + "short_name": "GenericWithoutNonDefaultAssociation", + "tags": [ + "correctness", + "maintainability", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "A generic selection should contain at least one non-default association" + }, + "RULE-23-4": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Generic selections undergo lvalue conversion before type comparison, leading to certain types being impossible to select.", + "kind": "problem", + "name": "A generic association shall list an appropriate type", + "precision": "very-high", + "severity": "error", + "short_name": "GenericAssociationWithUnselectableType", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "A generic association shall list an appropriate type" + }, + "RULE-23-5": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "Pointer types in a generic selection do not undergo pointer conversions and should not counterintuitively fall through to the default association.", + "kind": "problem", + "name": "A generic selection should not depend on implicit pointer type conversion", + "precision": "very-high", + "severity": "warning", + "short_name": "DangerousDefaultSelectionForPointerInGeneric", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "A generic selection should not depend on implicit pointer type conversion" + }, + "RULE-23-6": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "The controlling expression of a generic selection shall have an essential type that matches its standard type.", + "kind": "problem", + "name": "The controlling expression of a generic selection shall have an essential type that matches its standard type", + "precision": "high", + "severity": "error", + "short_name": "GenericExpressionWithIncorrectEssentialType", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + } + ], + "implementation_scope": { + "description": + "The CodeQL extractor will expand character literals passed into macros into integer literals, and therefore the essential type system for character literals will not necessarily be analyzed correctly." + }, + "title": "The controlling expression of a generic selection shall have an essential type that matches its standard type" + }, + "RULE-23-7": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "A generic selection that is expanded from a macro should evaluate its argument only once.", + "kind": "problem", + "name": "A generic selection that is expanded from a macro should evaluate its argument only once", + "precision": "medium", + "severity": "warning", + "short_name": "InvalidGenericMacroArgumentEvaluation", + "tags": [ + "correctness", + "maintainability", + "external/misra/c/2012/amendment3" + ] + } + ], + "implementation_scope": { + "description": + "Due to limited information in the CodeQL database for macro argument expansions, this implementation performs string matching on the macro parameters against the macro body to determine where parameters are expanded. If text indicating a nonevaluated context such as sizeof() or _Alignof() appear, there will be no positive result." + }, + "title": "A generic selection that is expanded from a macro should evaluate its argument only once" + }, + "RULE-23-8": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "A default association shall appear as either the first or the last association of a generic selection.", + "kind": "problem", + "name": "A default association shall appear as either the first or the last association of a generic", + "precision": "very-high", + "severity": "warning", + "short_name": "DefaultGenericSelectionNotFirstOrLast", + "tags": [ + "maintainability", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "A default association shall appear as either the first or the last association of a generic selection" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/IO1.json b/rule_packages/c/IO1.json index 1d90c6f28f..8a42c4e52a 100644 --- a/rule_packages/c/IO1.json +++ b/rule_packages/c/IO1.json @@ -15,7 +15,12 @@ "shared_implementation_short_name": "NonConstantFormat", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -35,7 +40,12 @@ "short_name": "DistinguishBetweenCharReadFromAFileAndEofOrWeof", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function. The query does not validate if the FILE status is handled correctly after being read." @@ -50,7 +60,12 @@ "short_name": "EndOfFileCheckPortability", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function. The query does not validate if the FILE status is handled correctly after being read." @@ -73,7 +88,12 @@ "short_name": "DoNotAlternatelyIOFromAStreamWithoutPositioning", "shared_implementation_short_name": "IOFstreamMissingPositioning", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function." @@ -97,7 +117,12 @@ "shared_implementation_short_name": "CloseFileHandleWhenNoLongerNeededShared", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function." @@ -120,7 +145,12 @@ "short_name": "UndefinedBehaviorAccessingAClosedFile", "shared_implementation_short_name": "DoNotAccessAClosedFile", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function." @@ -145,7 +175,8 @@ "short_name": "FileUsedAfterClosed", "shared_implementation_short_name": "DoNotAccessAClosedFile", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function." diff --git a/rule_packages/c/IO2.json b/rule_packages/c/IO2.json index 41c14a0d0e..69c12d7723 100644 --- a/rule_packages/c/IO2.json +++ b/rule_packages/c/IO2.json @@ -14,7 +14,12 @@ "short_name": "DoNotCopyAFileObject", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -34,7 +39,12 @@ "short_name": "ResetStringsOnFgetsOrFgetwsFailure", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -53,7 +63,12 @@ "severity": "error", "short_name": "DoNotCallGetcAndPutcWithSideEffects", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -72,7 +87,12 @@ "severity": "error", "short_name": "OnlyUseValuesForFsetposThatAreReturnedFromFgetpos", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/IO3.json b/rule_packages/c/IO3.json index 8d1c250eda..af6e9da732 100644 --- a/rule_packages/c/IO3.json +++ b/rule_packages/c/IO3.json @@ -14,7 +14,12 @@ "short_name": "DoNotPerformFileOperationsOnDevices", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "The rule checks that filenames are not tainted. It does not verify that appropriate OS-specific checks are in place to exclude that the opened file is a device." @@ -36,7 +41,12 @@ "severity": "error", "short_name": "SuccessfulFgetsOrFgetwsMayReturnAnEmptyString", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ], "implementation_scope": { "description": "The rule checks that access to a string returned by fgets() or fgetws() if protected by a guard condition. The rule is enforced in the context of a single function." @@ -60,7 +70,8 @@ "severity": "error", "short_name": "FileOpenForReadAndWriteOnDifferentStreams", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function." @@ -82,7 +93,8 @@ "severity": "error", "short_name": "AttemptToWriteToAReadOnlyStream", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -101,7 +113,8 @@ "severity": "error", "short_name": "PointerToAFileObjectDereferenced", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -120,7 +133,8 @@ "severity": "error", "short_name": "EofShallBeComparedWithUnmodifiedReturnValues", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/IO4.json b/rule_packages/c/IO4.json index 0873d2707b..8d9c150335 100644 --- a/rule_packages/c/IO4.json +++ b/rule_packages/c/IO4.json @@ -14,7 +14,12 @@ "short_name": "ToctouRaceConditionsWhileAccessingFiles", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ], "implementation_scope": { "description": "The query is limited to the specific class of TOCTOU race conditions that derives from the incorrectuse of `fopen` to check the existence of a file." @@ -37,7 +42,12 @@ "short_name": "UseValidSpecifiers", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ] }, { @@ -49,7 +59,12 @@ "short_name": "WrongNumberOfFormatArguments", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ] }, { @@ -61,11 +76,16 @@ "short_name": "WrongTypeFormatArguments", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], "title": "Use valid format strings" } } -} +} \ No newline at end of file diff --git a/rule_packages/c/IntegerOverflow.json b/rule_packages/c/IntegerOverflow.json index 5edc90eb21..f528d3d542 100644 --- a/rule_packages/c/IntegerOverflow.json +++ b/rule_packages/c/IntegerOverflow.json @@ -12,9 +12,15 @@ "precision": "medium", "severity": "error", "short_name": "UnsignedIntegerOperationsWrapAround", + "shared_implementation_short_name": "UnsignedOperationWithConstantOperandsWraps", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/high", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], @@ -33,7 +39,12 @@ "severity": "error", "short_name": "IntegerConversionCausesDataLoss", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -53,7 +64,12 @@ "short_name": "SignedIntegerOverflow", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/high", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], @@ -72,7 +88,12 @@ "severity": "error", "short_name": "DivOrRemByZero", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -91,7 +112,12 @@ "severity": "error", "short_name": "UseCorrectIntegerPrecisions", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -114,7 +140,8 @@ "shared_implementation_short_name": "ConstantUnsignedIntegerExpressionsWrapAround", "tags": [ "correctness", - "security" + "security", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/InvalidMemory1.json b/rule_packages/c/InvalidMemory1.json index 0d84c1c87e..3b0a6bb40c 100644 --- a/rule_packages/c/InvalidMemory1.json +++ b/rule_packages/c/InvalidMemory1.json @@ -15,7 +15,12 @@ "short_name": "DoNotReadUninitializedMemory", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ] } ], @@ -35,7 +40,12 @@ "shared_implementation_short_name": "DereferenceOfNullPointer", "short_name": "DoNotDereferenceNullPointers", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -55,7 +65,12 @@ "short_name": "DoNotAccessFreedMemory", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -78,7 +93,8 @@ "short_name": "ObjectWithAutoStorageDurationReadBeforeInit", "tags": [ "correctness", - "security" + "security", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/InvalidMemory2.json b/rule_packages/c/InvalidMemory2.json index cb7d380159..025a5d246c 100644 --- a/rule_packages/c/InvalidMemory2.json +++ b/rule_packages/c/InvalidMemory2.json @@ -14,7 +14,12 @@ "short_name": "VariableLengthArraySizeNotInValidRange", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -33,7 +38,12 @@ "severity": "error", "short_name": "DoNotUsePointerArithmeticOnNonArrayObjectPointers", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -52,7 +62,12 @@ "severity": "error", "short_name": "DoNotModifyObjectsWithTemporaryLifetime", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "This implementation also always reports non-modifying accesses of objects with temporary lifetime, which are only compliant in C11." diff --git a/rule_packages/c/InvalidMemory3.json b/rule_packages/c/InvalidMemory3.json new file mode 100644 index 0000000000..feeb8b2b47 --- /dev/null +++ b/rule_packages/c/InvalidMemory3.json @@ -0,0 +1,59 @@ +{ + "MISRA-C-2012": { + "RULE-18-10": { + "properties": { + "obligation": "mandatory" + }, + "queries": [ + { + "description": "Pointers to variably-modified array types shall not be used, as these pointer types are frequently incompatible with other fixed or variably sized arrays, resulting in undefined behavior.", + "kind": "problem", + "name": "Pointers to variably-modified array types shall not be used", + "precision": "high", + "severity": "error", + "short_name": "PointersToVariablyModifiedArrayTypesUsed", + "tags": [ + "external/misra/c/2012/amendment4", + "correctness", + "security" + ] + } + ], + "title": "Pointers to variably-modified array types shall not be used" + }, + "RULE-18-9": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Modifying or accessing elements of an array with temporary lifetime that has been converted to a pointer will result in undefined behavior.", + "kind": "problem", + "name": "An object with temporary lifetime shall not undergo array to pointer conversion", + "precision": "high", + "severity": "error", + "short_name": "ArrayToPointerConversionOfTemporaryObject", + "tags": [ + "external/misra/c/2012/amendment3", + "correctness", + "security" + ] + }, + { + "description": "Modifying elements of an array with temporary lifetime will result in undefined behavior.", + "kind": "problem", + "name": "Usage of the subscript operator on an object with temporary lifetime shall not return a modifiable value", + "precision": "high", + "severity": "error", + "short_name": "ModifiableLValueSubscriptedWithTemporaryLifetime", + "tags": [ + "external/misra/c/2012/amendment3", + "correctness", + "security" + ] + } + ], + "title": "An object with temporary lifetime shall not undergo array to pointer conversion" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/Language1.json b/rule_packages/c/Language1.json index 50aed45c55..6b20822196 100644 --- a/rule_packages/c/Language1.json +++ b/rule_packages/c/Language1.json @@ -14,7 +14,8 @@ "short_name": "LanguageNotEncapsulatedAndIsolated", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/Language2.json b/rule_packages/c/Language2.json index 66f219a025..43dbb4ecef 100644 --- a/rule_packages/c/Language2.json +++ b/rule_packages/c/Language2.json @@ -15,7 +15,8 @@ "shared_implementation_short_name": "UsageOfAssemblerNotDocumented", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -35,7 +36,8 @@ "short_name": "EmergentLanguageFeaturesUsed", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/amendment2" ] } ], diff --git a/rule_packages/c/Language3.json b/rule_packages/c/Language3.json index d48444a4ab..c19881e05c 100644 --- a/rule_packages/c/Language3.json +++ b/rule_packages/c/Language3.json @@ -14,7 +14,8 @@ "short_name": "LanguageExtensionsShouldNotBeUsed", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This implementation attempts to cover a broad section of the compiler specific extensions documented in: https://clang.llvm.org/docs/LanguageExtensions.html and https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html but is not comprehensive. The following topics are addressed in this query: Builtin macros, Variable Attributes, Function Attributes, Statement Expressions, Non-Local Gotos, Conditionals, Extended Integer / Numeric Types, Zero Length Structures, Zero Length Arrays, Variable Length Arrays, Case Attributes, Alignment, __sync and __fetch builtins. Other topics listed in the extension references are not covered by this query." @@ -37,7 +38,8 @@ "short_name": "OccurrenceOfUndefinedBehavior", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This implementation only considers alternate forms of `main` and the undefined behavior that results. Note that the current version of CodeQL is not able to detect this issue if a function is named `main` since it will assume the return type and formal parameters. Additional cases from Appendix J of the C99 standard are not currently considered." diff --git a/rule_packages/c/Language4.json b/rule_packages/c/Language4.json new file mode 100644 index 0000000000..fdc11924f4 --- /dev/null +++ b/rule_packages/c/Language4.json @@ -0,0 +1,144 @@ +{ + "MISRA-C-2012": { + "RULE-1-5": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Declaring a function with internal linkage without the static storage class specifier is an obselescent feature.", + "kind": "problem", + "name": "If a function has internal linkage then all re-declarations shall include the static storage class", + "precision": "very-high", + "severity": "warning", + "short_name": "MissingStaticSpecifierFuncRedeclarationObsolete", + "shared_implementation_short_name": "MissingStaticSpecifierFunctionRedeclarationShared", + "tags": [ + "readability", + "external/misra/c/2012/amendment3" + ] + }, + { + "description": "Declaring an identifier with internal linkage without the static storage class specifier is an obselescent feature.", + "kind": "problem", + "name": "If an object has internal linkage then all re-declarations shall include the static storage class", + "precision": "very-high", + "severity": "warning", + "short_name": "MissingStaticSpecifierObjectRedeclarationObsolete", + "shared_implementation_short_name": "MissingStaticSpecifierObjectRedeclarationShared", + "tags": [ + "readability", + "external/misra/c/2012/amendment3" + ] + }, + { + "description": "The use of non-prototype format parameter type declarators is an obsolescent language feature.", + "kind": "problem", + "name": "Function types shall be in prototype form with named parameters", + "precision": "medium", + "severity": "error", + "short_name": "FunctionTypesNotInPrototypeFormObsolete", + "shared_implementation_short_name": "FunctionTypesNotInPrototypeFormShared", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ], + "implementation_scope": { + "description": "This query does not check for implicitly typed parameters and checks function declarations and definitions but not function pointer types." + } + }, + { + "description": "The macro ATOMIC_VAR_INIT is has been declared an obsolescent language feature since C18.", + "kind": "problem", + "name": "Disallowed usage of obsolete macro ATOMIC_VAR_INIT compiled as C18", + "precision": "very-high", + "severity": "recommendation", + "short_name": "UseOfObsoleteMacroAtomicVarInit", + "tags": [ + "maintainability", + "readability", + "external/misra/c/2012/amendment3" + ] + }, + { + "description": "Directives that undefine and/or redefine the standard boolean macros has been declared an obsolescent language feature since C99.", + "kind": "problem", + "name": "Programs may not undefine or redefine the macros bool, true, or false", + "precision": "very-high", + "severity": "warning", + "short_name": "InvalidDefineOrUndefOfStdBoolMacro", + "tags": [ + "maintainability", + "readability", + "external/misra/c/2012/amendment3" + ] + }, + { + "description": "The function 'gets' is an obsolescent language feature which was removed in C11.", + "kind": "problem", + "name": "Disallowed usage of obsolescent function 'gets'", + "precision": "very-high", + "severity": "error", + "short_name": "CallToObsolescentFunctionGets", + "tags": [ + "external/misra/c/2012/amendment3", + "security", + "maintainability" + ] + }, + { + "description": "Calling the function 'ungetc' on a file stream with a position of zero is an obsolescent language feature.", + "kind": "path-problem", + "name": "Disallowed obsolescent usage of 'ungetc' on a file stream at position zero", + "precision": "high", + "severity": "error", + "short_name": "UngetcCallOnStreamPositionZero", + "tags": [ + "external/misra/c/2012/amendment3", + "security", + "maintainability" + ] + }, + { + "description": "Invoking realloc with a size argument set to zero is implementation-defined behavior and declared as an obsolete feature in C18.", + "kind": "problem", + "name": "Size argument value in realloc call may equal zero", + "precision": "medium", + "severity": "error", + "short_name": "SizeInReallocCallMayBeZero", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + }, + { + "description": "Invoking realloc with a size argument set to zero is implementation-defined behavior and declared as an obsolete feature in C18.", + "kind": "problem", + "name": "Size argument value in realloc call is equal zero", + "precision": "very-high", + "severity": "error", + "short_name": "SizeInReallocCallIsZero", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "Obsolencent language features shall not be used", + "implementation_scope": { + "description": "Not all items from Appendix F are covered by this rule. Some are not supportable and some are covered already by other rules.", + "items": [ + "Appendix F, item ID 1 is reported by both Rule 8.8 and by this implementation of Rule 1.5.", + "Appendix F, item ID 2 refers to compiler behavior which cannot be statically analyzed.", + "Appendix F, item ID 3, which states that storage-class specifiers may not be used except in the beginning of a declaration, is not supportable without additional changes to the CodeQL CLI.", + "Appendix F, item IDs 4 and 5 are reported by both Rule 8.2 and by this implementation of Rule 1.5.", + "Appendix F, item ID 6 is reported for all C versions, though the macro ATOMIC_VAR_INIT was not officially declared obsolescent until C18.", + "Appendix F, item ID 8 is reported by both Rule 21.6 and by this implementation of Rule 1.5.", + "Appendix F, item ID 9 is reported by this implementation of 1.5, though all uses of ungetc() are also reported by Rule 21.3.", + "Appendix F, item ID 10 is reported by this implementation of 1.5, though all uses of realloc() are also reported by Rule 21.3.", + "Appendix F, item ID 10 is reported for all C versions, as realloc() with a size argument of zero was implementation-defined behavior in C99 and C11." + ] + } + } + } +} \ No newline at end of file diff --git a/rule_packages/c/Memory1.json b/rule_packages/c/Memory1.json index 7232b18751..8515fe15e1 100644 --- a/rule_packages/c/Memory1.json +++ b/rule_packages/c/Memory1.json @@ -14,8 +14,9 @@ "short_name": "InitializerForAggregateOrUnionNotEnclosedInBraces", "shared_implementation_short_name": "UseInitializerBracesToMatchAggregateTypeStructure", "tags": [ - "maintainability", - "readability" + "maintainability", + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -35,7 +36,8 @@ "short_name": "PartiallyInitializedArrayWithExplicitInitializers", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -56,7 +58,8 @@ "tags": [ "correctness", "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/Memory2.json b/rule_packages/c/Memory2.json index 677711938a..55a7dd2a35 100644 --- a/rule_packages/c/Memory2.json +++ b/rule_packages/c/Memory2.json @@ -14,7 +14,12 @@ "short_name": "DoNotSubtractPointersThatDoNotReferToTheSameArray", "shared_implementation_short_name": "DoNotSubtractPointersAddressingDifferentArrays", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] }, { @@ -26,7 +31,12 @@ "short_name": "DoNotRelatePointersThatDoNotReferToTheSameArray", "shared_implementation_short_name": "DoNotUseRelationalOperatorsWithDifferingArrays", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -46,7 +56,12 @@ "short_name": "DoNotComparePaddingData", "shared_implementation_short_name": "MemcmpUsedToComparePaddingData", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -67,7 +82,12 @@ "shared_implementation_short_name": "FreeMemoryWhenNoLongerNeededShared", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function." @@ -89,7 +109,12 @@ "severity": "error", "short_name": "AllocStructsWithAFlexibleArrayMemberDynamically", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -100,7 +125,12 @@ "severity": "error", "short_name": "CopyStructsWithAFlexibleArrayMemberDynamically", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], @@ -121,7 +151,12 @@ "shared_implementation_short_name": "OnlyFreeMemoryAllocatedDynamicallyShared", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -141,7 +176,12 @@ "short_name": "DoNotModifyAlignmentOfMemoryWithRealloc", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -164,7 +204,8 @@ "shared_implementation_short_name": "FreeMemoryWhenNoLongerNeededShared", "tags": [ "correctness", - "security" + "security", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function." @@ -180,7 +221,8 @@ "shared_implementation_short_name": "CloseFileHandleWhenNoLongerNeededShared", "tags": [ "correctness", - "security" + "security", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function." @@ -204,7 +246,8 @@ "shared_implementation_short_name": "OnlyFreeMemoryAllocatedDynamicallyShared", "tags": [ "correctness", - "security" + "security", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/Memory3.json b/rule_packages/c/Memory3.json index 6eafcc6509..e1ed7382e0 100644 --- a/rule_packages/c/Memory3.json +++ b/rule_packages/c/Memory3.json @@ -14,7 +14,12 @@ "short_name": "InsufficientMemoryAllocatedForObject", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/c/Misc.json b/rule_packages/c/Misc.json index 323ec17350..183c05988b 100644 --- a/rule_packages/c/Misc.json +++ b/rule_packages/c/Misc.json @@ -12,9 +12,14 @@ "precision": "very-high", "severity": "error", "short_name": "RandUsedForGeneratingPseudorandomNumbers", - "shared_implementation_short_name" : "DoNotUseRandForGeneratingPseudorandomNumbers", + "shared_implementation_short_name": "DoNotUseRandForGeneratingPseudorandomNumbers", "tags": [ - "security" + "security", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -33,7 +38,12 @@ "severity": "error", "short_name": "ProperlySeedPseudorandomNumberGenerators", "tags": [ - "security" + "security", + "external/cert/severity/medium", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p18", + "external/cert/level/l1" ], "implementation_scope": { "description": "This rule will be checked by looking for calls to random that are no preceded by a call to srandom(). We perform a simple check for the argument to srandom() and verify it is not a literal (or a value easily deduced to be a literal)." @@ -56,7 +66,12 @@ "short_name": "ControlFlowReachesTheEndOfANonVoidFunction", "shared_implementation_short_name": "NonVoidFunctionDoesNotReturn", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/c/NoReturn.json b/rule_packages/c/NoReturn.json new file mode 100644 index 0000000000..f485060095 --- /dev/null +++ b/rule_packages/c/NoReturn.json @@ -0,0 +1,65 @@ +{ + "MISRA-C-2012": { + "RULE-17-10": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Function declared with _noreturn will by definition not return a value, and should be declared to return void.", + "kind": "problem", + "name": "A function declared with _noreturn shall have a return type of void", + "precision": "very-high", + "severity": "recommendation", + "short_name": "NonVoidReturnTypeOfNoreturnFunction", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "A function declared with _noreturn shall have a return type of void" + }, + "RULE-17-11": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "Functions which cannot return should be declared with _Noreturn.", + "kind": "problem", + "name": "A function without a branch that returns shall be declared with _Noreturn", + "precision": "very-high", + "severity": "recommendation", + "short_name": "FunctionWithNoReturningBranchShouldBeNoreturn", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "A function without a branch that returns shall be declared with _Noreturn" + }, + "RULE-17-9": { + "properties": { + "obligation": "mandatory" + }, + "queries": [ + { + "description": "Returning inside a function declared with _Noreturn is undefined behavior.", + "kind": "problem", + "name": "Verify that a function declared with _Noreturn does not return", + "precision": "very-high", + "severity": "error", + "short_name": "ReturnStatementInNoreturnFunction", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ], + "shared_implementation_short_name": "FunctionNoReturnAttributeCondition" + } + ], + "title": "Verify that a function declared with _Noreturn does not return" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/OutOfBounds.json b/rule_packages/c/OutOfBounds.json index 31d0349a63..3354348230 100644 --- a/rule_packages/c/OutOfBounds.json +++ b/rule_packages/c/OutOfBounds.json @@ -14,7 +14,12 @@ "short_name": "DoNotFormOutOfBoundsPointersOrArraySubscripts", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/high", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], @@ -34,7 +39,12 @@ "short_name": "LibraryFunctionArgumentOutOfBounds", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -56,7 +66,8 @@ "short_name": "StringFunctionPointerArgumentOutOfBounds", "tags": [ "correctness", - "security" + "security", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -76,7 +87,8 @@ "short_name": "StringLibrarySizeArgumentOutOfBounds", "tags": [ "correctness", - "security" + "security", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/Pointers1.json b/rule_packages/c/Pointers1.json index 6b2df1595c..1b54fc1fb6 100644 --- a/rule_packages/c/Pointers1.json +++ b/rule_packages/c/Pointers1.json @@ -13,7 +13,8 @@ "severity": "error", "short_name": "ConversionBetweenFunctionPointerAndOtherType", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -32,7 +33,8 @@ "severity": "error", "short_name": "ConversionBetweenIncompleteTypePointerAndOtherType", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -51,7 +53,8 @@ "severity": "error", "short_name": "CastBetweenObjectPointerAndDifferentObjectType", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -70,7 +73,8 @@ "severity": "error", "short_name": "ConversionBetweenPointerToObjectAndIntegerType", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -89,7 +93,8 @@ "severity": "error", "short_name": "ConversionFromPointerToVoidIntoPointerToObject", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -108,7 +113,8 @@ "severity": "error", "short_name": "CastBetweenPointerToVoidAndArithmeticType", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -127,7 +133,8 @@ "severity": "error", "short_name": "CastBetweenPointerToObjectAndNonIntArithmeticType", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -146,7 +153,8 @@ "severity": "error", "short_name": "CastRemovesConstOrVolatileQualification", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -165,7 +173,8 @@ "severity": "error", "short_name": "MacroNullNotUsedAsIntegerNullPointerConstant", "tags": [ - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This rule allows two forms of null-pointer constants: a Zero literal created by the NULL macro or a Zero literal cast to a void pointer." @@ -188,7 +197,8 @@ "short_name": "PointerAndDerivedPointerMustAddressSameArray", "shared_implementation_short_name": "DoNotUsePointerArithmeticToAddressDifferentArrays", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -208,7 +218,8 @@ "short_name": "SubtractionBetweenPointersMustAddressSameArray", "shared_implementation_short_name": "DoNotSubtractPointersAddressingDifferentArrays", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -228,11 +239,12 @@ "short_name": "RelationalOperatorComparesPointerToDifferentArray", "shared_implementation_short_name": "DoNotUseRelationalOperatorsWithDifferingArrays", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], - "title": "The relational operators >, >=, < and <= shall not be applied to objects of pointer type except where they point into the same object" + "title": "The relational operators >, >=, < and <= shall not be applied to expressions of pointer type except where they point into the same object" }, "RULE-18-4": { "properties": { @@ -248,7 +260,8 @@ "short_name": "DoNotUseAdditionOrSubtractionOperatorsOnPointers", "shared_implementation_short_name": "UseOnlyArrayIndexingForPointerArithmetic", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -268,7 +281,8 @@ "short_name": "NoMoreThanTwoLevelsOfPointerNestingInDeclarations", "shared_implementation_short_name": "DoNotUseMoreThanTwoLevelsOfPointerIndirection", "tags": [ - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -288,7 +302,20 @@ "short_name": "AutomaticStorageObjectAddressCopiedToOtherObject", "shared_implementation_short_name": "DoNotCopyAddressOfAutoStorageObjectToOtherObject", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" + ] + }, + { + "description": "Storing the address of a thread-local object in a global object will result in undefined behavior if the address is accessed after the relevant thread is terminated.", + "kind": "problem", + "name": "The address of an object with thread-local storage shall not be copied to a global object", + "precision": "very-high", + "severity": "error", + "short_name": "ThreadLocalObjectAddressCopiedToGlobalObject", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" ] } ], @@ -308,7 +335,8 @@ "short_name": "ObjectWithNoPointerDereferenceShouldBeOpaque", "tags": [ "readability", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This rule considers all cases where a structure or union is referenced as a pointer but has no FieldAccess within a translation unit. Further excluded from this rule are translation units in which the structure or union is declared as a non-pointer variable." @@ -332,7 +360,8 @@ "tags": [ "correctness", "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "To exclude compliant exceptions, this rule only excludes direct assignments of pointers to non-const-qualified types in the context of a single function and does not cover memory-copying functions. This rule also excludes pointers passed to other functions without conversion." diff --git a/rule_packages/c/Pointers2.json b/rule_packages/c/Pointers2.json index da275001c4..fcfd9356e6 100644 --- a/rule_packages/c/Pointers2.json +++ b/rule_packages/c/Pointers2.json @@ -12,8 +12,13 @@ "precision": "high", "severity": "error", "short_name": "DoNotAddOrSubtractAScaledIntegerToAPointer", - "tags":[ - "correctness" + "tags": [ + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/c/Pointers3.json b/rule_packages/c/Pointers3.json index a694300cd5..8a169b71a8 100644 --- a/rule_packages/c/Pointers3.json +++ b/rule_packages/c/Pointers3.json @@ -13,7 +13,12 @@ "severity": "error", "short_name": "DoNotAccessVolatileObjectWithNonVolatileReference", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ], "implementation_scope": { "description": "In limited cases, this query can raise false-positives for assignment of volatile objects and subsequent accesses of those objects via non-volatile pointers." @@ -35,7 +40,12 @@ "severity": "error", "short_name": "DoNotCastPointerToMoreStrictlyAlignedPointerType", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -54,7 +64,12 @@ "severity": "error", "short_name": "DoNotAccessVariableViaPointerOfIncompatibleType", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/high", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -72,8 +87,14 @@ "precision": "medium", "severity": "error", "short_name": "DoNotPassAliasedPointerToRestrictQualifiedParam", + "shared_implementation_short_name": "DoNotPassAliasedPointerToRestrictQualifiedParamShared", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -84,7 +105,12 @@ "severity": "error", "short_name": "RestrictPointerReferencesOverlappingObject", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/Preprocessor1.json b/rule_packages/c/Preprocessor1.json index b93bc72731..cf4f023023 100644 --- a/rule_packages/c/Preprocessor1.json +++ b/rule_packages/c/Preprocessor1.json @@ -14,7 +14,8 @@ "short_name": "IncludeDirectivesPrecededByDirectivesOrComments", "shared_implementation_short_name": "PreprocessorIncludesPreceded", "tags": [ - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -34,10 +35,10 @@ "short_name": "PreprocessorHashOperatorsShouldNotBeUsed", "shared_implementation_short_name": "HashOperatorsUsed", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } - ], "title": "The # and ## preprocessor operators should not be used" }, @@ -55,7 +56,8 @@ "short_name": "ForbiddenCharactersInHeaderFileName", "shared_implementation_short_name": "PreprocessorIncludesForbiddenHeaderNames", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This query identifies the use of the ', \\, /*, // characters in header file names. The query is not able to detect the use of the \" character in header file names.", @@ -79,8 +81,9 @@ "short_name": "IdentifiersUsedInPreprocessorExpression", "shared_implementation_short_name": "UndefinedMacroIdentifiers", "tags": [ - "correctness", - "readability" + "correctness", + "readability", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This query does not detect the case where an undefined character is used but not actually evaluated, for example, as a result of the inclusion of a logical AND operator in the #if expression.", diff --git a/rule_packages/c/Preprocessor2.json b/rule_packages/c/Preprocessor2.json index 9eeb7beba8..62bb0b770a 100644 --- a/rule_packages/c/Preprocessor2.json +++ b/rule_packages/c/Preprocessor2.json @@ -12,8 +12,10 @@ "precision": "very-high", "severity": "warning", "short_name": "MoreThanOneHashOperatorInMacroDefinition", + "shared_implementation_short_name": "MacroParameterFollowingHash", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This query applies to function like macros and not object like macros. This rule strictly disallows the use of # operator followed by a ## and other combinations are permitted.", @@ -35,9 +37,11 @@ "precision": "high", "severity": "warning", "short_name": "MacroParameterUsedAsHashOperand", + "shared_implementation_short_name": "AMixedUseMacroArgumentSubjectToExpansion", "tags": [ - "maintainability", - "readability" + "maintainability", + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -56,8 +60,9 @@ "severity": "warning", "short_name": "UndefShouldNotBeUsed", "tags": [ - "maintainability", - "readability" + "maintainability", + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -79,7 +84,8 @@ "tags": [ "correctness", "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This query defines header file as any file that is included regardless of file extension. This query does not consider the use of `#pragma once` as a permitted header guard.", diff --git a/rule_packages/c/Preprocessor3.json b/rule_packages/c/Preprocessor3.json index 0b0c735a04..79e2aec59c 100644 --- a/rule_packages/c/Preprocessor3.json +++ b/rule_packages/c/Preprocessor3.json @@ -1,24 +1,25 @@ { "MISRA-C-2012": { "RULE-20-8": { - "properties": { - "obligation": "required" - }, - "queries": [ - { - "description": "A controlling expression of a #if or #elif preprocessing directive that does not evaluate to 0 or 1 makes code more difficult to understand.", - "kind": "problem", - "name": "The controlling expression of a #if or #elif preprocessing directive shall evaluate to 0 or 1", - "precision": "high", - "severity": "warning", - "short_name": "ControllingExpressionIfDirective", - "tags": [ - "maintainability", - "readability" - ] - } - ], - "title": "The controlling expression of a #if or #elif preprocessing directive shall evaluate to 0 or 1" - } + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "A controlling expression of a #if or #elif preprocessing directive that does not evaluate to 0 or 1 makes code more difficult to understand.", + "kind": "problem", + "name": "The controlling expression of a #if or #elif preprocessing directive shall evaluate to 0 or 1", + "precision": "high", + "severity": "warning", + "short_name": "ControllingExpressionIfDirective", + "tags": [ + "maintainability", + "readability", + "external/misra/c/2012/third-edition-first-revision" + ] + } + ], + "title": "The controlling expression of a #if or #elif preprocessing directive shall evaluate to 0 or 1" + } } } \ No newline at end of file diff --git a/rule_packages/c/Preprocessor4.json b/rule_packages/c/Preprocessor4.json index 404909c479..608a23d974 100644 --- a/rule_packages/c/Preprocessor4.json +++ b/rule_packages/c/Preprocessor4.json @@ -15,7 +15,8 @@ "tags": [ "correctness", "readability", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -36,7 +37,8 @@ "shared_implementation_short_name": "PreprocessingDirectiveWithinMacroArgument", "tags": [ "readability", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -57,7 +59,8 @@ "tags": [ "correctness", "readability", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/Preprocessor5.json b/rule_packages/c/Preprocessor5.json index 29c0156410..60a1752e73 100644 --- a/rule_packages/c/Preprocessor5.json +++ b/rule_packages/c/Preprocessor5.json @@ -14,7 +14,12 @@ "short_name": "DoNotTreatAPredefinedIdentifierAsObject", "tags": [ "correctness", - "readability" + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ], "implementation_scope": { "description": "This query reports locations corresponding to both redefinitions of those standard library macros as well as locations where the identifiers used for accesses.", @@ -38,7 +43,12 @@ "short_name": "MacroOrFunctionArgsContainHashToken", "tags": [ "correctness", - "readability" + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ], "implementation_scope": { "description": "This query defines end of function call as the next node in the control flow graph.", @@ -65,7 +75,8 @@ "shared_implementation_short_name": "MacroParameterNotEnclosedInParentheses", "tags": [ "correctness", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This query checks for every instance of a parameter to be enclosed in parentheses regardless of whether the expansion of that parameter forms an expression or not.", diff --git a/rule_packages/c/Preprocessor6.json b/rule_packages/c/Preprocessor6.json index be0ae84851..6d71b8697b 100644 --- a/rule_packages/c/Preprocessor6.json +++ b/rule_packages/c/Preprocessor6.json @@ -12,10 +12,12 @@ "precision": "medium", "severity": "recommendation", "short_name": "FunctionOverFunctionLikeMacro", + "shared_implementation_short_name": "FunctionLikeMacrosDefined", "tags": [ "external/misra/audit", "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/SideEffects1.json b/rule_packages/c/SideEffects1.json index e66f4c3136..4dec3d8bbf 100644 --- a/rule_packages/c/SideEffects1.json +++ b/rule_packages/c/SideEffects1.json @@ -13,7 +13,12 @@ "severity": "warning", "short_name": "DependenceOnOrderOfScalarEvaluationForSideEffects", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] }, { @@ -24,7 +29,12 @@ "severity": "warning", "short_name": "DependenceOnOrderOfFunctionArgumentsForSideEffects", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -43,7 +53,12 @@ "severity": "error", "short_name": "UnevaluatedOperandWithSideEffect", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], @@ -62,7 +77,12 @@ "severity": "error", "short_name": "AssignmentsInSelectionStatements", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -83,7 +103,8 @@ "severity": "warning", "short_name": "UnenclosedSizeofOperand", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] }, { @@ -94,7 +115,8 @@ "severity": "warning", "short_name": "ImplicitPrecedenceOfOperatorsInExpression", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -113,7 +135,8 @@ "severity": "error", "short_name": "InitializerListsContainPersistentSideEffects", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -131,9 +154,11 @@ "precision": "very-high", "severity": "error", "short_name": "ResultOfAnAssignmentOperatorShouldNotBeUsed", + "shared_implementation_short_name": "ResultOfAnAssignmentOperatorShouldNotBeUsed", "tags": [ "correctness", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -152,7 +177,8 @@ "severity": "error", "short_name": "PossibleSuppressedSideEffectInLogicOperatorOperand", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -160,7 +186,7 @@ }, "RULE-13-6": { "properties": { - "obligation": "mandatory" + "obligation": "required" }, "queries": [ { @@ -171,7 +197,8 @@ "severity": "error", "short_name": "SizeofOperandWithSideEffect", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/SideEffects2.json b/rule_packages/c/SideEffects2.json index 42467c2852..b7e1baa901 100644 --- a/rule_packages/c/SideEffects2.json +++ b/rule_packages/c/SideEffects2.json @@ -14,7 +14,8 @@ "short_name": "SideEffectAndCrementInFullExpression", "tags": [ "readability", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -33,7 +34,8 @@ "severity": "warning", "short_name": "ModificationOfFunctionParameter", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/SideEffects3.json b/rule_packages/c/SideEffects3.json index 2d67df6e2e..1ff29ec166 100644 --- a/rule_packages/c/SideEffects3.json +++ b/rule_packages/c/SideEffects3.json @@ -13,7 +13,20 @@ "severity": "error", "short_name": "UnsequencedSideEffects", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" + ] + }, + { + "description": "The value of an atomic variable shall not depend on evaluation order and interleaving of threads.", + "kind": "problem", + "name": "The value of an atomic variable shall not depend on the evaluation order of interleaved threads", + "precision": "very-high", + "severity": "error", + "short_name": "UnsequencedAtomicReads", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" ] } ], diff --git a/rule_packages/c/SideEffects4.json b/rule_packages/c/SideEffects4.json index 77121019de..5b0c6da3f5 100644 --- a/rule_packages/c/SideEffects4.json +++ b/rule_packages/c/SideEffects4.json @@ -13,7 +13,12 @@ "severity": "error", "short_name": "SideEffectsInArgumentsToUnsafeMacros", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ], "implementation_scope": { "description": "This implementation only considers ++ and function call side effects. Due to the textual nature of macro expansion it is not always possible to determine accurately whether a side-effect was produced by a particular argument, and this may cause both false positives and false negatives. The query does not consider the case where a macro argument including a side-effect is never evaluated." diff --git a/rule_packages/c/SignalHandlers.json b/rule_packages/c/SignalHandlers.json index 0ceaa5914d..ae9045a64d 100644 --- a/rule_packages/c/SignalHandlers.json +++ b/rule_packages/c/SignalHandlers.json @@ -14,7 +14,12 @@ "short_name": "CallOnlyAsyncSafeFunctionsWithinSignalHandlers", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -34,7 +39,12 @@ "short_name": "DoNotAccessSharedObjectsInSignalHandlers", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/high", + "external/cert/priority/p9", + "external/cert/level/l2" ], "implementation_scope": { "description": "The implementation does not verify the correct usage of `atomic_is_lock_free`." @@ -57,7 +67,12 @@ "short_name": "DoNotCallSignalFromInterruptibleSignalHandlers", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], @@ -77,7 +92,12 @@ "short_name": "DoNotReturnFromAComputationalExceptionHandler", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/high", + "external/cert/priority/p1", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/StandardLibraryFunctionTypes.json b/rule_packages/c/StandardLibraryFunctionTypes.json index 274eadbced..ee0d7f5af1 100644 --- a/rule_packages/c/StandardLibraryFunctionTypes.json +++ b/rule_packages/c/StandardLibraryFunctionTypes.json @@ -12,7 +12,9 @@ "precision": "very-high", "severity": "error", "short_name": "CtypeFunctionArgNotUnsignedCharOrEof", - "tags": [] + "tags": [ + "external/misra/c/2012/third-edition-first-revision" + ] } ], "title": "Any value passed to a function in shall be representable as an unsigned char or be the value EOF" @@ -29,7 +31,9 @@ "precision": "very-high", "severity": "error", "short_name": "MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes", - "tags": [] + "tags": [ + "external/misra/c/2012/third-edition-first-revision" + ] } ], "title": "The pointer arguments to the Standard Library functions memcpy, memmove and memcmp shall be pointers to qualified or unqualified versions of compatible types" diff --git a/rule_packages/c/Statements1.json b/rule_packages/c/Statements1.json index a8dc1b55ea..c932a8642d 100644 --- a/rule_packages/c/Statements1.json +++ b/rule_packages/c/Statements1.json @@ -15,7 +15,8 @@ "shared_implementation_short_name": "NestedLabelInSwitch", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -35,7 +36,8 @@ "short_name": "BreakShallTerminateSwitchClause", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -55,7 +57,8 @@ "short_name": "EverySwitchShallHaveDefaultLabel", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -73,7 +76,9 @@ "precision": "very-high", "severity": "recommendation", "short_name": "DefaultNotFirstOrLastOfSwitch", - "tags": [] + "tags": [ + "external/misra/c/2012/third-edition-first-revision" + ] } ], "title": "A default label shall appear as either the first or the last switch label of a switch statement" diff --git a/rule_packages/c/Statements2.json b/rule_packages/c/Statements2.json index 8aa44c5091..9cd71b69c9 100644 --- a/rule_packages/c/Statements2.json +++ b/rule_packages/c/Statements2.json @@ -15,7 +15,8 @@ "shared_implementation_short_name": "GotoStatementCondition", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -33,9 +34,11 @@ "precision": "high", "severity": "recommendation", "short_name": "GotoLabelBlockCondition", + "shared_implementation_short_name": "GotoReferenceALabelInSurroundingBlock", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -55,7 +58,8 @@ "short_name": "LoopIterationCondition", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -75,7 +79,8 @@ "short_name": "SwitchClauseNumberCondition", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -95,11 +100,12 @@ "short_name": "SwitchExpressionBoolCondition", "tags": [ "readability", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ] } ], "title": "A switch-expression shall not have essentially Boolean type" } } -} +} \ No newline at end of file diff --git a/rule_packages/c/Statements3.json b/rule_packages/c/Statements3.json index 41463415a6..94206d485f 100644 --- a/rule_packages/c/Statements3.json +++ b/rule_packages/c/Statements3.json @@ -14,31 +14,34 @@ "short_name": "SwitchCompoundCondition", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] }, { "description": "if the body of a loop is not enclosed in braces, then this can lead to incorrect execution, and is hard for developers to maintain.", "kind": "problem", - "name": "the statement forming the body of a loop shall be a compound statement", + "name": "The statement forming the body of a loop shall be a compound statement", "precision": "very-high", "severity": "recommendation", "short_name": "LoopCompoundCondition", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] }, { "description": "if the body of a selection statement is not enclosed in braces, then this can lead to incorrect execution, and is hard for developers to maintain.", "kind": "problem", - "name": "the statement forming the body of a loop shall be a compound statement", + "name": "The statement forming the body of a slection statement shall be a compound statement", "precision": "very-high", "severity": "recommendation", "short_name": "SelectionCompoundCondition", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -59,7 +62,8 @@ "short_name": "IfElseEndCondition", "tags": [ "readability", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -80,7 +84,8 @@ "short_name": "SwitchCaseStartCondition", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] }, { @@ -93,7 +98,8 @@ "short_name": "SwitchStmtNotWellFormed", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -113,7 +119,8 @@ "short_name": "RecursiveFunctionCondition", "tags": [ "maintainability", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/Statements4.json b/rule_packages/c/Statements4.json index 56e13c9de6..e770fe032a 100644 --- a/rule_packages/c/Statements4.json +++ b/rule_packages/c/Statements4.json @@ -15,7 +15,12 @@ "tags": [ "maintainability", "readability", - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/low", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -37,7 +42,8 @@ "short_name": "ForLoopNotWellFormed", "tags": [ "readability", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -57,7 +63,8 @@ "short_name": "NonBooleanIfCondition", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] }, { @@ -69,7 +76,8 @@ "short_name": "NonBooleanIterationCondition", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/Statements5.json b/rule_packages/c/Statements5.json index 93a533939b..03380f4897 100644 --- a/rule_packages/c/Statements5.json +++ b/rule_packages/c/Statements5.json @@ -15,10 +15,14 @@ "tags": [ "correctness", "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], + "implementation_scope": { + "description": "Not all invariant logical expressions which contain dynamic values are detected to be invariant, for instance, `x < 3 && x > 5` where x does not have a statically known value." + }, "title": "Controlling expressions shall not be invariant" }, "RULE-15-5": { @@ -36,7 +40,8 @@ "tags": [ "maintainability", "readability", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -58,11 +63,12 @@ "tags": [ "correctness", "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], "title": "All exit paths from a function with non-void return type shall have an explicit return statement with an expression" } } -} +} \ No newline at end of file diff --git a/rule_packages/c/Statements6.json b/rule_packages/c/Statements6.json index 101987f9c3..c8ab3efe38 100644 --- a/rule_packages/c/Statements6.json +++ b/rule_packages/c/Statements6.json @@ -12,9 +12,11 @@ "precision": "very-high", "severity": "error", "short_name": "GotoStatementUsed", + "shared_implementation_short_name": "GotoStatementShouldNotBeUsed", "tags": [ "correctness", - "security" + "security", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/Static.json b/rule_packages/c/Static.json index 7edf903703..2af2af402a 100644 --- a/rule_packages/c/Static.json +++ b/rule_packages/c/Static.json @@ -13,7 +13,8 @@ "severity": "error", "short_name": "UseOfArrayStatic", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "The static keyword is associated with particular array types in our model. This means we can get false positives when two parameter use the same array type and size, but only one of which uses the `static` keyword." diff --git a/rule_packages/c/Strings1.json b/rule_packages/c/Strings1.json index 39529df3cc..c4565fc898 100644 --- a/rule_packages/c/Strings1.json +++ b/rule_packages/c/Strings1.json @@ -14,7 +14,12 @@ "short_name": "DoNotAttemptToModifyStringLiterals", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], @@ -34,7 +39,12 @@ "short_name": "StringsHasSufficientSpaceForTheNullTerminator", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ], "implementation_scope": { "description": "The enforcement of this rule does not try to approximate the effects of loops and as such may not find cases where a loop operation on a string fails to null terminate a string (or causes an overflow)." @@ -57,7 +67,12 @@ "short_name": "NonNullTerminatedToFunctionThatExpectsAString", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ], "implementation_scope": { "description": "Wide character types are not handled correctly on the `aarch64le` architecture. This can lead to false negative alerts." diff --git a/rule_packages/c/Strings2.json b/rule_packages/c/Strings2.json index 99f5e240d7..a32b1b4c28 100644 --- a/rule_packages/c/Strings2.json +++ b/rule_packages/c/Strings2.json @@ -14,7 +14,12 @@ "short_name": "ToCharacterHandlingFunctionsRepresentableAsUChar", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/Strings3.json b/rule_packages/c/Strings3.json index 9456f4b422..c9003f2ff8 100644 --- a/rule_packages/c/Strings3.json +++ b/rule_packages/c/Strings3.json @@ -12,9 +12,15 @@ "precision": "very-high", "severity": "error", "short_name": "CastCharBeforeConvertingToLargerSizes", + "shared_implementation_short_name": "CastCharBeforeConvertingToLargerSizes", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -34,7 +40,12 @@ "short_name": "DoNotConfuseNarrowAndWideFunctions", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p27", + "external/cert/level/l1" ], "implementation_scope": { "description": "Wide character types are not handled correctly on the `aarch64le` architecture. This can lead to false negative alerts." diff --git a/rule_packages/c/Syntax.json b/rule_packages/c/Syntax.json index d294c44183..e588c366c0 100644 --- a/rule_packages/c/Syntax.json +++ b/rule_packages/c/Syntax.json @@ -14,7 +14,8 @@ "short_name": "CharacterSequencesAndUsedWithinAComment", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -35,7 +36,8 @@ "tags": [ "maintainability", "readability", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -53,10 +55,12 @@ "precision": "very-high", "severity": "warning", "short_name": "OctalAndHexadecimalEscapeSequencesNotTerminated", + "shared_implementation_short_name": "NonTerminatedEscapeSequences", "tags": [ "maintainability", "readability", - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -78,8 +82,9 @@ "tags": [ "maintainability", "readability", - "correctness" - ] + "correctness", + "external/misra/c/2012/third-edition-first-revision" + ] } ], "title": "Sections of code should not be commented out" @@ -96,10 +101,11 @@ "precision": "very-high", "severity": "recommendation", "short_name": "IdentifiersInTheSameNameSpaceUnambiguous", - "shared_implementation_short_name" : "DifferentIdentifiersNotTypographicallyUnambiguous", + "shared_implementation_short_name": "DifferentIdentifiersNotTypographicallyUnambiguous", "tags": [ "readability", - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ] } ], @@ -119,8 +125,12 @@ "short_name": "UOrUSuffixRepresentedInUnsignedType", "tags": [ "maintainability", - "readability" - ] + "readability", + "external/misra/c/2012/third-edition-first-revision" + ], + "implementation_scope": { + "description": "This implementation does not consider constants defined in macro bodies." + } } ], "title": "A 'U' or 'u' suffix shall be applied to all integer constants that are represented in an unsigned type" @@ -137,9 +147,11 @@ "precision": "very-high", "severity": "recommendation", "short_name": "LowercaseCharacterLUsedInLiteralSuffix", + "shared_implementation_short_name": "LowercaseLStartsInLiteralSuffix", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/third-edition-first-revision" ] } ], diff --git a/rule_packages/c/Types1.json b/rule_packages/c/Types1.json index fae0339d3c..bb451eba70 100644 --- a/rule_packages/c/Types1.json +++ b/rule_packages/c/Types1.json @@ -12,7 +12,13 @@ "precision": "very-high", "severity": "error", "short_name": "ExprShiftedbyNegativeOrGreaterPrecisionOperand", - "tags": [] + "tags": [ + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" + ] } ], "title": "Do not shift an expression by a negative number of bits or by greater than or equal to the number of bits that exist in the operand" @@ -29,7 +35,13 @@ "precision": "very-high", "severity": "error", "short_name": "ConvertingAPointerToIntegerOrIntegerToPointer", - "tags": [] + "tags": [ + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p2", + "external/cert/level/l3" + ] } ], "title": "Converting a pointer to integer or integer to pointer" @@ -48,7 +60,9 @@ "precision": "high", "severity": "error", "short_name": "PlainNumericalTypeUsedOverExplicitTypedef", - "tags": [] + "tags": [ + "external/misra/c/2012/third-edition-first-revision" + ] } ], "title": "typedefs that indicate size and signedness should be used in place of the basic numerical types" @@ -65,7 +79,9 @@ "precision": "very-high", "severity": "error", "short_name": "SizeofOperatorUsedOnArrayTypeParam", - "tags": [] + "tags": [ + "external/misra/c/2012/third-edition-first-revision" + ] } ], "title": "The sizeof operator shall not have an operand which is a function parameter declared as 'array of type'" @@ -82,10 +98,12 @@ "precision": "very-high", "severity": "error", "short_name": "StringLiteralAssignedToNonConstChar", - "tags": [] + "tags": [ + "external/misra/c/2012/third-edition-first-revision" + ] } ], "title": "A string literal shall not be assigned to an object unless the object's type is 'pointer to const-qualified char'" } } -} +} \ No newline at end of file diff --git a/rule_packages/c/Types2.json b/rule_packages/c/Types2.json new file mode 100644 index 0000000000..7e4c0827fe --- /dev/null +++ b/rule_packages/c/Types2.json @@ -0,0 +1,84 @@ +{ + "MISRA-C-2012": { + "RULE-7-5": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Integer constant macros should be given a literal value as an argument.", + "kind": "problem", + "name": "The argument of an integer constant macro shall be a literal", + "precision": "very-high", + "severity": "warning", + "short_name": "InvalidIntegerConstantMacroArgument", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + }, + { + "description": "Integer constant macro arguments should be a decimal, hex, or octal literal.", + "kind": "problem", + "name": "The argument of an integer constant macro shall be a decimal, hex, or octal literal", + "precision": "very-high", + "severity": "error", + "short_name": "InvalidLiteralForIntegerConstantMacroArgument", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + }, + { + "description": "Integer constant macros should be used integer literal values with no u/l suffix.", + "kind": "problem", + "name": "The argument of an integer constant macro shall not use literal suffixes u, l, or ul", + "precision": "high", + "severity": "warning", + "short_name": "IntegerConstantMacroArgumentUsesSuffix", + "tags": [ + "readability", + "maintainability", + "external/misra/c/2012/amendment3" + ] + }, + { + "description": "Integer constant macros argument values should be values of a compatible size.", + "kind": "problem", + "name": "The argument of an integer constant macro shall have an appropriate size", + "precision": "very-high", + "severity": "error", + "short_name": "IncorrectlySizedIntegerConstantMacroArgument", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ], + "implementation_scope": { + "description": "This rule can validate integers sized 32 or smaller. When the CodeQL runtime supports big ints, this will be expanded to include 64 bit integer types." + } + } + ], + "title": "The argument of an integer constant macro shall have an appropriate form" + }, + "RULE-7-6": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Small integer constant macros expression are promoted to type int, which can lead to unexpected results.", + "kind": "problem", + "name": "The small integer variants of the minimum-width integer constant macros shall not be used", + "precision": "very-high", + "severity": "warning", + "short_name": "UseOfBannedSmallIntegerConstantMacro", + "tags": [ + "readability", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "The small integer variants of the minimum-width integer constant macros shall not be used" + } + } +} \ No newline at end of file diff --git a/rule_packages/cpp/Allocations.json b/rule_packages/cpp/Allocations.json index 6b40523e16..416cd3b567 100644 --- a/rule_packages/cpp/Allocations.json +++ b/rule_packages/cpp/Allocations.json @@ -197,7 +197,12 @@ "short_name": "ProperlyDeallocateDynamicallyAllocatedResources", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -216,7 +221,12 @@ "severity": "error", "short_name": "DetectAndHandleMemoryAllocationErrors", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -235,7 +245,12 @@ "severity": "error", "short_name": "MissingConstructorCallForManuallyManagedObject", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] }, { @@ -246,7 +261,12 @@ "severity": "error", "short_name": "MissingDestructorCallForManuallyManagedObject", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -267,7 +287,12 @@ "shared_implementation_short_name": "PlacementNewNotProperlyAligned", "tags": [ "security", - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] }, { @@ -280,7 +305,12 @@ "shared_implementation_short_name": "PlacementNewInsufficientStorage", "tags": [ "security", - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -300,7 +330,12 @@ "short_name": "ThrowingOperatorNewReturnsNullCert", "shared_implementation_short_name": "ThrowingOperatorNewReturnsNull", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] }, { @@ -312,7 +347,12 @@ "short_name": "ThrowingOperatorNewThrowsInvalidExceptionCert", "shared_implementation_short_name": "ThrowingOperatorNewThrowsInvalidException", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] }, { @@ -324,7 +364,12 @@ "short_name": "ThrowingNoThrowOperatorNewDeleteCert", "shared_implementation_short_name": "ThrowingNoThrowOperatorNewDelete", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] }, { @@ -336,7 +381,12 @@ "short_name": "OperatorDeleteMissingPartnerCert", "shared_implementation_short_name": "OperatorDeleteMissingPartner", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -356,7 +406,12 @@ "short_name": "UsingDefaultOperatorNewForOverAlignedTypes", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/BannedAPIs.json b/rule_packages/cpp/BannedAPIs.json new file mode 100644 index 0000000000..3bb456fdd4 --- /dev/null +++ b/rule_packages/cpp/BannedAPIs.json @@ -0,0 +1,227 @@ +{ + "MISRA-C++-2023": { + "RULE-18-5-2": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "Using program-terminating functions like abort, exit, _Exit, quick_exit or terminate causes the stack to not be unwound and object destructors to not be called, potentially leaving the environment in an undesirable state.", + "kind": "problem", + "name": "Program-terminating functions should not be used", + "precision": "very-high", + "severity": "error", + "short_name": "AvoidProgramTerminatingFunctions", + "tags": [ + "scope/single-translation-unit", + "maintainability", + "correctness" + ] + } + ], + "title": "Program-terminating functions should not be used" + }, + "RULE-21-10-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using features like va_list, va_arg, va_start, va_end and va_copy bypasses compiler type checking and leads to undefined behavior when used incorrectly.", + "kind": "problem", + "name": "The features of shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "NoVariadicFunctionMacros", + "tags": [ + "scope/single-translation-unit", + "correctness", + "maintainability" + ] + } + ], + "title": "The features of shall not be used" + }, + "RULE-21-10-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using facilities from the header causes undefined behavior by bypassing normal function return mechanisms and may result in non-trivial object destruction being omitted.", + "kind": "problem", + "name": "The standard header file shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "NoCsetjmpHeader", + "tags": [ + "scope/single-translation-unit", + "correctness", + "maintainability" + ] + } + ], + "title": "The standard header file shall not be used" + }, + "RULE-21-2-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using string handling functions from , , and headers may result in buffer overflows or unreliable error detection through errno.", + "kind": "problem", + "name": "The string handling functions from , , and shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "UnsafeStringHandlingFunctions", + "tags": [ + "scope/single-translation-unit", + "correctness", + "maintainability" + ] + } + ], + "title": "The string handling functions from , , and shall not be used" + }, + "RULE-21-2-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using the system() function from cstdlib or stdlib.h causes undefined behavior and potential security vulnerabilities.", + "kind": "problem", + "name": "The library function system from shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "BannedSystemFunction", + "tags": [ + "scope/single-translation-unit", + "correctness", + "maintainability", + "security" + ] + } + ], + "title": "The library function system from shall not be used" + }, + "RULE-23-11-1": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "Using raw pointer constructors of std::shared_ptr and std::unique_ptr instead of make_shared/make_unique can lead to memory leaks if exceptions occur during construction.", + "kind": "problem", + "name": "The raw pointer constructors of std::shared_ptr and std::unique_ptr should not be used", + "precision": "very-high", + "severity": "error", + "short_name": "UseSmartPtrFactoryFunctions", + "tags": [ + "scope/single-translation-unit", + "correctness", + "maintainability" + ] + } + ], + "title": "The raw pointer constructors of std::shared_ptr and std::unique_ptr should not be used" + }, + "RULE-24-5-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using character classification and case mapping functions from and causes undefined behavior when arguments are not representable as unsigned char or not equal to EOF.", + "kind": "problem", + "name": "The character handling functions from and shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "CharacterHandlingFunctionRestrictions", + "tags": [ + "scope/single-translation-unit", + "correctness", + "maintainability" + ] + } + ], + "title": "The character handling functions from and shall not be used" + }, + "RULE-24-5-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using memcpy, memmove or memcmp from can result in undefined behavior due to overlapping memory, non-trivially copyable objects, or unequal comparison of logically equal objects.", + "kind": "problem", + "name": "The C++ Standard Library functions memcpy, memmove and memcmp from shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "NoMemoryFunctionsFromCString", + "tags": [ + "scope/single-translation-unit", + "correctness", + "maintainability" + ] + } + ], + "title": "The C++ Standard Library functions memcpy, memmove and memcmp from shall not be used" + }, + "RULE-25-5-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Calling setlocale or std::locale::global functions can introduce data races with functions that use the locale, leading to undefined behavior.", + "kind": "problem", + "name": "The setlocale and std::locale::global functions shall not be called", + "precision": "very-high", + "severity": "error", + "short_name": "LocaleGlobalFunctionNotAllowed", + "tags": [ + "scope/single-translation-unit", + "correctness", + "maintainability", + "concurrency" + ] + } + ], + "title": "The setlocale and std::locale::global functions shall not be called" + }, + "RULE-6-9-2": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "Using standard signed and unsigned integer type names instead of specified width types makes storage requirements unclear and implementation-dependent.", + "kind": "problem", + "name": "The names of the standard signed integer types and standard unsigned integer types should not be", + "precision": "very-high", + "severity": "error", + "short_name": "AvoidStandardIntegerTypeNames", + "shared_implementation_short_name": "VariableWidthIntegerTypesUsed", + "tags": [ + "scope/single-translation-unit", + "correctness", + "maintainability" + ] + } + ], + "title": "The names of the standard signed integer types and standard unsigned integer types should not be used" + } + } +} \ No newline at end of file diff --git a/rule_packages/cpp/BannedFunctions.json b/rule_packages/cpp/BannedFunctions.json index bb89ab2320..6cdb019ace 100644 --- a/rule_packages/cpp/BannedFunctions.json +++ b/rule_packages/cpp/BannedFunctions.json @@ -189,6 +189,7 @@ "precision": "very-high", "severity": "error", "short_name": "MacroOffsetofUsed", + "shared_implementation_short_name": "MacroOffsetofUsed", "tags": [ "security", "scope/single-translation-unit" @@ -214,7 +215,12 @@ "shared_implementation_short_name": "DoNotUseSetjmpOrLongjmpShared", "tags": [ "correctness", - "scope/single-translation-unit" + "scope/single-translation-unit", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -235,7 +241,12 @@ "shared_implementation_short_name": "DoNotUseRandForGeneratingPseudorandomNumbers", "tags": [ "security", - "scope/single-translation-unit" + "scope/single-translation-unit", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -255,7 +266,12 @@ "short_name": "PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions", "tags": [ "correctness", - "scope/single-translation-unit" + "scope/single-translation-unit", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/BannedLibraries.json b/rule_packages/cpp/BannedLibraries.json index 09b5d2f224..fce11b9eca 100644 --- a/rule_packages/cpp/BannedLibraries.json +++ b/rule_packages/cpp/BannedLibraries.json @@ -114,6 +114,7 @@ "precision": "very-high", "severity": "warning", "short_name": "CsignalFunctionsUsed", + "shared_implementation_short_name": "CsignalFunctionsUsed", "tags": [ "maintainability", "correctness", @@ -127,6 +128,7 @@ "precision": "very-high", "severity": "warning", "short_name": "CsignalTypesUsed", + "shared_implementation_short_name": "CsignalTypesUsed", "tags": [ "maintainability", "correctness", @@ -177,6 +179,7 @@ "precision": "very-high", "severity": "warning", "short_name": "CstdioFunctionsUsed", + "shared_implementation_short_name": "CstdioFunctionsUsed", "tags": [ "maintainability", "correctness", @@ -190,6 +193,7 @@ "precision": "very-high", "severity": "warning", "short_name": "CstdioMacrosUsed", + "shared_implementation_short_name": "CstdioMacrosUsed", "tags": [ "maintainability", "correctness", @@ -203,6 +207,7 @@ "precision": "very-high", "severity": "warning", "short_name": "CstdioTypesUsed", + "shared_implementation_short_name": "CstdioTypesUsed", "tags": [ "maintainability", "correctness", diff --git a/rule_packages/cpp/BannedSyntax.json b/rule_packages/cpp/BannedSyntax.json index 0f559e60b7..8f739145f7 100644 --- a/rule_packages/cpp/BannedSyntax.json +++ b/rule_packages/cpp/BannedSyntax.json @@ -169,6 +169,7 @@ "precision": "very-high", "severity": "error", "short_name": "ReinterpretCastUsed", + "shared_implementation_short_name": "ReinterpretCastUsed", "tags": [ "correctness", "security", @@ -194,6 +195,7 @@ "precision": "very-high", "severity": "error", "short_name": "GotoStatementUsed", + "shared_implementation_short_name": "GotoStatementShouldNotBeUsed", "tags": [ "correctness", "security", @@ -266,6 +268,7 @@ "name": "The asm declaration shall not be used", "precision": "very-high", "severity": "error", + "shared_implementation_short_name": "AsmDeclarationUsed", "short_name": "AsmDeclarationUsed", "tags": [ "correctness", @@ -414,7 +417,12 @@ "tags": [ "correctness", "security", - "scope/single-translation-unit" + "scope/single-translation-unit", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ] } ], diff --git a/rule_packages/cpp/BannedTypes.json b/rule_packages/cpp/BannedTypes.json index 4a45433746..e84399b928 100644 --- a/rule_packages/cpp/BannedTypes.json +++ b/rule_packages/cpp/BannedTypes.json @@ -41,6 +41,7 @@ "precision": "very-high", "severity": "warning", "short_name": "VectorboolSpecializationUsed", + "shared_implementation_short_name": "VectorShouldNotBeSpecializedWithBool", "tags": [ "correctness", "scope/single-translation-unit" diff --git a/rule_packages/cpp/Classes.json b/rule_packages/cpp/Classes.json index 61eab45081..e7c8a10d92 100644 --- a/rule_packages/cpp/Classes.json +++ b/rule_packages/cpp/Classes.json @@ -178,23 +178,16 @@ "obligation": "required" }, "queries": [ - { - "description": "A function that is either trivial, a template function, or a member of a template class may not be defined outside of a class body.", - "kind": "problem", - "name": "A function shall be defined with a class body if and only if it is intended to be inlined", - "precision": "very-high", - "severity": "recommendation", - "short_name": "TrivialOrTemplateFunctionDefinedOutsideClassDefinition", - "tags": [] - }, { "description": "A function that is not either trivial, a template function, or a member of a template class may not be defined within a class body.", "kind": "problem", "name": "A function shall be defined with a class body if and only if it is intended to be inlined", - "precision": "very-high", + "precision": "low", "severity": "recommendation", "short_name": "NonTrivialNonTemplateFunctionDefinedInsideClassDefinition", - "tags": [] + "tags": [ + "external/autosar/audit" + ] } ], "title": "A function definition shall only be placed in a class definition if (1) the function is intended to be inlined (2) it is a member function template (3) it is a member function of a class template." @@ -322,7 +315,12 @@ "severity": "recommendation", "short_name": "OffsetUsedOnInvalidTypeOrMember", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/Comments.json b/rule_packages/cpp/Comments.json index 7af32f62c1..2421bec52f 100644 --- a/rule_packages/cpp/Comments.json +++ b/rule_packages/cpp/Comments.json @@ -16,6 +16,7 @@ "precision": "very-high", "severity": "warning", "short_name": "SingleLineCommentEndsWithSlash", + "shared_implementation_short_name": "LineSplicingUsedInComments", "tags": [ "correctness", "readability", @@ -94,6 +95,7 @@ "precision": "very-high", "severity": "warning", "short_name": "SlashStarUsedWithinACStyleComment", + "shared_implementation_short_name": "CharacterSequenceUsedWithinACStyleComment", "tags": [ "maintainability", "readability", diff --git a/rule_packages/cpp/Concurrency.json b/rule_packages/cpp/Concurrency.json index 6e5898ecd8..3bba2f409f 100644 --- a/rule_packages/cpp/Concurrency.json +++ b/rule_packages/cpp/Concurrency.json @@ -15,7 +15,12 @@ "shared_implementation_short_name": "DoNotAllowAMutexToGoOutOfScopeWhileLocked", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -28,7 +33,12 @@ "shared_implementation_short_name": "DoNotDestroyAMutexWhileItIsLocked", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -48,7 +58,12 @@ "short_name": "EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/low", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -69,7 +84,12 @@ "shared_implementation_short_name": "GuardAccessToBitFields", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -90,7 +110,12 @@ "shared_implementation_short_name": "PreventDeadlockByLockingInPredefinedOrder", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -111,7 +136,12 @@ "shared_implementation_short_name": "WrapSpuriousFunctionInLoop", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -132,7 +162,12 @@ "shared_implementation_short_name": "PreserveSafetyWhenUsingConditionVariables", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -152,7 +187,12 @@ "short_name": "DoNotSpeculativelyLockALockedNonRecursiveMutex", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/high", + "external/cert/priority/p1", + "external/cert/level/l3" ] }, { @@ -164,7 +204,12 @@ "short_name": "LockedALockedNonRecursiveMutexAudit", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/high", + "external/cert/priority/p1", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/Conditionals.json b/rule_packages/cpp/Conditionals.json index c2afb626e4..584df19420 100644 --- a/rule_packages/cpp/Conditionals.json +++ b/rule_packages/cpp/Conditionals.json @@ -78,6 +78,7 @@ "precision": "very-high", "severity": "recommendation", "short_name": "SwitchCompoundCondition", + "shared_implementation_short_name": "SwitchCompoundCondition", "tags": [ "maintainability", "readability" @@ -90,6 +91,7 @@ "precision": "very-high", "severity": "recommendation", "short_name": "LoopCompoundCondition", + "shared_implementation_short_name": "LoopCompoundCondition", "tags": [ "maintainability", "readability" diff --git a/rule_packages/cpp/Const.json b/rule_packages/cpp/Const.json index c574e547bf..6f76b7f5b8 100644 --- a/rule_packages/cpp/Const.json +++ b/rule_packages/cpp/Const.json @@ -71,17 +71,6 @@ "tags": [ "maintainability" ] - }, - { - "description": "Using 'constexpr' makes it clear that a function is intended to return a compile time constant.", - "kind": "problem", - "name": "The constexpr specifier shall be used for functions whose return value can be determined at compile time", - "precision": "high", - "severity": "recommendation", - "short_name": "FunctionMissingConstexpr", - "tags": [ - "maintainability" - ] } ], "title": "The constexpr specifier shall be used for values that can be determined at compile time." @@ -262,7 +251,12 @@ "shared_implementation_short_name": "RemoveConstOrVolatileQualification", "short_name": "RemoveConstOrVolatileQualificationCert", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/Conversions.json b/rule_packages/cpp/Conversions.json new file mode 100644 index 0000000000..441b5aa85f --- /dev/null +++ b/rule_packages/cpp/Conversions.json @@ -0,0 +1,147 @@ +{ + "MISRA-C++-2023": { + "RULE-7-0-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Converting a bool type (implicitly or explicitly) to another type can lead to unintended behavior and code obfuscation, particularly when using bitwise operators instead of logical operators.", + "kind": "problem", + "name": "There shall be no conversion from type bool", + "precision": "very-high", + "severity": "error", + "short_name": "NoConversionFromBool", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "There shall be no conversion from type bool" + }, + "RULE-7-0-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Implicit and contextual conversions to bool from fundamental types, unscoped enums, or pointers may lead to unintended behavior, except for specific cases like pointer checks and explicit operator bool conversions.", + "kind": "problem", + "name": "There shall be no conversion to type bool", + "precision": "very-high", + "severity": "error", + "short_name": "NoImplicitBoolConversion", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "There shall be no conversion to type bool" + }, + "RULE-7-0-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using the numerical value of a character type may lead to inconsistent behavior due to encoding dependencies and should be avoided in favor of safer C++ Standard Library functions.", + "kind": "problem", + "name": "The numerical value of a character shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "NoCharacterNumericalValue", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The numerical value of a character shall not be used" + }, + "RULE-7-0-4": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Bitwise and shift operators should only be applied to operands of appropriate types and values to avoid implementation-defined or undefined behavior.", + "kind": "problem", + "name": "The operands of bitwise operators and shift operators shall be appropriate", + "precision": "very-high", + "severity": "error", + "short_name": "InappropriateBitwiseOrShiftOperands", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The operands of bitwise operators and shift operators shall be appropriate" + }, + "RULE-7-0-5": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Integral promotion and usual arithmetic conversions that change operand signedness or type category may cause unexpected behavior or undefined behavior when operations overflow.", + "kind": "problem", + "name": "Integral promotion and the usual arithmetic conversions shall not change the signedness or the type", + "precision": "very-high", + "severity": "error", + "short_name": "NoSignednessChangeFromPromotion", + "tags": [ + "scope/single-translation-unit" + ], + "implementation_scope": { + "description": "Arithmetic conversions in preprocessor directives are not supported." + } + } + ], + "title": "Integral promotion and the usual arithmetic conversions shall not change the signedness or the type category of an operand" + }, + "RULE-7-0-6": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Assignment between numeric types with different sizes, signedness, or type categories can lead to unexpected information loss, undefined behavior, or silent overload resolution changes.", + "kind": "problem", + "name": "Assignment between numeric types shall be appropriate", + "precision": "high", + "severity": "error", + "short_name": "NumericAssignmentTypeMismatch", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "Assignment between numeric types shall be appropriate" + }, + "RULE-7-11-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Converting a function type to a pointer-to-function type outside of static_cast or assignment to a pointer-to-function object creates ambiguous behavior and potential unintended effects.", + "kind": "problem", + "name": "A conversion from function type to pointer-to-function type shall only occur in appropriate contexts", + "precision": "very-high", + "severity": "error", + "short_name": "FunctionPointerConversionContext", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "A conversion from function type to pointer-to-function type shall only occur in appropriate contexts" + } + } +} \ No newline at end of file diff --git a/rule_packages/cpp/Conversions2.json b/rule_packages/cpp/Conversions2.json new file mode 100644 index 0000000000..a4fc4f565d --- /dev/null +++ b/rule_packages/cpp/Conversions2.json @@ -0,0 +1,137 @@ +{ + "MISRA-C++-2023": { + "RULE-8-2-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Casting from a virtual base class to a derived class using anything other than dynamic_cast causes undefined behavior.", + "kind": "problem", + "name": "A virtual base class shall only be cast to a derived class by means of dynamic_cast", + "precision": "very-high", + "severity": "error", + "short_name": "VirtualBaseClassCastToDerived", + "tags": [ + "scope/single-translation-unit", + "correctness" + ], + "shared_implementation_short_name": "PointerToAVirtualBaseClassCastToAPointer" + } + ], + "title": "A virtual base class shall only be cast to a derived class by means of dynamic_cast" + }, + "RULE-8-2-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using C-style casts or functional notation casts allows unsafe type conversions and makes code harder to maintain compared to using named casts like const_cast, dynamic_cast, static_cast and reinterpret_cast.", + "kind": "problem", + "name": "C-style casts and functional notation casts shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "NoCStyleOrFunctionalCasts", + "tags": [ + "scope/single-translation-unit", + "readability", + "correctness" + ] + } + ], + "title": "C-style casts and functional notation casts shall not be used" + }, + "RULE-8-2-6": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Casting from an integral type, enumerated type, or pointer to void type to a pointer type leads to unspecified behavior and is error prone.", + "kind": "problem", + "name": "An object with integral, enumerated, or pointer to void type shall not be cast to a pointer type", + "precision": "very-high", + "severity": "error", + "short_name": "IntToPointerCastProhibited", + "tags": [ + "scope/single-translation-unit", + "correctness", + "maintainability" + ] + } + ], + "title": "An object with integral, enumerated, or pointer to void type shall not be cast to a pointer type" + }, + "RULE-8-2-7": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "Casting between pointer types and integral types makes code behavior harder to understand and may cause pointer tracking tools to become unreliable.", + "kind": "problem", + "name": "A cast should not convert a pointer type to an integral type", + "precision": "very-high", + "severity": "error", + "short_name": "NoPointerToIntegralCast", + "tags": [ + "scope/single-translation-unit", + "correctness", + "maintainability" + ] + } + ], + "title": "A cast should not convert a pointer type to an integral type" + }, + "RULE-8-2-8": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Casting object pointers to integral types other than std::uintptr_t or std::intptr_t can lead to implementation-defined behavior and potential loss of pointer information.", + "kind": "problem", + "name": "An object pointer type shall not be cast to an integral type other than std::uintptr_t or", + "precision": "very-high", + "severity": "error", + "short_name": "PointerToIntegralCast", + "tags": [ + "scope/single-translation-unit", + "correctness" + ] + } + ], + "title": "An object pointer type shall not be cast to an integral type other than std::uintptr_t or std::intptr_t" + }, + "RULE-9-2-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using an explicit type conversion as an expression statement creates a temporary object that is immediately discarded, which can lead to unintended premature resource cleanup.", + "kind": "problem", + "name": "An explicit type conversion shall not be an expression statement", + "precision": "very-high", + "severity": "error", + "short_name": "NoStandaloneTypeCastExpression", + "tags": [ + "scope/single-translation-unit", + "correctness" + ], + "implementation_scope": { + "description": "Expression statements in if statement initializers are not currently supported." + } + } + ], + "title": "An explicit type conversion shall not be an expression statement" + } + } +} \ No newline at end of file diff --git a/rule_packages/cpp/DeadCode.json b/rule_packages/cpp/DeadCode.json index 7eb5c9f6f9..4746f86dee 100644 --- a/rule_packages/cpp/DeadCode.json +++ b/rule_packages/cpp/DeadCode.json @@ -194,6 +194,21 @@ "readability", "maintainability" ] + }, + { + "description": "Uncalled functions complicate the program and can indicate a possible mistake on the part of the programmer.", + "kind": "problem", + "name": "Every defined function should be called at least once", + "precision": "medium", + "severity": "warning", + "short_name": "UnusedSplMemberFunction", + "tags": [ + "readability", + "maintainability" + ], + "implementation_scope": { + "description": "In limited cases, this query can raise false-positives for special member function calls invoked from the C++ Metaprogramming library." + } } ], "title": "Every defined function should be called at least once." diff --git a/rule_packages/cpp/Declarations.json b/rule_packages/cpp/Declarations.json index 65dfbf781e..61d286026a 100644 --- a/rule_packages/cpp/Declarations.json +++ b/rule_packages/cpp/Declarations.json @@ -50,6 +50,7 @@ "precision": "very-high", "severity": "error", "short_name": "GlobalSizedOperatorDeleteNotDefined", + "shared_implementation_short_name": "GlobalSizedOperatorDeleteNotDefined", "tags": [ "maintainability" ] @@ -61,6 +62,7 @@ "precision": "very-high", "severity": "error", "short_name": "GlobalUnsizedOperatorDeleteNotDefined", + "shared_implementation_short_name": "GlobalUnsizedOperatorDeleteNotDefined", "tags": [ "maintainability" ] @@ -90,8 +92,9 @@ "maintainability" ], "implementation_scope": { - "description": "This implementation excludes the plain char type from consideration." - } + "description": "This implementation excludes the plain char type. It also excludes the use of standard integer types in the definition of main functions, and the use of an integer parameter in the declaration of postfix operators." + }, + "shared_implementation_short_name": "VariableWidthIntegerTypesUsed" }, { "description": "The basic numerical type char is not supposed to be used. The specific-length types from header need be used instead.", @@ -216,6 +219,7 @@ "precision": "very-high", "severity": "recommendation", "short_name": "EnumerationUnderlyingBaseTypeNotExplicitlyDefined", + "shared_implementation_short_name": "EnumerationNotDefinedWithAnExplicitUnderlyingType", "tags": [ "readability", "maintainability" diff --git a/rule_packages/cpp/ExceptionSafety.json b/rule_packages/cpp/ExceptionSafety.json index 07e97ae328..73b84edde4 100644 --- a/rule_packages/cpp/ExceptionSafety.json +++ b/rule_packages/cpp/ExceptionSafety.json @@ -90,7 +90,12 @@ "short_name": "GuaranteeExceptionSafety", "shared_implementation_short_name": "ExceptionSafetyGuarantees", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/high", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], @@ -111,7 +116,12 @@ "shared_implementation_short_name": "ExceptionSafetyValidState", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/Exceptions1.json b/rule_packages/cpp/Exceptions1.json index d42c949b48..7c3a2a708a 100644 --- a/rule_packages/cpp/Exceptions1.json +++ b/rule_packages/cpp/Exceptions1.json @@ -90,6 +90,7 @@ "precision": "very-high", "severity": "error", "short_name": "PointerExceptionObject", + "shared_implementation_short_name": "ExceptionObjectHavePointerType", "tags": [ "correctness" ] @@ -224,6 +225,7 @@ "severity": "error", "kind": "path-problem", "short_name": "NoExceptFunctionThrows", + "shared_implementation_short_name": "NoexceptFunctionShouldNotPropagateToTheCaller", "tags": [ "correctness" ] @@ -428,6 +430,7 @@ "precision": "very-high", "severity": "error", "short_name": "EmptyThrowOutsideCatch", + "shared_implementation_short_name": "EmptyThrowOnlyWithinACatchHandler", "tags": [ "correctness" ] @@ -499,7 +502,12 @@ "shared_implementation_short_name": "ConditionVariablePostConditionFailed", "tags": [ "correctness", - "external/cert/audit" + "external/cert/audit", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -510,7 +518,12 @@ "short_name": "JoinableThreadCopiedOrDestroyedCert", "shared_implementation_short_name": "JoinableThreadCopiedOrDestroyed", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -522,7 +535,12 @@ "short_name": "RethrowNestedWithoutCaptureCert", "shared_implementation_short_name": "RethrowNestedWithoutCapture", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -534,7 +552,12 @@ "short_name": "ExplicitAbruptTerminationCert", "shared_implementation_short_name": "ExplicitAbruptTermination", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -546,7 +569,12 @@ "short_name": "ExitHandlerThrowsExceptionCert", "shared_implementation_short_name": "ExitHandlerThrowsException", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -565,7 +593,12 @@ "kind": "path-problem", "short_name": "HandleAllExceptions", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -584,7 +617,12 @@ "shared_implementation_short_name": "DestroyedValueReferencedInDestructorCatchBlock", "short_name": "DestroyedValueReferencedInConstructorDestructorCatchBlock", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -603,7 +641,12 @@ "kind": "path-problem", "short_name": "HonorExceptionSpecifications", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], @@ -623,7 +666,12 @@ "shared_implementation_short_name": "HandleAllExceptionsDuringStartup", "short_name": "HandleAllExceptionsThrownBeforeMainBeginsExecuting", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], @@ -641,7 +689,12 @@ "severity": "error", "short_name": "ExceptionObjectsMustBeNothrowCopyConstructible", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -660,7 +713,12 @@ "shared_implementation_short_name": "CatchExceptionsByLvalueReference", "short_name": "CatchExceptionsByLvalueReference", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/Exceptions2.json b/rule_packages/cpp/Exceptions2.json index ece305a04a..2e2f2dfba6 100644 --- a/rule_packages/cpp/Exceptions2.json +++ b/rule_packages/cpp/Exceptions2.json @@ -295,7 +295,12 @@ "severity": "error", "short_name": "DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -315,7 +320,12 @@ "shared_implementation_short_name": "CatchBlockShadowing", "short_name": "CatchBlockShadowingCert", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], diff --git a/rule_packages/cpp/Expressions.json b/rule_packages/cpp/Expressions.json index c0a7b6bb0b..10f85237de 100644 --- a/rule_packages/cpp/Expressions.json +++ b/rule_packages/cpp/Expressions.json @@ -86,9 +86,13 @@ "precision": "very-high", "severity": "recommendation", "short_name": "FunctionErroneousReturnValueNotTested", + "shared_implementation_short_name": "FunctionErroneousReturnValueNotTested", "tags": [ "maintainability" - ] + ], + "implementation_scope": { + "description": "The query enforces checking on some C standard library functions that may return error codes." + } } ], "title": "If a function generates error information, then that error information shall be tested." @@ -126,7 +130,7 @@ }, "queries": [ { - "description": "Expressions with type (plain) char and wchar_t shall not be used as operands to built-in operators other than the assignment operator =, the equality operators == and ! =, and the unary & operator. Manipulation of character data may generate results that are contrary to developer expectations. For example, ISO/IEC 14882:2003 [1] §2.2(3) only requires that the digits \"0\" to \"9\" have consecutive numerical values.", + "description": "Expressions with type (plain) char and wchar_t shall not be used as operands to built-in operators other than the assignment operator =, the equality operators == and ! =, and the unary & operator. Manipulation of character data may generate results that are contrary to developer expectations. For example, ISO/IEC 14882:2003 [1] \u00a72.2(3) only requires that the digits \"0\" to \"9\" have consecutive numerical values.", "kind": "problem", "name": "Expressions with type (plain) char and wchar_t shall only be used as operands to =, ==, !=, &", "precision": "very-high", @@ -319,7 +323,12 @@ "severity": "error", "short_name": "PassPromotablePrimitiveTypeToVaStart", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -330,7 +339,12 @@ "severity": "error", "short_name": "PassReferenceTypeToVaStart", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -341,7 +355,12 @@ "severity": "warning", "short_name": "PassNonTrivialObjectToVaStart", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/FloatingPoint.json b/rule_packages/cpp/FloatingPoint.json new file mode 100644 index 0000000000..672e57acff --- /dev/null +++ b/rule_packages/cpp/FloatingPoint.json @@ -0,0 +1,36 @@ +{ + "MISRA-C++-2023": { + "DIR-0-3-1": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "Possible misuse of a generate infinite floating point value.", + "kind": "path-problem", + "name": "Possible misuse of a generate infinite floating point value", + "precision": "medium", + "severity": "warning", + "short_name": "PossibleMisuseOfInfiniteFloatingPointValue", + "shared_implementation_short_name": "MisuseOfInfiniteFloatingPointValue", + "tags": [ + "correctness" + ] + }, + { + "description": "Possible mishandling of an undetected NaN value produced by a floating point operation.", + "kind": "path-problem", + "name": "Possible mishandling of an undetected NaN value produced by a floating point operation", + "precision": "low", + "severity": "warning", + "short_name": "PossibleMisuseOfNaNFloatingPointValue", + "shared_implementation_short_name": "MisuseOfNaNFloatingPointValue", + "tags": [ + "correctness" + ] + } + ], + "title": "Floating-point arithmetic should be used appropriately" + } + } +} \ No newline at end of file diff --git a/rule_packages/cpp/Freed.json b/rule_packages/cpp/Freed.json index 36b9b31c3d..30ab6982b2 100644 --- a/rule_packages/cpp/Freed.json +++ b/rule_packages/cpp/Freed.json @@ -111,7 +111,12 @@ "severity": "error", "short_name": "DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -132,7 +137,12 @@ "short_name": "ObjectAccessedBeforeLifetimeCert", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] }, { @@ -145,7 +155,12 @@ "short_name": "ObjectAccessedAfterLifetimeCert", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -166,7 +181,12 @@ "short_name": "UseAfterFree", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], diff --git a/rule_packages/cpp/Functions.json b/rule_packages/cpp/Functions.json index 7f21cf0873..b650b0937c 100644 --- a/rule_packages/cpp/Functions.json +++ b/rule_packages/cpp/Functions.json @@ -87,6 +87,7 @@ "precision": "very-high", "severity": "error", "short_name": "RecursiveFunctions", + "shared_implementation_short_name": "FunctionsCallThemselvesEitherDirectlyOrIndirectly", "tags": [ "correctness", "maintainability" @@ -232,6 +233,7 @@ "precision": "very-high", "severity": "error", "short_name": "FunctionReturnAutomaticVarCondition", + "shared_implementation_short_name": "ReturnReferenceOrPointerToAutomaticLocalVariable", "tags": [ "correctness", "security" @@ -279,7 +281,12 @@ "severity": "error", "short_name": "FunctionWithMismatchedLanguageLinkage", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -299,7 +306,12 @@ "short_name": "NonVoidFunctionDoesNotReturnCert", "shared_implementation_short_name": "NonVoidFunctionDoesNotReturn", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -319,11 +331,16 @@ "short_name": "FunctionNoReturnAttributeConditionCert", "shared_implementation_short_name": "FunctionNoReturnAttributeCondition", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], "title": "Do not return from a function declared [[noreturn]]" } } -} +} \ No newline at end of file diff --git a/rule_packages/cpp/IO.json b/rule_packages/cpp/IO.json index 9ad0650e62..3d1012232c 100644 --- a/rule_packages/cpp/IO.json +++ b/rule_packages/cpp/IO.json @@ -43,7 +43,12 @@ "short_name": "InterleavedInputOutputWithoutPosition", "shared_implementation_short_name": "IOFstreamMissingPositioning", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -63,7 +68,12 @@ "short_name": "CloseFilesWhenTheyAreNoLongerNeeded", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/ImportMisra23.json b/rule_packages/cpp/ImportMisra23.json new file mode 100644 index 0000000000..243fc7cc20 --- /dev/null +++ b/rule_packages/cpp/ImportMisra23.json @@ -0,0 +1,1733 @@ +{ + "MISRA-C++-2023": { + "DIR-5-7-2": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "Commented out code may become out of date leading to developer confusion.", + "kind": "problem", + "name": "Sections of code should not be \u201ccommented out\u201d", + "precision": "very-high", + "severity": "error", + "short_name": "SectionsOfCodeShouldNotBeCommentedOut", + "shared_implementation_short_name": "SectionsOfCodeShallNotBeCommentedOut", + "tags": [ + "maintainability", + "readability", + "correctness" + ] + } + ], + "title": "Sections of code should not be \u201ccommented out\u201d" + }, + "RULE-6-2-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "The one-definition rule specifies when there should be a single definition of an element and a violation of that rule leads to undefined behavior.", + "kind": "problem", + "name": "The one-definition rule shall not be violated", + "precision": "very-high", + "severity": "error", + "short_name": "OneDefinitionRuleViolated", + "shared_implementation_short_name": "OneDefinitionRuleViolation", + "tags": [ + "correctness", + "scope/system" + ] + } + ], + "title": "The one-definition rule shall not be violated" + }, + "RULE-6-4-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Use of an identifier declared in an inner scope with an identical name to an identifier in an outer scope can lead to inadvertent errors if the incorrect identifier is modified.", + "kind": "problem", + "name": "A variable declared in an inner scope shall not hide a variable declared in an outer scope", + "precision": "very-high", + "severity": "error", + "short_name": "VariableDeclaredInInnerScopeHidesOuterScope", + "shared_implementation_short_name": "IdentifierHidden", + "tags": [ + "readability", + "maintainability", + "scope/single-translation-unit" + ] + } + ], + "title": "A variable declared in an inner scope shall not hide a variable declared in an outer scope" + }, + "RULE-6-8-1": { + "properties": { + "enforcement": "undecidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Accessing an object before its lifetime can result in undefined behavior.", + "kind": "problem", + "name": "Access of uninitialized object", + "precision": "high", + "severity": "error", + "shared_implementation_short_name": "ObjectAccessedBeforeLifetime", + "short_name": "ObjectAccessedBeforeLifetimeMisra", + "tags": [ + "correctness", + "security" + ] + }, + { + "description": "Accessing an object after its lifetime results in undefined behavior.", + "kind": "problem", + "name": "Access of object after lifetime (use-after-free)", + "precision": "high", + "severity": "error", + "shared_implementation_short_name": "ObjectAccessedAfterLifetime", + "short_name": "ObjectAccessedAfterLifetimeMisra", + "tags": [ + "correctness", + "security" + ] + } + ], + "title": "An object shall not be accessed outside of its lifetime" + }, + "RULE-8-2-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "A cast shall not remove any const or volatile qualification from the type accessed via a pointer or by reference.", + "kind": "problem", + "name": "A cast shall not remove any const or volatile qualification from the type accessed via a pointer or", + "precision": "very-high", + "severity": "error", + "short_name": "CastRemovesConstOrVolatileFromPointerOrReference", + "shared_implementation_short_name": "RemoveConstOrVolatileQualification", + "tags": [ + "correctness", + "scope/single-translation-unit" + ] + } + ], + "title": "A cast shall not remove any const or volatile qualification from the type accessed via a pointer or by reference" + }, + "RULE-9-4-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "All if ... else if constructs shall be terminated with an else statement.", + "kind": "problem", + "name": "All if ... else if constructs shall be terminated with an else statement", + "precision": "very-high", + "severity": "error", + "short_name": "IfElseIfEndCondition", + "shared_implementation_short_name": "IfElseTerminationConstruct", + "tags": [ + "readability", + "maintainability", + "scope/single-translation-unit" + ] + } + ], + "title": "All if ... else if constructs shall be terminated with an else statement" + }, + "RULE-9-6-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Jumping back to an earlier section in the code can lead to accidental iterations.", + "kind": "problem", + "name": "The goto statement shall jump to a label declared later in the function body", + "precision": "very-high", + "severity": "error", + "short_name": "GotoShallJumpToLabelDeclaredLaterInTheFunction", + "shared_implementation_short_name": "GotoStatementCondition", + "tags": [ + "maintainability", + "readability", + "scope/single-translation-unit" + ] + } + ], + "title": "The goto statement shall jump to a label declared later in the function body" + }, + "RULE-9-6-4": { + "properties": { + "enforcement": "undecidable", + "obligation": "required" + }, + "queries": [ + { + "description": "A function with the [[noreturn]] attribute that returns leads to undefined behaviour.", + "kind": "problem", + "name": "A function declared with the [[noreturn]] attribute shall not return", + "precision": "very-high", + "severity": "error", + "short_name": "FunctionDeclaredWithTheNoreturnAttributeReturn", + "shared_implementation_short_name": "FunctionNoReturnAttributeCondition", + "tags": [ + "correctness", + "scope/system" + ] + } + ], + "title": "A function declared with the [[noreturn]] attribute shall not return" + }, + "RULE-9-6-5": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "A function with non-void return type that does not exit via a return statement can result in undefined behaviour. An exception to this rule is exiting via exception handling.", + "kind": "problem", + "name": "A function with non-void return type shall return a value on all paths", + "precision": "very-high", + "severity": "error", + "short_name": "NonVoidFunctionShallReturnAValueOnAllPaths", + "shared_implementation_short_name": "NonVoidFunctionDoesNotReturn", + "tags": [ + "correctness", + "scope/single-translation-unit" + ] + } + ], + "title": "A function with non-void return type shall return a value on all paths" + }, + "RULE-11-3-2": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "Declarations with more than two levels of pointer nesting can result in code that is difficult to read and understand.", + "kind": "problem", + "name": "The declaration of an object should contain no more than two levels of pointer indirection", + "precision": "very-high", + "severity": "error", + "short_name": "DeclarationOfAnObjectIndirectionsLevel", + "shared_implementation_short_name": "DoNotUseMoreThanTwoLevelsOfPointerIndirection", + "tags": [ + "readability", + "maintainability", + "scope/single-translation-unit" + ] + } + ], + "title": "The declaration of an object should contain no more than two levels of pointer indirection" + }, + "RULE-18-3-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Handlers for a function-try-block of a constructor or destructor shall not refer to non-static members from their class or its bases.", + "kind": "problem", + "name": "Handlers for a function-try-block of a constructor or destructor shall not refer to non-static", + "precision": "very-high", + "severity": "error", + "short_name": "HandlersReferToNonStaticMembersFromTheirClass", + "shared_implementation_short_name": "DestroyedValueReferencedInDestructorCatchBlock", + "tags": [ + "correctness", + "scope/single-translation-unit" + ] + } + ], + "title": "Handlers for a function-try-block of a constructor or destructor shall not refer to non-static members from their class or its bases" + }, + "RULE-19-0-3": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "Using anything other than other pre-processor directives or comments before an '#include' directive makes the code more difficult to read.", + "kind": "problem", + "name": "#include directives should only be preceded by preprocessor directives or comments", + "precision": "very-high", + "severity": "error", + "short_name": "IncludeDirectivesPrecededByPreprocessorDirectives", + "shared_implementation_short_name": "PreprocessorIncludesPreceded", + "tags": [ + "readability", + "scope/single-translation-unit" + ] + } + ], + "title": "#include directives should only be preceded by preprocessor directives or comments" + }, + "RULE-19-1-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "All identifiers used in the controlling expression of #if or #elif preprocessing directives shall be defined prior to evaluation.", + "kind": "problem", + "name": "All identifiers used in the controlling expression of #if or #elif preprocessing directives shall be", + "precision": "very-high", + "severity": "error", + "short_name": "IdentifiersUsedInTheControllingExpressionOf", + "shared_implementation_short_name": "UndefinedMacroIdentifiers", + "tags": [ + "correctness", + "readability", + "scope/single-translation-unit" + ] + } + ], + "title": "All identifiers used in the controlling expression of #if or #elif preprocessing directives shall be defined prior to evaluation" + }, + "RULE-19-2-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "The ' or \" or \\ characters and the /* or // character sequences shall not occur in a header file name.", + "kind": "problem", + "name": "The ' or \" or \\ characters and the /* or // character sequences shall not occur in a header file", + "precision": "very-high", + "severity": "error", + "short_name": "CharsThatShouldNotOccurInHeaderFileName", + "shared_implementation_short_name": "PreprocessorIncludesForbiddenHeaderNames", + "tags": [ + "scope/single-translation-unit", + "correctness" + ], + "implementation_scope": { + "description": "This query identifies the use of the ', \\, /*, // characters in header file names. The query is not able to detect the use of the \" character in header file names.", + "items": [] + } + } + ], + "title": "The ' or \" or \\ characters and the /* or // character sequences shall not occur in a header file name" + }, + "RULE-19-3-1": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "The order of evaluation for the '#' and '##' operators may differ between compilers, which can cause unexpected behaviour.", + "kind": "problem", + "name": "The # and ## preprocessor operators should not be used", + "precision": "very-high", + "severity": "error", + "short_name": "AndPreprocessorOperatorsShouldNotBeUsed", + "shared_implementation_short_name": "HashOperatorsUsed", + "tags": [ + "correctness", + "scope/single-translation-unit" + ] + } + ], + "title": "The # and ## preprocessor operators should not be used" + }, + "RULE-19-3-5": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Arguments to a function-like macro shall not contain tokens that look like pre-processing directives or else behaviour after macro expansion is unpredictable.", + "kind": "problem", + "name": "Tokens that look like a preprocessing directive shall not occur within a macro argument", + "precision": "very-high", + "severity": "error", + "short_name": "TokensThatLookLikeDirectivesInAMacroArgument", + "shared_implementation_short_name": "PreprocessingDirectiveWithinMacroArgument", + "tags": [ + "readability", + "correctness", + "scope/single-translation-unit" + ] + } + ], + "title": "Tokens that look like a preprocessing directive shall not occur within a macro argument" + }, + "RULE-21-6-5": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Do not delete pointers to incomplete classes to prevent undefined behavior.", + "kind": "problem", + "name": "A pointer to an incomplete class type shall not be deleted", + "precision": "very-high", + "severity": "error", + "short_name": "PointerToAnIncompleteClassTypeDeleted", + "shared_implementation_short_name": "DeleteOfPointerToIncompleteClass", + "tags": [ + "correctness", + "scope/single-translation-unit" + ] + } + ], + "title": "A pointer to an incomplete class type shall not be deleted" + }, + "RULE-25-5-2": { + "properties": { + "enforcement": "decidable", + "obligation": "mandatory" + }, + "queries": [ + { + "description": "The pointers returned by the C++ Standard Library functions localeconv, getenv, setlocale or strerror must only be used as if they have pointer to const-qualified type.", + "kind": "path-problem", + "name": "The pointers returned by environment functions should be treated as const", + "precision": "very-high", + "severity": "error", + "short_name": "PointersReturnedByLocaleFunctionsMustBeUsedAsConst", + "shared_implementation_short_name": "ConstLikeReturnValue", + "tags": [ + "correctness", + "scope/single-translation-unit" + ] + } + ], + "title": "The pointers returned by the C++ Standard Library functions localeconv, getenv, setlocale or strerror must only be used as if they have pointer to const-qualified type" + }, + "RULE-25-5-3": { + "properties": { + "enforcement": "undecidable", + "obligation": "mandatory" + }, + "queries": [ + { + "description": "The pointer returned by the Standard Library functions asctime, ctime, gmtime, localtime, localeconv, getenv, setlocale or strerror may be invalid following a subsequent call to the same function.", + "kind": "problem", + "name": "The pointer returned by the Standard Library env functions is invalid", + "precision": "very-high", + "severity": "error", + "short_name": "CallToSetlocaleInvalidatesOldPointersMisra", + "shared_implementation_short_name": "InvalidatedEnvStringPointers", + "tags": [ + "correctness", + "scope/system" + ] + }, + { + "description": "The pointer returned by the Standard Library functions asctime, ctime, gmtime, localtime, localeconv, getenv, setlocale or strerror may be invalid following a subsequent call to the same function.", + "kind": "problem", + "name": "The pointer returned by the Standard Library env functions is invalid warning", + "precision": "very-high", + "severity": "warning", + "short_name": "CallToSetlocaleInvalidatesOldPointersWarnMisra", + "shared_implementation_short_name": "InvalidatedEnvStringPointersWarn", + "tags": [ + "correctness", + "scope/system" + ] + } + ], + "title": "The pointer returned by the C++ Standard Library functions asctime, ctime, gmtime, localtime, localeconv, getenv, setlocale or strerror must not be used following a subsequent call to the same function" + }, + "RULE-28-6-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Moved-from object shall not be read-accessed.", + "kind": "problem", + "name": "An object shall not be used while in a potentially moved-from state", + "precision": "very-high", + "severity": "error", + "short_name": "ObjectUsedWhileInPotentiallyMovedFromState", + "shared_implementation_short_name": "MovedFromObjectsUnspecifiedState", + "tags": [ + "correctness", + "scope/single-translation-unit" + ] + } + ], + "title": "An object shall not be used while in a potentially moved-from state" + }, + "RULE-30-0-2": { + "properties": { + "enforcement": "undecidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Alternate input and output operations on a file stream shall not be used without an intervening flush or positioning call.", + "kind": "problem", + "name": "Reads and writes on the same file stream shall be separated by a positioning operation", + "precision": "very-high", + "severity": "error", + "short_name": "ReadsAndWritesOnStreamNotSeparatedByPositioning", + "shared_implementation_short_name": "IOFstreamMissingPositioning", + "tags": [ + "correctness", + "scope/system" + ], + "implementation_scope": { + "description": "The rule is enforced in the context of a single function." + } + } + ], + "title": "Reads and writes on the same file stream shall be separated by a positioning operation" + }, + "RULE-8-19-1": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "The comma operator should not be used.", + "kind": "problem", + "name": "The comma operator should not be used", + "precision": "very-high", + "severity": "error", + "short_name": "CommaOperatorShouldNotBeUsed", + "shared_implementation_short_name": "CommaOperatorUsed", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The comma operator should not be used" + }, + "DIR-15-8-1": { + "properties": { + "allocated-target": [ + "implementation" + ], + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "User-provided copy assignment operators and move assignment operators shall handle self-assignment.", + "kind": "problem", + "name": "User-provided copy assignment operators and move assignment operators shall handle self-assignment", + "precision": "very-high", + "severity": "error", + "short_name": "CopyAndMoveAssignmentsShallHandleSelfAssignment", + "shared_implementation_short_name": "CopyAndMoveAssignmentsShallHandleSelfAssignment", + "tags": [] + } + ], + "title": "User-provided copy assignment operators and move assignment operators shall handle self-assignment" + }, + "RULE-10-0-1": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "A declaration should not declare more than one variable or member variable.", + "kind": "problem", + "name": "Multiple declarations in the same local statement", + "precision": "very-high", + "severity": "recommendation", + "short_name": "UseSingleLocalDeclarators", + "shared_implementation_short_name": "MultipleLocalDeclarators", + "tags": [ + "readability", + "maintainability", + "scope/single-translation-unit" + ] + }, + { + "description": "A declaration should not declare more than one variable or member variable.", + "kind": "problem", + "name": "Multiple declarations in the same global or member declaration sequence", + "precision": "medium", + "severity": "recommendation", + "short_name": "UseSingleGlobalOrMemberDeclarators", + "shared_implementation_short_name": "MultipleGlobalOrMemberDeclarators", + "tags": [ + "readability", + "maintainability", + "scope/single-translation-unit" + ] + } + ], + "title": "A declaration should not declare more than one variable or member variable" + }, + "RULE-10-2-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "An enumeration shall be defined with an explicit underlying type.", + "kind": "problem", + "name": "An enumeration shall be defined with an explicit underlying type", + "precision": "very-high", + "severity": "error", + "short_name": "EnumerationNotDefinedWithAnExplicitUnderlyingType", + "shared_implementation_short_name": "EnumerationNotDefinedWithAnExplicitUnderlyingType", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "An enumeration shall be defined with an explicit underlying type" + }, + "RULE-10-4-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "The asm declaration shall not be used.", + "kind": "problem", + "name": "The asm declaration shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "AsmDeclarationShallNotBeUsed", + "shared_implementation_short_name": "AsmDeclarationUsed", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The asm declaration shall not be used" + }, + "RULE-11-6-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Within an enumerator list, the value of an implicitly-specified enumeration constant shall be unique.", + "kind": "problem", + "name": "Within an enumerator list, the value of an implicitly-specified enumeration constant shall be unique", + "precision": "very-high", + "severity": "error", + "short_name": "NonUniqueEnumerationConstant", + "shared_implementation_short_name": "NonUniqueEnumerationConstant", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "Within an enumerator list, the value of an implicitly-specified enumeration constant shall be unique" + }, + "RULE-12-2-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "A bit-field shall have an appropriate type.", + "kind": "problem", + "name": "A bit-field shall have an appropriate type", + "precision": "very-high", + "severity": "error", + "short_name": "BitFieldShallHaveAnAppropriateType", + "shared_implementation_short_name": "BitFieldShallHaveAnAppropriateType", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "A bit-field shall have an appropriate type" + }, + "RULE-12-2-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "A named bit-field with signed integer type shall not have a length of one bit.", + "kind": "problem", + "name": "A named bit-field with signed integer type shall not have a length of one bit", + "precision": "very-high", + "severity": "error", + "short_name": "SignedIntegerNamedBitFieldHaveALengthOfOneBit", + "shared_implementation_short_name": "NamedBitFieldsWithSignedIntegerType", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "A named bit-field with signed integer type shall not have a length of one bit" + }, + "RULE-13-1-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "An accessible base class shall not be both virtual and non-virtual in the same hierarchy.", + "kind": "problem", + "name": "An accessible base class shall not be both virtual and non-virtual in the same hierarchy", + "precision": "very-high", + "severity": "error", + "short_name": "VirtualAndNonVirtualClassInTheHierarchy", + "shared_implementation_short_name": "VirtualAndNonVirtualClassInTheHierarchy", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "An accessible base class shall not be both virtual and non-virtual in the same hierarchy" + }, + "RULE-13-3-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Parameters in an overriding virtual function shall not specify different default arguments.", + "kind": "problem", + "name": "Parameters in an overriding virtual function shall not specify different default arguments", + "precision": "very-high", + "severity": "error", + "short_name": "OverridingShallSpecifyDifferentDefaultArguments", + "shared_implementation_short_name": "OverridingShallSpecifyDifferentDefaultArguments", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "Parameters in an overriding virtual function shall not specify different default arguments" + }, + "RULE-13-3-4": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "A comparison of a potentially virtual pointer to member function shall only be with nullptr.", + "kind": "problem", + "name": "A comparison of a potentially virtual pointer to member function shall only be with nullptr", + "precision": "very-high", + "severity": "error", + "short_name": "PotentiallyVirtualPointerOnlyComparesToNullptr", + "shared_implementation_short_name": "PotentiallyVirtualPointerOnlyComparesToNullptr", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "A comparison of a potentially virtual pointer to member function shall only be with nullptr" + }, + "RULE-15-1-1": { + "properties": { + "enforcement": "undecidable", + "obligation": "required" + }, + "queries": [ + { + "description": "An object\u2019s dynamic type shall not be used from within its constructor or destructor.", + "kind": "problem", + "name": "An object\u2019s dynamic type shall not be used from within its constructor or destructor", + "precision": "very-high", + "severity": "error", + "short_name": "ObjectsDynamicTypeUsedFromConstructorOrDestructor", + "shared_implementation_short_name": "ObjectsDynamicTypeUsedFromConstructorOrDestructor", + "tags": [ + "scope/system" + ] + } + ], + "title": "An object\u2019s dynamic type shall not be used from within its constructor or destructor" + }, + "RULE-15-1-2": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "All constructors of a class should explicitly initialize all of its virtual base classes and immediate base classes.", + "kind": "problem", + "name": "All constructors of a class should explicitly initialize all of its virtual base classes and", + "precision": "very-high", + "severity": "error", + "short_name": "InitializeAllVirtualBaseClasses", + "shared_implementation_short_name": "InitializeAllVirtualBaseClasses", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "All constructors of a class should explicitly initialize all of its virtual base classes and immediate base classes" + }, + "RULE-15-1-5": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "A class shall only define an initializer-list constructor when it is the only constructor.", + "kind": "problem", + "name": "A class shall only define an initializer-list constructor when it is the only constructor", + "precision": "very-high", + "severity": "error", + "short_name": "InitializerListConstructorIsTheOnlyConstructor", + "shared_implementation_short_name": "InitializerListConstructorIsTheOnlyConstructor", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "A class shall only define an initializer-list constructor when it is the only constructor" + }, + "RULE-16-5-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "The address-of operator shall not be overloaded.", + "kind": "problem", + "name": "The address-of operator shall not be overloaded", + "precision": "very-high", + "severity": "error", + "short_name": "AddressOfOperatorOverloaded", + "shared_implementation_short_name": "AddressOfOperatorOverloaded", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The address-of operator shall not be overloaded" + }, + "RULE-17-8-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Function templates shall not be explicitly specialized.", + "kind": "problem", + "name": "Function templates shall not be explicitly specialized", + "precision": "very-high", + "severity": "error", + "short_name": "FunctionTemplatesExplicitlySpecialized", + "shared_implementation_short_name": "FunctionTemplatesExplicitlySpecialized", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "Function templates shall not be explicitly specialized" + }, + "RULE-18-1-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "An exception object shall not have pointer type.", + "kind": "problem", + "name": "An exception object shall not have pointer type", + "precision": "very-high", + "severity": "error", + "short_name": "ExceptionObjectHavePointerType", + "shared_implementation_short_name": "ExceptionObjectHavePointerType", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "An exception object shall not have pointer type" + }, + "RULE-18-1-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "An empty throw shall only occur within the compound-statement of a catch handler.", + "kind": "problem", + "name": "An empty throw shall only occur within the compound-statement of a catch handler", + "precision": "very-high", + "severity": "error", + "short_name": "EmptyThrowOnlyWithinACatchHandler", + "shared_implementation_short_name": "EmptyThrowOnlyWithinACatchHandler", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "An empty throw shall only occur within the compound-statement of a catch handler" + }, + "RULE-18-5-1": { + "properties": { + "enforcement": "undecidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "A noexcept function should not attempt to propagate an exception to the calling function.", + "kind": "path-problem", + "name": "A noexcept function should not attempt to propagate an exception to the calling function", + "precision": "very-high", + "severity": "error", + "short_name": "NoexceptFunctionShouldNotPropagateToTheCaller", + "shared_implementation_short_name": "NoexceptFunctionShouldNotPropagateToTheCaller", + "tags": [ + "scope/system" + ] + } + ], + "title": "A noexcept function should not attempt to propagate an exception to the calling function" + }, + "RULE-19-0-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Function-like macros shall not be defined.", + "kind": "problem", + "name": "Function-like macros shall not be defined", + "precision": "very-high", + "severity": "error", + "short_name": "FunctionLikeMacrosDefined", + "shared_implementation_short_name": "FunctionLikeMacrosDefined", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "Function-like macros shall not be defined" + }, + "RULE-19-3-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "A macro parameter immediately following a # operator shall not be immediately followed by a ## operator.", + "kind": "problem", + "name": "A macro parameter immediately following a # operator shall not be immediately followed by a ##", + "precision": "very-high", + "severity": "error", + "short_name": "MacroParameterFollowingHash", + "shared_implementation_short_name": "MacroParameterFollowingHash", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "A macro parameter immediately following a # operator shall not be immediately followed by a ## operator" + }, + "RULE-19-3-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "The argument to a mixed-use macro parameter shall not be subject to further expansion.", + "kind": "problem", + "name": "The argument to a mixed-use macro parameter shall not be subject to further expansion", + "precision": "very-high", + "severity": "error", + "short_name": "AMixedUseMacroArgumentSubjectToExpansion", + "shared_implementation_short_name": "AMixedUseMacroArgumentSubjectToExpansion", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The argument to a mixed-use macro parameter shall not be subject to further expansion" + }, + "RULE-21-10-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Signal handling contains implementation-defined and undefined behaviour.", + "kind": "problem", + "name": "The facilities provided by the standard header file shall not be used", + "precision": "very-high", + "severity": "warning", + "short_name": "CsignalFacilitiesUsed", + "shared_implementation_short_name": "CsignalFunctionsUsed", + "tags": [ + "maintainability", + "correctness", + "scope/single-translation-unit" + ] + }, + { + "description": "The types provided by the standard header file shall not be used.", + "kind": "problem", + "name": "The signal-handling types of shall not be used", + "precision": "very-high", + "severity": "warning", + "short_name": "CsignalTypesShallNotBeUsed", + "shared_implementation_short_name": "CsignalTypesUsed", + "tags": [ + "maintainability", + "correctness", + "scope/single-translation-unit" + ] + } + ], + "title": "The facilities provided by the standard header file shall not be used" + }, + "RULE-21-2-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "The library functions atof, atoi, atol and atoll from shall not be used.", + "kind": "problem", + "name": "The library functions atof, atoi, atol and atoll from shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "AtofAtoiAtolAndAtollUsed", + "shared_implementation_short_name": "AtofAtoiAtolAndAtollUsed", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The library functions atof, atoi, atol and atoll from shall not be used" + }, + "RULE-21-2-4": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "The macro offsetof shall not be used.", + "kind": "problem", + "name": "The macro offsetof shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "MacroOffsetofShallNotBeUsed", + "shared_implementation_short_name": "MacroOffsetofUsed", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The macro offsetof shall not be used" + }, + "RULE-21-6-4": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "If a project defines the unsized version of a global operator delete, then the sized version shall be defined.", + "kind": "problem", + "name": "Sized 'operator delete' must be defined globally if unsized 'operator delete' is defined globally", + "precision": "very-high", + "severity": "error", + "short_name": "GlobalSizedOperatorDeleteShallBeDefined", + "shared_implementation_short_name": "GlobalSizedOperatorDeleteNotDefined", + "tags": [ + "maintainability", + "scope/system" + ] + }, + { + "description": "If a project defines the sized version of a global operator delete, then the unsized version shall be defined.", + "kind": "problem", + "name": "Unsized 'operator delete' must be defined globally if sized 'operator delete' is defined globally", + "precision": "very-high", + "severity": "error", + "short_name": "GlobalUnsizedOperatorDeleteShallBeDefined", + "shared_implementation_short_name": "GlobalUnsizedOperatorDeleteNotDefined", + "tags": [ + "maintainability", + "scope/system" + ] + } + ], + "title": "If a project defines either a sized or unsized version of a global operator delete, then both shall be defined" + }, + "RULE-26-3-1": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "std::vector should not be specialized with bool.", + "kind": "problem", + "name": "std::vector should not be specialized with bool", + "precision": "very-high", + "severity": "error", + "short_name": "VectorShouldNotBeSpecializedWithBool", + "shared_implementation_short_name": "VectorShouldNotBeSpecializedWithBool", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "std::vector should not be specialized with bool" + }, + "RULE-28-6-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Forwarding references and std::forward shall be used together.", + "kind": "problem", + "name": "Forwarding references and std::forward shall be used together", + "precision": "very-high", + "severity": "error", + "short_name": "ForwardingReferencesAndForwardNotUsedTogether", + "shared_implementation_short_name": "ForwardingReferencesAndForwardNotUsedTogether", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "Forwarding references and std::forward shall be used together" + }, + "RULE-30-0-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "The C Library input/output functions shall not be used.", + "kind": "problem", + "name": "The stream input/output library functions shall not be used", + "precision": "very-high", + "severity": "warning", + "short_name": "CstdioFunctionsShallNotBeUsed", + "shared_implementation_short_name": "CstdioFunctionsUsed", + "tags": [ + "maintainability", + "correctness", + "scope/single-translation-unit" + ] + }, + { + "description": "The C Library input/output functions shall not be used.", + "kind": "problem", + "name": "The stream input/output library macros shall not be used", + "precision": "very-high", + "severity": "warning", + "short_name": "CstdioMacrosShallNotBeUsed", + "shared_implementation_short_name": "CstdioMacrosUsed", + "tags": [ + "maintainability", + "correctness", + "scope/single-translation-unit" + ] + }, + { + "description": "The C Library input/output functions shall not be used.", + "kind": "problem", + "name": "The stream input/output library types shall not be used", + "precision": "very-high", + "severity": "warning", + "short_name": "CstdioTypesShallNotBeUsed", + "shared_implementation_short_name": "CstdioTypesUsed", + "tags": [ + "maintainability", + "correctness", + "scope/single-translation-unit" + ] + } + ], + "title": "The C Library input/output functions shall not be used" + }, + "RULE-5-13-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "In character literals and non-raw string literals, \\ shall only be used to form a defined escape sequence or universal character name.", + "kind": "problem", + "name": "In character literals and non-raw string literals, \\ shall only be used to form a defined escape", + "precision": "very-high", + "severity": "error", + "short_name": "BackslashCharacterMisuse", + "shared_implementation_short_name": "BackslashCharacterMisuse", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "In character literals and non-raw string literals, \\ shall only be used to form a defined escape sequence or universal character name" + }, + "RULE-5-13-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Octal escape sequences, hexadecimal escape sequences, and universal character names shall be terminated.", + "kind": "problem", + "name": "Octal escape sequences, hexadecimal escape sequences, and universal character names shall be", + "precision": "very-high", + "severity": "error", + "short_name": "NonTerminatedEscapeSequences", + "shared_implementation_short_name": "NonTerminatedEscapeSequences", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "Octal escape sequences, hexadecimal escape sequences, and universal character names shall be terminated" + }, + "RULE-5-13-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Octal constants shall not be used.", + "kind": "problem", + "name": "Octal constants shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "OctalConstantsUsed", + "shared_implementation_short_name": "UseOfNonZeroOctalLiteral", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "Octal constants shall not be used" + }, + "RULE-5-13-4": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Unsigned integer literals shall be appropriately suffixed.", + "kind": "problem", + "name": "Unsigned integer literals shall be appropriately suffixed", + "precision": "very-high", + "severity": "error", + "short_name": "UnsignedIntegerLiteralsNotAppropriatelySuffixed", + "shared_implementation_short_name": "UnsignedIntegerLiteralsNotAppropriatelySuffixed", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "Unsigned integer literals shall be appropriately suffixed" + }, + "RULE-5-13-5": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "The lowercase form of L shall not be used as the first character in a literal suffix.", + "kind": "problem", + "name": "The lowercase form of L shall not be used as the first character in a literal suffix", + "precision": "very-high", + "severity": "error", + "short_name": "LowercaseLStartsInLiteralSuffix", + "shared_implementation_short_name": "LowercaseLStartsInLiteralSuffix", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The lowercase form of L shall not be used as the first character in a literal suffix" + }, + "RULE-5-7-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "The character sequence /* shall not be used within a C-style comment.", + "kind": "problem", + "name": "The character sequence /* shall not be used within a C-style comment", + "precision": "very-high", + "severity": "error", + "short_name": "CharacterSequenceUsedWithinACStyleComment", + "shared_implementation_short_name": "CharacterSequenceUsedWithinACStyleComment", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The character sequence /* shall not be used within a C-style comment" + }, + "RULE-5-7-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Line-splicing shall not be used in // comments.", + "kind": "problem", + "name": "Line-splicing shall not be used in // comments", + "precision": "very-high", + "severity": "error", + "short_name": "LineSplicingUsedInComments", + "shared_implementation_short_name": "LineSplicingUsedInComments", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "Line-splicing shall not be used in // comments" + }, + "RULE-6-0-3": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "The only declarations in the global namespace should be main, namespace declarations and extern \"C\" declarations.", + "kind": "problem", + "name": "The only declarations in the global namespace should be main, namespace declarations and extern \"C\"", + "precision": "very-high", + "severity": "error", + "short_name": "GlobalNamespaceDeclarations", + "shared_implementation_short_name": "GlobalNamespaceDeclarations", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The only declarations in the global namespace should be main, namespace declarations and extern \"C\" declarations" + }, + "RULE-6-0-4": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "The identifier main shall not be used for a function other than the global function main.", + "kind": "problem", + "name": "The identifier main shall not be used for a function other than the global function main", + "precision": "very-high", + "severity": "error", + "short_name": "NonGlobalFunctionMain", + "shared_implementation_short_name": "NonGlobalFunctionMain", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The identifier main shall not be used for a function other than the global function main" + }, + "RULE-6-4-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "A non-overriding member function definition that hides an inherited member function can result in unexpected behavior.", + "kind": "problem", + "name": "Member function hides inherited member function", + "precision": "very-high", + "severity": "error", + "short_name": "InheritedNonOverridableMemberFunction", + "shared_implementation_short_name": "HiddenInheritedNonOverridableMemberFunction", + "tags": [ + "correctness", + "scope/single-translation-unit" + ] + }, + { + "description": "An overriding member function definition thats hides an overload of the overridden inherited member function can result in unexpected behavior.", + "kind": "problem", + "name": "Member function hides inherited member function", + "precision": "very-high", + "severity": "error", + "short_name": "InheritedOverridableMemberFunction", + "shared_implementation_short_name": "HiddenInheritedOverridableMemberFunction", + "tags": [ + "correctness", + "scope/single-translation-unit" + ] + }, + { + "description": "A using declaration that makes a symbol available for unqualified lookup does not included definitions defined after the using declaration which can result in unexpected behavior.", + "kind": "problem", + "name": "Using declaration followed by new definition", + "precision": "very-high", + "severity": "error", + "short_name": "DefinitionShallBeConsideredForUnqualifiedLookup", + "shared_implementation_short_name": "DefinitionNotConsideredForUnqualifiedLookup", + "tags": [ + "correctness", + "scope/single-translation-unit" + ] + } + ], + "title": "Derived classes shall not conceal functions that are inherited from their bases" + }, + "RULE-6-4-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Not using a qualified-id or `this->` syntax for identifiers used in a class template makes the code more difficult to understand.", + "kind": "problem", + "name": "In a class template with a dependent base, any name that may be found in that dependent base shall shall be referred to using a qualified-id or this->", + "precision": "very-high", + "severity": "warning", + "short_name": "NameShallBeReferredUsingAQualifiedIdOrThis", + "shared_implementation_short_name": "NameNotReferredUsingAQualifiedIdOrThis", + "tags": [ + "maintainability", + "readability", + "scope/single-translation-unit" + ] + }, + { + "description": "Not using a qualified-id or `this->` syntax for identifiers used in a class template makes the code more difficult to understand.", + "kind": "problem", + "name": "(Audit) In a class template with a dependent base, any name that may be found in that dependent base shall shall be referred to using a qualified-id or this->", + "precision": "very-high", + "severity": "warning", + "short_name": "NameShallBeReferredUsingAQualifiedIdOrThisAudit", + "shared_implementation_short_name": "NameNotReferredUsingAQualifiedIdOrThisAudit", + "tags": [ + "maintainability", + "readability", + "scope/single-translation-unit" + ] + } + ], + "title": "A name that is present in a dependent base shall not be resolved by unqualified lookup" + }, + "RULE-6-8-2": { + "properties": { + "enforcement": "decidable", + "obligation": "mandatory" + }, + "queries": [ + { + "description": "A function must not return a reference or a pointer to a local variable with automatic storage duration.", + "kind": "problem", + "name": "A function must not return a reference or a pointer to a local variable with automatic storage", + "precision": "very-high", + "severity": "error", + "short_name": "ReturnReferenceOrPointerToAutomaticLocalVariable", + "shared_implementation_short_name": "ReturnReferenceOrPointerToAutomaticLocalVariable", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "A function must not return a reference or a pointer to a local variable with automatic storage duration" + }, + "RULE-7-11-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "nullptr shall be the only form of the null-pointer-constant.", + "kind": "problem", + "name": "nullptr shall be the only form of the null-pointer-constant", + "precision": "very-high", + "severity": "error", + "short_name": "NullptrNotTheOnlyFormOfTheNullPointerConstant", + "shared_implementation_short_name": "NullptrNotTheOnlyFormOfTheNullPointerConstant", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "nullptr shall be the only form of the null-pointer-constant" + }, + "RULE-7-11-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "An array passed as a function argument shall not decay to a pointer.", + "kind": "problem", + "name": "An array passed as a function argument shall not decay to a pointer", + "precision": "very-high", + "severity": "error", + "short_name": "ArrayPassedAsFunctionArgumentDecayToAPointer", + "shared_implementation_short_name": "ArrayPassedAsFunctionArgumentDecayToAPointer", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "An array passed as a function argument shall not decay to a pointer" + }, + "RULE-8-18-2": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "The result of an assignment operator should not be used.", + "kind": "problem", + "name": "The result of an assignment operator should not be used", + "precision": "very-high", + "severity": "error", + "short_name": "ResultOfAnAssignmentOperatorShouldNotBeUsed", + "shared_implementation_short_name": "ResultOfAnAssignmentOperatorShouldNotBeUsed", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The result of an assignment operator should not be used" + }, + "RULE-8-2-10": { + "properties": { + "enforcement": "undecidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Functions shall not call themselves, either directly or indirectly.", + "kind": "problem", + "name": "Functions shall not call themselves, either directly or indirectly", + "precision": "very-high", + "severity": "error", + "short_name": "FunctionsCallThemselvesEitherDirectlyOrIndirectly", + "shared_implementation_short_name": "FunctionsCallThemselvesEitherDirectlyOrIndirectly", + "tags": [ + "scope/system" + ] + } + ], + "title": "Functions shall not call themselves, either directly or indirectly" + }, + "RULE-8-2-4": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Casts shall not be performed between a pointer to function and any other type.", + "kind": "problem", + "name": "Casts shall not be performed between a pointer to function and any other type", + "precision": "very-high", + "severity": "error", + "short_name": "CastsBetweenAPointerToFunctionAndAnyOtherType", + "shared_implementation_short_name": "CastsBetweenAPointerToFunctionAndAnyOtherType", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "Casts shall not be performed between a pointer to function and any other type" + }, + "RULE-8-2-5": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "reinterpret_cast shall not be used.", + "kind": "problem", + "name": "reinterpret_cast shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "ReinterpretCastShallNotBeUsed", + "shared_implementation_short_name": "ReinterpretCastUsed", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "reinterpret_cast shall not be used" + }, + "RULE-8-20-1": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "An unsigned arithmetic operation with constant operands should not wrap.", + "kind": "problem", + "name": "An unsigned arithmetic operation with constant operands should not wrap", + "precision": "very-high", + "severity": "error", + "short_name": "UnsignedOperationWithConstantOperandsWraps", + "shared_implementation_short_name": "UnsignedOperationWithConstantOperandsWraps", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "An unsigned arithmetic operation with constant operands should not wrap" + }, + "RULE-8-3-1": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "The built-in unary - operator should not be applied to an expression of unsigned type.", + "kind": "problem", + "name": "The built-in unary - operator should not be applied to an expression of unsigned type", + "precision": "very-high", + "severity": "error", + "short_name": "BuiltInUnaryOperatorAppliedToUnsignedExpression", + "shared_implementation_short_name": "BuiltInUnaryOperatorAppliedToUnsignedExpression", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The built-in unary - operator should not be applied to an expression of unsigned type" + }, + "RULE-9-3-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "If the body of a switch is not enclosed in braces, then this can lead to incorrect execution, and hard for developers to maintain.", + "kind": "problem", + "name": "The statement forming the body of a switch shall be a compound statement", + "precision": "very-high", + "severity": "recommendation", + "short_name": "SwitchBodyCompoundCondition", + "shared_implementation_short_name": "SwitchCompoundCondition", + "tags": [ + "maintainability", + "readability", + "scope/single-translation-unit" + ] + }, + { + "description": "If the body of a loop is not enclosed in braces, then this can lead to incorrect execution, and hard for developers to maintain.", + "kind": "problem", + "name": "The statement forming the body of a loop shall be a compound statement", + "precision": "very-high", + "severity": "recommendation", + "short_name": "LoopBodyCompoundCondition", + "shared_implementation_short_name": "LoopCompoundCondition", + "tags": [ + "maintainability", + "readability", + "scope/single-translation-unit" + ] + } + ], + "title": "The body of an iteration-statement or a selection-statement shall be a compound-statement" + }, + "RULE-9-6-1": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "The goto statement should not be used.", + "kind": "problem", + "name": "The goto statement should not be used", + "precision": "very-high", + "severity": "error", + "short_name": "GotoStatementShouldNotBeUsed", + "shared_implementation_short_name": "GotoStatementShouldNotBeUsed", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The goto statement should not be used" + }, + "RULE-9-6-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "A goto statement shall reference a label in a surrounding block.", + "kind": "problem", + "name": "A goto statement shall reference a label in a surrounding block", + "precision": "very-high", + "severity": "error", + "short_name": "GotoReferenceALabelInSurroundingBlock", + "shared_implementation_short_name": "GotoReferenceALabelInSurroundingBlock", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "A goto statement shall reference a label in a surrounding block" + } + } +} \ No newline at end of file diff --git a/rule_packages/cpp/Inheritance.json b/rule_packages/cpp/Inheritance.json index 55175e0013..fc4805fc21 100644 --- a/rule_packages/cpp/Inheritance.json +++ b/rule_packages/cpp/Inheritance.json @@ -145,6 +145,7 @@ "precision": "very-high", "severity": "warning", "short_name": "AccessibleBaseClassBothVirtualAndNonVirtualInHierarchy", + "shared_implementation_short_name": "VirtualAndNonVirtualClassInTheHierarchy", "tags": [] } ], @@ -187,6 +188,7 @@ "precision": "very-high", "severity": "error", "short_name": "DynamicTypeOfThisUsedFromConstructorOrDestructor", + "shared_implementation_short_name": "ObjectsDynamicTypeUsedFromConstructorOrDestructor", "tags": [] } ], @@ -227,7 +229,13 @@ "precision": "very-high", "severity": "error", "short_name": "DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors", - "tags": [] + "tags": [ + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" + ] } ], "title": "Do not invoke virtual functions from constructors or destructors" @@ -244,7 +252,13 @@ "precision": "very-high", "severity": "error", "short_name": "DoNotSliceDerivedObjects", - "tags": [] + "tags": [ + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" + ] } ], "title": "Do not slice derived objects" @@ -261,7 +275,13 @@ "precision": "very-high", "severity": "warning", "short_name": "DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor", - "tags": [] + "tags": [ + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p9", + "external/cert/level/l2" + ] } ], "title": "Do not delete a polymorphic object without a virtual destructor" diff --git a/rule_packages/cpp/Initialization.json b/rule_packages/cpp/Initialization.json index da2ed53c98..e81160a273 100644 --- a/rule_packages/cpp/Initialization.json +++ b/rule_packages/cpp/Initialization.json @@ -16,6 +16,7 @@ "precision": "very-high", "severity": "warning", "short_name": "ExplicitConstructorBaseClassInitialization", + "shared_implementation_short_name": "InitializeAllVirtualBaseClasses", "tags": [ "maintainability", "correctness" @@ -304,6 +305,7 @@ "precision": "very-high", "severity": "recommendation", "short_name": "ConfusingUseOfInitializerListConstructors", + "shared_implementation_short_name": "InitializerListConstructorIsTheOnlyConstructor", "tags": [ "readability", "maintainability" @@ -328,6 +330,7 @@ "precision": "very-high", "severity": "recommendation", "short_name": "MultipleLocalDeclarators", + "shared_implementation_short_name": "MultipleLocalDeclarators", "tags": [ "readability", "maintainability" @@ -340,6 +343,7 @@ "precision": "medium", "severity": "recommendation", "short_name": "MultipleGlobalOrMemberDeclarators", + "shared_implementation_short_name": "MultipleGlobalOrMemberDeclarators", "tags": [ "readability", "maintainability" @@ -413,7 +417,12 @@ "short_name": "CyclesDuringStaticObjectInit", "tags": [ "correctness", - "maintainability" + "maintainability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -433,7 +442,12 @@ "short_name": "BadlySeededRandomNumberGenerator", "tags": [ "security", - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -456,7 +470,12 @@ "correctness", "security", "maintainability", - "readability" + "readability", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/Invariants.json b/rule_packages/cpp/Invariants.json index b473fb499d..215e4edff4 100644 --- a/rule_packages/cpp/Invariants.json +++ b/rule_packages/cpp/Invariants.json @@ -63,7 +63,12 @@ "shared_implementation_short_name": "OrderingPredicateMustBeStrictlyWeak", "short_name": "ProvideAValidOrderingPredicate", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -82,7 +87,12 @@ "severity": "error", "short_name": "SignalHandlerMustBeAPlainOldFunction", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -101,7 +111,12 @@ "severity": "error", "short_name": "HonorTerminationReplacementHandlerRequirements", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p2", + "external/cert/level/l3" ] }, { @@ -112,7 +127,12 @@ "severity": "error", "short_name": "HonorNewReplacementHandlerRequirements", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/Iterators.json b/rule_packages/cpp/Iterators.json index a43740f7e7..c345adb371 100644 --- a/rule_packages/cpp/Iterators.json +++ b/rule_packages/cpp/Iterators.json @@ -61,7 +61,12 @@ "severity": "error", "short_name": "UsesValidContainerElementAccess", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -80,7 +85,12 @@ "severity": "error", "short_name": "UseValidIteratorRanges", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -99,7 +109,12 @@ "severity": "error", "short_name": "DoNotSubtractIteratorsForDifferentContainers", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -118,7 +133,12 @@ "severity": "error", "short_name": "DoNotUseAnAdditiveOperatorOnAnIterator", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -138,7 +158,12 @@ "severity": "error", "short_name": "UseValidReferencesForElementsOfString", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/Lambdas.json b/rule_packages/cpp/Lambdas.json index ea43fa0231..8f973c361f 100644 --- a/rule_packages/cpp/Lambdas.json +++ b/rule_packages/cpp/Lambdas.json @@ -205,7 +205,12 @@ "shared_implementation_short_name": "DanglingCaptureWhenReturningLambdaObject", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] }, { @@ -218,7 +223,12 @@ "shared_implementation_short_name": "DanglingCaptureWhenMovingLambdaObject", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/Literals.json b/rule_packages/cpp/Literals.json index e762a9c411..7721b7dd6a 100644 --- a/rule_packages/cpp/Literals.json +++ b/rule_packages/cpp/Literals.json @@ -39,6 +39,7 @@ "precision": "very-high", "severity": "error", "short_name": "EscapeSequenceOutsideISO", + "shared_implementation_short_name": "BackslashCharacterMisuse", "tags": [ "correctness" ] @@ -85,6 +86,7 @@ "precision": "very-high", "severity": "recommendation", "short_name": "NullPointerConstantNotNullptr", + "shared_implementation_short_name": "NullptrNotTheOnlyFormOfTheNullPointerConstant", "tags": [ "readability" ] @@ -132,6 +134,7 @@ "precision": "very-high", "severity": "recommendation", "short_name": "UseOfNonZeroOctalLiteral", + "shared_implementation_short_name": "UseOfNonZeroOctalLiteral", "tags": [ "readability" ] @@ -166,6 +169,7 @@ "precision": "very-high", "severity": "warning", "short_name": "MissingUSuffix", + "shared_implementation_short_name": "UnsignedIntegerLiteralsNotAppropriatelySuffixed", "tags": [ "correctness", "readability" diff --git a/rule_packages/cpp/MoveForward.json b/rule_packages/cpp/MoveForward.json index 6278135d2c..6f071a6f53 100644 --- a/rule_packages/cpp/MoveForward.json +++ b/rule_packages/cpp/MoveForward.json @@ -40,6 +40,7 @@ "precision": "very-high", "severity": "error", "short_name": "ForwardingValuesToOtherFunctions", + "shared_implementation_short_name": "ForwardingReferencesAndForwardNotUsedTogether", "tags": [ "correctness" ] @@ -153,7 +154,12 @@ "short_name": "DoNotRelyOnTheValueOfAMovedFromObject", "shared_implementation_short_name": "MovedFromObjectsUnspecifiedState", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/Naming.json b/rule_packages/cpp/Naming.json index e59f007975..34a9f2c66e 100644 --- a/rule_packages/cpp/Naming.json +++ b/rule_packages/cpp/Naming.json @@ -290,7 +290,7 @@ "precision": "very-high", "severity": "recommendation", "short_name": "DifferentIdentifiersNotTypographicallyUnambiguous", - "shared_implementation_short_name" : "DifferentIdentifiersNotTypographicallyUnambiguous", + "shared_implementation_short_name": "DifferentIdentifiersNotTypographicallyUnambiguous", "tags": [ "readability", "maintainability" @@ -314,6 +314,7 @@ "precision": "very-high", "severity": "warning", "short_name": "IdentifierMainUsedForAFunctionOtherThanTheGlobalFunctionMain", + "shared_implementation_short_name": "NonGlobalFunctionMain", "tags": [ "maintainability", "readability" @@ -381,7 +382,12 @@ "severity": "error", "short_name": "RedefiningOfStandardLibraryName", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -391,7 +397,12 @@ "severity": "error", "short_name": "ReuseOfReservedIdentifier", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -402,7 +413,12 @@ "short_name": "UseOfSingleUnderscoreReservedPrefix", "tags": [ "maintainability", - "readability" + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -413,7 +429,12 @@ "short_name": "UseOfDoubleUnderscoreReservedPrefix", "tags": [ "maintainability", - "readability" + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -425,7 +446,12 @@ "tags": [ "maintainability", "readability", - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -437,7 +463,12 @@ "tags": [ "maintainability", "readability", - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -449,7 +480,12 @@ "tags": [ "maintainability", "readability", - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -461,7 +497,12 @@ "tags": [ "maintainability", "readability", - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/Null.json b/rule_packages/cpp/Null.json index a5410840ce..543552660c 100644 --- a/rule_packages/cpp/Null.json +++ b/rule_packages/cpp/Null.json @@ -63,7 +63,12 @@ "severity": "error", "short_name": "DoNotAttemptToCreateAStringFromANullPointer", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], diff --git a/rule_packages/cpp/OperatorInvariants.json b/rule_packages/cpp/OperatorInvariants.json index b34df998e9..5eaefd68c8 100644 --- a/rule_packages/cpp/OperatorInvariants.json +++ b/rule_packages/cpp/OperatorInvariants.json @@ -39,6 +39,7 @@ "precision": "very-high", "severity": "error", "short_name": "CopyAssignmentAndAMoveHandleSelfAssignment", + "shared_implementation_short_name": "CopyAndMoveAssignmentsShallHandleSelfAssignment", "tags": [ "correctness" ] @@ -176,7 +177,12 @@ "severity": "error", "short_name": "GracefullyHandleSelfCopyAssignment", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -195,7 +201,12 @@ "severity": "error", "short_name": "CopyOperationsMustNotMutateTheSourceObject", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/Operators.json b/rule_packages/cpp/Operators.json index 8bb2cb9d55..76be8a732a 100644 --- a/rule_packages/cpp/Operators.json +++ b/rule_packages/cpp/Operators.json @@ -297,6 +297,7 @@ "precision": "very-high", "severity": "error", "short_name": "UnaryMinusOperatorAppliedToAnExpressionWhoseUnderlyingTypeIsUnsigned", + "shared_implementation_short_name": "BuiltInUnaryOperatorAppliedToUnsignedExpression", "tags": [] } ], @@ -318,6 +319,7 @@ "precision": "very-high", "severity": "error", "short_name": "UnaryOperatorOverloaded", + "shared_implementation_short_name": "AddressOfOperatorOverloaded", "tags": [] } ], diff --git a/rule_packages/cpp/OutOfBounds.json b/rule_packages/cpp/OutOfBounds.json index a3cb8fbf91..2a657df95c 100644 --- a/rule_packages/cpp/OutOfBounds.json +++ b/rule_packages/cpp/OutOfBounds.json @@ -42,7 +42,12 @@ "shared_implementation_short_name": "ContainerAccessWithoutRangeCheck", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/high", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], @@ -62,7 +67,12 @@ "short_name": "GuaranteeGenericCppLibraryFunctionsDoNotOverflow", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -82,7 +92,12 @@ "short_name": "RangeCheckStringElementAccess", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/Pointers.json b/rule_packages/cpp/Pointers.json index 6a862e057c..3815ba521c 100644 --- a/rule_packages/cpp/Pointers.json +++ b/rule_packages/cpp/Pointers.json @@ -87,6 +87,7 @@ "precision": "very-high", "severity": "error", "short_name": "PointerToMemberVirtualFunctionWithNullPointerConstant", + "shared_implementation_short_name": "PotentiallyVirtualPointerOnlyComparesToNullptr", "tags": [ "correctness" ] @@ -279,6 +280,7 @@ "precision": "very-high", "severity": "warning", "short_name": "IdentifierWithArrayTypePassedAsFunctionArgumentDecayToAPointer", + "shared_implementation_short_name": "ArrayPassedAsFunctionArgumentDecayToAPointer", "tags": [ "correctness" ] @@ -304,7 +306,8 @@ "short_name": "PointerToAVirtualBaseClassCastToAPointer", "tags": [ "correctness" - ] + ], + "shared_implementation_short_name": "PointerToAVirtualBaseClassCastToAPointer" } ], "title": "A pointer to a virtual base class shall only be cast to a pointer to a derived class by means of dynamic_cast." @@ -325,6 +328,7 @@ "precision": "very-high", "severity": "error", "short_name": "CastNotConvertPointerToFunction", + "shared_implementation_short_name": "CastsBetweenAPointerToFunctionAndAnyOtherType", "tags": [ "correctness" ] @@ -393,7 +397,12 @@ "severity": "warning", "short_name": "DoNotUsePointerArithmeticOnPolymorphicObjects", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/high", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], @@ -413,7 +422,12 @@ "short_name": "DeletingPointerToIncompleteClass", "shared_implementation_short_name": "DeleteOfPointerToIncompleteClass", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -424,7 +438,12 @@ "severity": "error", "short_name": "CastOfPointerToIncompleteClass", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -444,7 +463,12 @@ "short_name": "UseOfPointerToMemberToAccessUndefinedMember", "shared_implementation_short_name": "AccessOfUndefinedMemberThroughNullPointer", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] }, { @@ -456,7 +480,12 @@ "short_name": "MemberAccessWithUninitializedStaticPointerToMember", "shared_implementation_short_name": "AccessOfUndefinedMemberThroughUninitializedStaticPointer", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] }, { @@ -468,7 +497,12 @@ "short_name": "UseOfPointerToMemberToAccessNonexistentMember", "shared_implementation_short_name": "AccessOfNonExistingMemberThroughPointerToMember", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/Representation.json b/rule_packages/cpp/Representation.json index 96674eef0e..813373afb4 100644 --- a/rule_packages/cpp/Representation.json +++ b/rule_packages/cpp/Representation.json @@ -53,6 +53,18 @@ "tags": [ "correctness" ] + }, + { + "description": "Passing a aliased pointers as parameters of certain functions is undefined behavior.", + "kind": "problem", + "name": "Do not pass aliased pointers as parameters of functions where it is undefined behaviour for those pointers to overlap", + "precision": "medium", + "severity": "error", + "short_name": "DoNotPassAliasedPointerToParam", + "shared_implementation_short_name": "DoNotPassAliasedPointerToRestrictQualifiedParamShared", + "tags": [ + "correctness" + ] } ], "title": "An object shall not be assigned to an overlapping object." @@ -96,6 +108,7 @@ "precision": "very-high", "severity": "error", "short_name": "NamedBitFieldsWithSignedIntegerTypeShallHaveALengthOfMoreThanOneBit", + "shared_implementation_short_name": "NamedBitFieldsWithSignedIntegerType", "tags": [ "correctness" ] @@ -118,7 +131,12 @@ "severity": "error", "short_name": "MemsetUsedToAccessObjectRepresentation", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] }, { @@ -130,7 +148,12 @@ "short_name": "MemcmpUsedToAccessObjectRepresentation", "shared_implementation_short_name": "MemcmpUsedToComparePaddingData", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] }, { @@ -141,7 +164,12 @@ "severity": "error", "short_name": "MemcpyUsedToAccessObjectRepresentation", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/Scope.json b/rule_packages/cpp/Scope.json index 30b92a0675..6fc3aa8487 100644 --- a/rule_packages/cpp/Scope.json +++ b/rule_packages/cpp/Scope.json @@ -64,6 +64,7 @@ "precision": "very-high", "severity": "error", "short_name": "HiddenInheritedNonOverridableMemberFunction", + "shared_implementation_short_name": "HiddenInheritedNonOverridableMemberFunction", "tags": [ "correctness" ] @@ -75,6 +76,7 @@ "precision": "very-high", "severity": "error", "short_name": "HiddenInheritedOverridableMemberFunction", + "shared_implementation_short_name": "HiddenInheritedOverridableMemberFunction", "tags": [ "correctness" ] @@ -86,6 +88,7 @@ "precision": "very-high", "severity": "error", "short_name": "DefinitionNotConsideredForUnqualifiedLookup", + "shared_implementation_short_name": "DefinitionNotConsideredForUnqualifiedLookup", "tags": [ "correctness" ] @@ -228,6 +231,7 @@ "precision": "very-high", "severity": "warning", "short_name": "GlobalNamespaceMembershipViolation", + "shared_implementation_short_name": "GlobalNamespaceDeclarations", "tags": [ "readability" ] @@ -250,7 +254,12 @@ "severity": "warning", "short_name": "LocalFunctionDeclaration", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] }, { @@ -261,7 +270,12 @@ "severity": "warning", "short_name": "LocalConstructorInitializedObjectHidesIdentifier", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -280,7 +294,12 @@ "severity": "error", "short_name": "SingularOverloadOfMemoryFunction", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/low", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -300,7 +319,12 @@ "short_name": "ModificationOfTheStandardNamespaces", "shared_implementation_short_name": "NonStandardEntitiesInStandardNamespaces", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -319,7 +343,12 @@ "severity": "error", "short_name": "UnnamedNamespaceInHeaderFile", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -339,7 +368,12 @@ "short_name": "OneDefinitionRuleNotObeyed", "shared_implementation_short_name": "OneDefinitionRuleViolation", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/high", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/SideEffects1.json b/rule_packages/cpp/SideEffects1.json index adddbc3b36..587a6ceb66 100644 --- a/rule_packages/cpp/SideEffects1.json +++ b/rule_packages/cpp/SideEffects1.json @@ -84,7 +84,12 @@ "severity": "warning", "short_name": "DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] }, { @@ -95,7 +100,12 @@ "severity": "warning", "short_name": "DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -114,7 +124,12 @@ "severity": "warning", "short_name": "DoNotRelyOnSideEffectsInSizeOfOperand", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -125,7 +140,12 @@ "severity": "warning", "short_name": "DoNotRelyOnSideEffectsInTypeIdOperand", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -136,7 +156,12 @@ "severity": "warning", "short_name": "DoNotRelyOnSideEffectsInNoExceptOperand", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -147,7 +172,12 @@ "severity": "warning", "short_name": "DoNotRelyOnSideEffectsInDeclTypeOperand", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -158,7 +188,12 @@ "severity": "warning", "short_name": "DoNotRelyOnSideEffectsInDeclValExpression", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/SideEffects2.json b/rule_packages/cpp/SideEffects2.json index 6e5e4812fb..0338b88895 100644 --- a/rule_packages/cpp/SideEffects2.json +++ b/rule_packages/cpp/SideEffects2.json @@ -165,7 +165,12 @@ "shared_implementation_short_name": "PredicateFunctionObjectsShouldNotBeMutable", "short_name": "PredicateFunctionObjectsShouldNotBeMutable", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/high", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/SmartPointers2.json b/rule_packages/cpp/SmartPointers2.json index 2f89c4868a..db641b4c7e 100644 --- a/rule_packages/cpp/SmartPointers2.json +++ b/rule_packages/cpp/SmartPointers2.json @@ -16,7 +16,10 @@ "precision": "medium", "severity": "warning", "short_name": "WeakPtrNotUsedToRepresentTemporarySharedOwnership", - "tags": ["correctness", "external/autosar/audit"] + "tags": [ + "correctness", + "external/autosar/audit" + ] } ], "title": "A std::weak_ptr shall be used to represent temporary shared ownership." @@ -36,8 +39,14 @@ "severity": "error", "short_name": "OwnedPointerValueStoredInUnrelatedSmartPointerCert", "shared_implementation_short_name": "OwnedPointerValueStoredInUnrelatedSmartPointer", - - "tags": ["correctness"] + "tags": [ + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" + ] } ], "title": "Do not store an already-owned pointer value in an unrelated smart pointer" diff --git a/rule_packages/cpp/Statements.json b/rule_packages/cpp/Statements.json new file mode 100644 index 0000000000..91a643253d --- /dev/null +++ b/rule_packages/cpp/Statements.json @@ -0,0 +1,78 @@ +{ + "MISRA-C++-2023": { + "RULE-9-4-2": { + "properties": { + "allocated-target": [ + "Single Translation Unit" + ], + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "A switch statement should have an appropriate structure with proper cases, default labels, and break statements to ensure clear control flow and prevent unintended fall-through behavior.", + "kind": "problem", + "name": "The structure of a switch statement shall be appropriate", + "precision": "very-high", + "severity": "error", + "short_name": "AppropriateStructureOfSwitchStatement", + "tags": [ + "correctness", + "maintainability", + "readability" + ] + } + ], + "title": "The structure of a switch statement shall be appropriate" + }, + "RULE-9-5-1": { + "properties": { + "allocated-target": [ + "Single Translation Unit" + ], + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "Legacy for statements with complex initialization, condition, and increment expressions can be difficult to understand and maintain. Simple for loops are more readable.", + "kind": "problem", + "name": "Legacy for statements should be simple", + "precision": "high", + "severity": "recommendation", + "short_name": "LegacyForStatementsShouldBeSimple", + "tags": [ + "maintainability", + "readability" + ] + } + ], + "title": "Legacy for statements should be simple" + }, + "RULE-9-5-2": { + "properties": { + "allocated-target": [ + "Single Translation Unit" + ], + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Multiple function calls in a for-range-initializer can lead to unclear iteration behavior and potential side effects that make the code harder to understand and debug.", + "kind": "problem", + "name": "A for-range-initializer shall contain at most one function call", + "precision": "very-high", + "severity": "error", + "short_name": "ForRangeInitializerAtMostOneFunctionCall", + "tags": [ + "correctness", + "maintainability", + "readability" + ] + } + ], + "title": "A for-range-initializer shall contain at most one function call" + } + } +} diff --git a/rule_packages/cpp/Strings.json b/rule_packages/cpp/Strings.json index 2152684792..acccdc7753 100644 --- a/rule_packages/cpp/Strings.json +++ b/rule_packages/cpp/Strings.json @@ -133,7 +133,13 @@ "severity": "recommendation", "shared_implementation_short_name": "BasicStringMayNotBeNullTerminated", "short_name": "BasicStringMayNotBeNullTerminatedCert", - "tags": [] + "tags": [ + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" + ] }, { "description": "Certain operations may not null terminate CStyle strings which may cause unpredictable behavior.", @@ -143,7 +149,13 @@ "severity": "recommendation", "shared_implementation_short_name": "OperationMayNotNullTerminateCStyleString", "short_name": "OperationMayNotNullTerminateCStyleStringCert", - "tags": [] + "tags": [ + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" + ] } ], "title": "Guarantee that storage for strings has sufficient space for character data and the null terminator" diff --git a/rule_packages/cpp/Templates.json b/rule_packages/cpp/Templates.json index 006f81bda6..a6520a7780 100644 --- a/rule_packages/cpp/Templates.json +++ b/rule_packages/cpp/Templates.json @@ -22,7 +22,7 @@ "readability" ] } - ], + ], "title": "A template should check if a specific template argument is suitable for this template." }, "A14-5-1": { @@ -112,6 +112,7 @@ "precision": "very-high", "severity": "warning", "short_name": "ExplicitSpecializationsOfFunctionTemplatesUsed", + "shared_implementation_short_name": "FunctionTemplatesExplicitlySpecialized", "tags": [ "maintainability", "readability" @@ -171,25 +172,27 @@ "precision": "very-high", "severity": "warning", "short_name": "NameNotReferredUsingAQualifiedIdOrThis", + "shared_implementation_short_name": "NameNotReferredUsingAQualifiedIdOrThis", "tags": [ "maintainability", "readability" ] }, { - "description": "Not using a qualified-id or `this->` syntax for identifiers used in a class template makes the code more difficult to understand.", - "kind": "problem", - "name": "(Audit) In a class template with a dependent base, any name that may be found in that dependent base shall shall be referred to using a qualified-id or this->", - "precision": "very-high", - "severity": "warning", - "short_name": "NameNotReferredUsingAQualifiedIdOrThisAudit", - "tags": [ - "maintainability", - "readability" - ] - } + "description": "Not using a qualified-id or `this->` syntax for identifiers used in a class template makes the code more difficult to understand.", + "kind": "problem", + "name": "(Audit) In a class template with a dependent base, any name that may be found in that dependent base shall shall be referred to using a qualified-id or this->", + "precision": "very-high", + "severity": "warning", + "short_name": "NameNotReferredUsingAQualifiedIdOrThisAudit", + "shared_implementation_short_name": "NameNotReferredUsingAQualifiedIdOrThisAudit", + "tags": [ + "maintainability", + "readability" + ] + } ], "title": "In a class template with a dependent base, any name that may be found in that dependent base shall be referred to using a qualified-id or this->." } } -} +} \ No newline at end of file diff --git a/rule_packages/cpp/TrustBoundaries.json b/rule_packages/cpp/TrustBoundaries.json index 7387fffc1f..0b697cd49c 100644 --- a/rule_packages/cpp/TrustBoundaries.json +++ b/rule_packages/cpp/TrustBoundaries.json @@ -38,7 +38,12 @@ "severity": "error", "short_name": "DoNotThrowAnExceptionAcrossExecutionBoundaries", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ] } ], @@ -57,7 +62,12 @@ "severity": "error", "short_name": "DoNotPassANonstandardObjectAcrossBoundaries", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ] } ], diff --git a/rule_packages/cpp/TypeRanges.json b/rule_packages/cpp/TypeRanges.json index 1b27e0ed91..1e8ef914bf 100644 --- a/rule_packages/cpp/TypeRanges.json +++ b/rule_packages/cpp/TypeRanges.json @@ -184,7 +184,12 @@ "short_name": "DetectErrorsWhenConvertingAStringToANumber", "shared_implementation_short_name": "StringNumberConversionMissingErrorCheck", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -203,7 +208,12 @@ "severity": "error", "short_name": "DoNotCastToAnOutOfRangeEnumerationValue", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/Uninitialized.json b/rule_packages/cpp/Uninitialized.json index 019987eef4..1432e11603 100644 --- a/rule_packages/cpp/Uninitialized.json +++ b/rule_packages/cpp/Uninitialized.json @@ -41,7 +41,12 @@ "short_name": "InformationLeakageAcrossTrustBoundaries", "shared_implementation_short_name": "InformationLeakageAcrossBoundaries", "tags": [ - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/high", + "external/cert/priority/p1", + "external/cert/level/l3" ], "implementation_scope": { "description": "The rule does not detect cases where fields may have uninitialized padding but are initialized via an initializer." @@ -65,7 +70,12 @@ "shared_implementation_short_name": "ReadOfUninitializedMemory", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ] } ], diff --git a/rule_packages/cpp/VirtualFunctions.json b/rule_packages/cpp/VirtualFunctions.json index 198aba1bb7..eff4e15beb 100644 --- a/rule_packages/cpp/VirtualFunctions.json +++ b/rule_packages/cpp/VirtualFunctions.json @@ -177,6 +177,7 @@ "precision": "very-high", "severity": "warning", "short_name": "VirtualFunctionParametersUseTheSameDefaultArguments", + "shared_implementation_short_name": "OverridingShallSpecifyDifferentDefaultArguments", "tags": [ "correctness" ] diff --git a/rules.csv b/rules.csv index 913aa27282..3cb64a0bac 100644 --- a/rules.csv +++ b/rules.csv @@ -511,10 +511,11 @@ c,CERT-C,ENV31-C,Yes,Rule,,,Do not rely on an environment pointer following an o c,CERT-C,ENV32-C,Yes,Rule,,,All exit handlers must return normally,,Contracts2,Medium, c,CERT-C,ENV33-C,Yes,Rule,,,Do not call system(),"RULE-21-21, M18-0-3",Banned,Easy, c,CERT-C,ENV34-C,Yes,Rule,,,Do not store pointers returned by certain functions,RULE-21-20,Contracts2,Medium, -c,CERT-C,ERR30-C,Yes,Rule,,,"Take care when reading errno",M19-3-1,Contracts4,Hard, +c,CERT-C,ERR30-C,Yes,Rule,,,Take care when reading errno,M19-3-1,Contracts4,Hard, c,CERT-C,ERR32-C,Yes,Rule,,,Do not rely on indeterminate values of errno,,Contracts5,Hard, c,CERT-C,ERR33-C,Yes,Rule,,,Detect and handle standard library errors,MEM52-CPP,Contracts5,Hard, c,CERT-C,ERR34-C,OutOfScope,Rule,,,Detect errors when converting a string to a number,,,, +c,CERT-C,EXP16-C,Yes,Recommendation,,,Do not compare function pointers to constant values,,Expressions2,Medium, c,CERT-C,EXP30-C,Yes,Rule,,,Do not depend on the order of evaluation for side effects,EXP50-CPP,SideEffects1,Easy, c,CERT-C,EXP32-C,Yes,Rule,,,Do not access a volatile object through a nonvolatile reference,,Pointers3,Easy, c,CERT-C,EXP33-C,Yes,Rule,,,Do not read uninitialized memory,EXP53-CPP,InvalidMemory1,Import, @@ -530,6 +531,8 @@ c,CERT-C,EXP44-C,Yes,Rule,,,"Do not rely on side effects in operands to sizeof, c,CERT-C,EXP45-C,Yes,Rule,,,Do not perform assignments in selection statements,M6-2-1,SideEffects1,Medium, c,CERT-C,EXP46-C,Yes,Rule,,,Do not use a bitwise operator with a Boolean-like operand,,Expressions,Easy, c,CERT-C,EXP47-C,OutOfScope,Rule,,,Do not call va_arg with an argument of the incorrect type,,,, +c,CERT-C,FIO03-C,Yes,Recommendation,,,Do not make assumptions about fopen() and file creation,,IO5,Hard, +c,CERT-C,FIO21-C,Yes,Recommendation,,,Do not create temporary files in shared directories,,IO5,Easy, c,CERT-C,FIO30-C,Yes,Rule,,,Exclude user input from format strings,A27-0-1,IO1,Import, c,CERT-C,FIO32-C,Yes,Rule,,,Do not perform operations on devices that are only appropriate for files,,IO3,Medium, c,CERT-C,FIO34-C,Yes,Rule,,,Distinguish between characters read from a file and EOF or WEOF,,IO1,Hard, @@ -569,7 +572,7 @@ c,CERT-C,MSC38-C,Yes,Rule,,,Do not treat a predefined identifier as an object if c,CERT-C,MSC39-C,Yes,Rule,,,Do not call va_arg() on a va_list that has an indeterminate value,,Contracts7,Hard, c,CERT-C,MSC40-C,Yes,Rule,,,Do not violate constraints,,Contracts,Very Hard, c,CERT-C,MSC41-C,OutOfScope,Rule,,,Never hard code sensitive information,,,, -c,CERT-C,POS30-C,OutOfScope,Rule,,,Use the readlink() function properly,,,, +c,CERT-C,POS30-C,Yes,Rule,,,Use the readlink() function properly,,IO5,Hard, c,CERT-C,POS34-C,OutOfScope,Rule,,,Do not call putenv() with a pointer to an automatic variable as the argument,,,, c,CERT-C,POS35-C,OutOfScope,Rule,,,Avoid race conditions while checking for the existence of a symbolic link,,,, c,CERT-C,POS36-C,OutOfScope,Rule,,,Observe correct revocation order while relinquishing privileges,,,, @@ -614,12 +617,17 @@ c,MISRA-C-2012,DIR-4-9,Yes,Advisory,,,A function should be used in preference to c,MISRA-C-2012,DIR-4-10,Yes,Required,,,Precautions shall be taken in order to prevent the contents of a header file being included more than once,M16-2-3,Preprocessor2,Medium, c,MISRA-C-2012,DIR-4-11,Yes,Required,,,The validity of values passed to library functions shall be checked,,Contracts,Hard, c,MISRA-C-2012,DIR-4-12,Yes,Required,,,Dynamic memory allocation shall not be used,,Banned,Medium, -c,MISRA-C-2012,DIR-4-13,No,Advisory,,,Functions which are designed to provide operations on a resource should be called in an appropriate sequence,,,,Rule 22.1, 22.2 and 22.6 cover aspects of this rule. In other cases this is a design issue and needs to be checked manually. -c,MISRA-C-2012,DIR-4-14,Yes,Required,,,The validity of values received from external sources shall be checked,,Contracts,Hard,This is supported by CodeQLs default C security queries. +c,MISRA-C-2012,DIR-4-13,No,Advisory,,,Functions which are designed to provide operations on a resource should be called in an appropriate sequence,,,,"Rule 22.1, 22.2 and 22.6 cover aspects of this rule. In other cases this is a design issue and needs to be checked manually." +c,MISRA-C-2012,DIR-4-14,Yes,Required,,,The validity of values received from external sources shall be checked,,Contracts8,Hard,This is supported by CodeQLs default C security queries. +c,MISRA-C-2012,DIR-4-15,Yes,Required,,,Evaluation of floating-point expressions shall not lead to the undetected generation of infinities and NaNs,FLP32-C and FLP04-C,FloatingTypes2,Medium, +c,MISRA-C-2012,DIR-5-1,Yes,Required,,,There shall be no data races between threads,CON43-C and CON32-C,Concurrency9,Very Hard, +c,MISRA-C-2012,DIR-5-2,Yes,Required,,,There shall be no deadlocks between threads,CON35-C,Concurrency6,Import, +c,MISRA-C-2012,DIR-5-3,Yes,Required,,,There shall be no dynamic thread creation,,Concurrency6,Easy, c,MISRA-C-2012,RULE-1-1,No,Required,,,"The program shall contain no violations of the standard C syntax and constraints, and shall not exceed the implementation's translation limits",,,Easy,"This should be checked via the compiler output, rather than CodeQL, which adds unnecessary steps." c,MISRA-C-2012,RULE-1-2,Yes,Advisory,,,Language extensions should not be used,,Language3,Hard, c,MISRA-C-2012,RULE-1-3,Yes,Required,,,There shall be no occurrence of undefined or critical unspecified behaviour,,Language3,Hard, c,MISRA-C-2012,RULE-1-4,Yes,Required,,,Emergent language features shall not be used,,Language2,Medium, +c,MISRA-C-2012,RULE-1-5,Yes,Required,,,Obsolencent language features shall not be used,,Language4,Medium, c,MISRA-C-2012,RULE-2-1,Yes,Required,,,A project shall not contain unreachable code,M0-1-1,DeadCode,Import, c,MISRA-C-2012,RULE-2-2,Yes,Required,,,There shall be no dead code,M0-1-9,DeadCode,Import, c,MISRA-C-2012,RULE-2-3,Yes,Advisory,,,A project should not contain unused type declarations,A0-1-6,DeadCode,Import, @@ -627,6 +635,7 @@ c,MISRA-C-2012,RULE-2-4,Yes,Advisory,,,A project should not contain unused tag d c,MISRA-C-2012,RULE-2-5,Yes,Advisory,,,A project should not contain unused macro declarations,,DeadCode,Easy, c,MISRA-C-2012,RULE-2-6,Yes,Advisory,,,A function should not contain unused label declarations,,DeadCode,Easy, c,MISRA-C-2012,RULE-2-7,Yes,Advisory,,,There should be no unused parameters in functions,A0-1-4 A0-1-5,DeadCode,Easy, +c,MISRA-C-2012,RULE-2-8,Yes,Advisory,,,A project should not contain unused object definitions,Rules 2.3-2.7,DeadCode2,Medium, c,MISRA-C-2012,RULE-3-1,Yes,Required,,,The character sequences /* and // shall not be used within a comment,M2-7-1,Syntax,Easy, c,MISRA-C-2012,RULE-3-2,Yes,Required,,,Line-splicing shall not be used in // comments,,Syntax,Easy, c,MISRA-C-2012,RULE-4-1,Yes,Required,,,Octal and hexadecimal escape sequences shall be terminated,A2-13-1 M2-13-2,Syntax,Medium, @@ -642,10 +651,13 @@ c,MISRA-C-2012,RULE-5-8,Yes,Required,,,Identifiers that define objects or functi c,MISRA-C-2012,RULE-5-9,Yes,Advisory,,,Identifiers that define objects or functions with internal linkage should be unique,,Declarations6,Easy, c,MISRA-C-2012,RULE-6-1,Yes,Required,,,Bit-fields shall only be declared with an appropriate type,M9-6-4,BitfieldTypes,Medium, c,MISRA-C-2012,RULE-6-2,Yes,Required,,,Single-bit named bit fields shall not be of a signed type,M9-6-4,BitfieldTypes,Import, +c,MISRA-C-2012,RULE-6-3,Yes,Required,,,A bit field shall not be declared as a member of a union,DCL39-C,BitfieldTypes2,Easy, c,MISRA-C-2012,RULE-7-1,Yes,Required,,,Octal constants shall not be used,M2-13-2,Banned,Import, -c,MISRA-C-2012,RULE-7-2,Yes,Required,,,A �u� or �U� suffix shall be applied to all integer constants that are represented in an unsigned type,M2-13-3,Syntax,Easy, -c,MISRA-C-2012,RULE-7-3,Yes,Required,,,The lowercase character �l� shall not be used in a literal suffix,M2-13-4,Syntax,Easy, -c,MISRA-C-2012,RULE-7-4,Yes,Required,,,A string literal shall not be assigned to an object unless the object�s type is �pointer to const-qualified char�,A2-13-4,Types1,Easy, +c,MISRA-C-2012,RULE-7-2,Yes,Required,,,A 'u' or 'U' suffix shall be applied to all integer constants that are represented in an unsigned type,M2-13-3,Syntax,Easy, +c,MISRA-C-2012,RULE-7-3,Yes,Required,,,The lowercase character 'l' shall not be used in a literal suffix,M2-13-4,Syntax,Easy, +c,MISRA-C-2012,RULE-7-4,Yes,Required,,,A string literal shall not be assigned to an object unless the object's type is 'pointer to const-qualified char',A2-13-4,Types1,Easy, +c,MISRA-C-2012,RULE-7-5,Yes,Required,,,The argument of an integer constant macro shall have an appropriate form,,Types2,Medium, +c,MISRA-C-2012,RULE-7-6,Yes,Required,,,The small integer variants of the minimum-width integer constant macros shall not be used,,Types2,Easy, c,MISRA-C-2012,RULE-8-1,Yes,Required,,,Types shall be explicitly specified,,Declarations3,Medium, c,MISRA-C-2012,RULE-8-2,Yes,Required,,,Function types shall be in prototype form with named parameters,,Declarations4,Medium, c,MISRA-C-2012,RULE-8-3,Yes,Required,,,All declarations of an object or function shall use the same names and type qualifiers,M3-2-1,Declarations4,Medium, @@ -660,11 +672,16 @@ c,MISRA-C-2012,RULE-8-11,Yes,Advisory,,,"When an array with external linkage is c,MISRA-C-2012,RULE-8-12,Yes,Required,,,"Within an enumerator list, the value of an implicitly-specified enumeration constant shall be unique",,Declarations7,Medium, c,MISRA-C-2012,RULE-8-13,Yes,Advisory,,,A pointer should point to a const-qualified type whenever possible,,Pointers1,Medium, c,MISRA-C-2012,RULE-8-14,Yes,Required,,,The restrict type qualifier shall not be used,,Banned,Easy, +c,MISRA-C-2012,RULE-8-15,Yes,Required,,,All declarations of an object with an explicit alignment specification shall specify the same alignment,,Alignment,Easy, +c,MISRA-C-2012,RULE-8-16,Yes,Advisory,,,The alignment specification of zero should not appear in an object declaration,,Alignment,Easy, +c,MISRA-C-2012,RULE-8-17,Yes,Advisory,,,At most one explicit alignment specifier should appear in an object declaration,,Alignment,Easy, c,MISRA-C-2012,RULE-9-1,Yes,Mandatory,,,The value of an object with automatic storage duration shall not be read before it has been set,,InvalidMemory1,Import, c,MISRA-C-2012,RULE-9-2,Yes,Required,,,The initializer for an aggregate or union shall be enclosed in braces,,Memory1,Easy, c,MISRA-C-2012,RULE-9-3,Yes,Required,,,Arrays shall not be partially initialized,,Memory1,Medium, c,MISRA-C-2012,RULE-9-4,Yes,Required,,,An element of an object shall not be initialized more than once,,Memory1,Medium, c,MISRA-C-2012,RULE-9-5,No,Required,,,Where designated initializers are used to initialize an array object the size of the array shall be specified explicitly,,,Medium, +c,MISRA-C-2012,RULE-9-6,Yes,Required,,,An initializer using chained designators shall not contain initializers without designators,,Declarations10,Hard, +c,MISRA-C-2012,RULE-9-7,Yes,Mandatory,,,Atomic objects shall be appropriately initialized before being accessed,,Concurrency7,Hard, c,MISRA-C-2012,RULE-10-1,Yes,Required,,,Operands shall not be of an inappropriate essential type,,EssentialTypes,Hard, c,MISRA-C-2012,RULE-10-2,Yes,Required,,,Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations,,EssentialTypes,Medium, c,MISRA-C-2012,RULE-10-3,Yes,Required,,,The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category,,EssentialTypes,Hard, @@ -682,17 +699,19 @@ c,MISRA-C-2012,RULE-11-6,Yes,Required,,,A cast shall not be performed between po c,MISRA-C-2012,RULE-11-7,Yes,Required,,,A cast shall not be performed between pointer to object and a non- integer arithmetic type,,Pointers1,Easy, c,MISRA-C-2012,RULE-11-8,Yes,Required,,,A cast shall not remove any const or volatile qualification from the type pointed to by a pointer,,Pointers1,Easy, c,MISRA-C-2012,RULE-11-9,Yes,Required,,,The macro NULL shall be the only permitted form of integer null pointer constant,,Pointers1,Easy, +c,MISRA-C-2012,RULE-11-10,Yes,Required,,,The _Atomic qualifier shall not be applied to the incomplete type void,,Declarations9,Easy, c,MISRA-C-2012,RULE-12-1,Yes,Advisory,,,The precedence of operators within expressions should be made explicit,,SideEffects1,Medium, c,MISRA-C-2012,RULE-12-2,Yes,Required,,,The right hand operand of a shift operator shall lie in the range zero to one less than the width in bits of the essential type of the left hand operand,,Contracts7,Medium, c,MISRA-C-2012,RULE-12-3,Yes,Advisory,,,The comma operator should not be used,M5-18-1,Banned,Import, c,MISRA-C-2012,RULE-12-4,Yes,Advisory,,,Evaluation of constant expressions should not lead to unsigned integer wrap-around,INT30-C,IntegerOverflow,Easy, -c,MISRA-C-2012,RULE-12-5,Yes,Mandatory,,,The sizeof operator shall not have an operand which is a function parameter declared as �array of type�,,Types1,Medium, +c,MISRA-C-2012,RULE-12-5,Yes,Mandatory,,,The sizeof operator shall not have an operand which is a function parameter declared as 'array of type',,Types1,Medium, +c,MISRA-C-2012,RULE-12-6,Yes,Required,,,Structure and union members of atomic objects shall not be directly accessed,,Concurrency6,Easy, c,MISRA-C-2012,RULE-13-1,Yes,Required,,,Initializer lists shall not contain persistent side effects,,SideEffects1,Medium, c,MISRA-C-2012,RULE-13-2,Yes,Required,,,The value of an expression and its persistent side effects shall be the same under all permitted evaluation orders,PRE31-C,SideEffects3,Medium, c,MISRA-C-2012,RULE-13-3,Yes,Advisory,,,A full expression containing an increment (++) or decrement (--) operator should have no other potential side effects other than that caused by the increment or decrement operator,,SideEffects2,Medium, c,MISRA-C-2012,RULE-13-4,Yes,Advisory,,,The result of an assignment operator should not be used,M6-2-1,SideEffects1,Easy, c,MISRA-C-2012,RULE-13-5,Yes,Required,,,The right hand operand of a logical && or || operator shall not contain persistent side effects,M5-14-1,SideEffects1,Import, -c,MISRA-C-2012,RULE-13-6,Yes,Mandatory,,,The operand of the sizeof operator shall not contain any expressiosn which has potential side effects,M5-3-4,SideEffects1,Import, +c,MISRA-C-2012,RULE-13-6,Yes,Required,,,The operand of the sizeof operator shall not contain any expressiosn which has potential side effects,M5-3-4,SideEffects1,Import, c,MISRA-C-2012,RULE-14-1,Yes,Required,,,A loop counter shall not have essentially floating type,FLP30-C A6-5-2,EssentialTypes,Hard, c,MISRA-C-2012,RULE-14-2,Yes,Required,,,A for loop shall be well-formed,M6-5-1...M6-5-6,Statements4,Medium, c,MISRA-C-2012,RULE-14-3,Yes,Required,,,Controlling expressions shall not be invariant,,Statements5,Medium, @@ -703,7 +722,7 @@ c,MISRA-C-2012,RULE-15-3,Yes,Required,,,"Any label referenced by a goto statemen c,MISRA-C-2012,RULE-15-4,Yes,Advisory,,,There should be no more than one break or goto statement used to terminate any iteration statement,,Statements2,Medium, c,MISRA-C-2012,RULE-15-5,Yes,Advisory,,,A function should have a single point of exit at the end,,Statements5,Medium, c,MISRA-C-2012,RULE-15-6,Yes,Required,,,The body of an iteration-statement or a selection-statement shall be a compund-statement,M6-3-1,Statements3,Import, -c,MISRA-C-2012,RULE-15-7,Yes,Required,,,All if / else if constructs shall be terminated with an else statement,M6-4-2,Statements3,Import, +c,MISRA-C-2012,RULE-15-7,Yes,Required,,,All if else if constructs shall be terminated with an else statement,M6-4-2,Statements3,Import, c,MISRA-C-2012,RULE-16-1,Yes,Required,,,All switch statements shall be well-formed,M6-4-3,Statements3,Import, c,MISRA-C-2012,RULE-16-2,Yes,Required,,,A switch label shall only be used when the most closely-enclosing compound statement is the body of a switch statement,M6-4-4,Statements1,Import, c,MISRA-C-2012,RULE-16-3,Yes,Required,,,An unconditional break statement shall terminate every switch-clause,M6-4-5,Statements1,Import, @@ -715,10 +734,15 @@ c,MISRA-C-2012,RULE-17-1,Yes,Required,,,The features of shall not be c,MISRA-C-2012,RULE-17-2,Yes,Required,,,"Functions shall not call themselves, either directly or indirectly",A7-5-2,Statements3,Import, c,MISRA-C-2012,RULE-17-3,Yes,Mandatory,,,A function shall not be declared implicitly,,Declarations6,Medium, c,MISRA-C-2012,RULE-17-4,Yes,Mandatory,,,All exit paths from a function with non-void return type shall have an explicit return statement with an expression,MSC52-CPP,Statements5,Medium, -c,MISRA-C-2012,RULE-17-5,Yes,Advisory,,,The function argument corresponding to a parameter declared to have an array type shall have an appropriate number of elements,,Contracts6,Hard, +c,MISRA-C-2012,RULE-17-5,Yes,Required,,,The function argument corresponding to a parameter declared to have an array type shall have an appropriate number of elements,,Contracts6,Hard, c,MISRA-C-2012,RULE-17-6,Yes,Mandatory,,,The declaration of an array parameter shall not contain the static keyword between the [ ],,Static,Easy, c,MISRA-C-2012,RULE-17-7,Yes,Required,,,The value returned by a function having non-void return type shall be used,A0-1-2,Contracts6,Easy, c,MISRA-C-2012,RULE-17-8,Yes,Advisory,,,A function parameter should not be modified,,SideEffects2,Medium, +c,MISRA-C-2012,RULE-17-9,Yes,Mandatory,,,Verify that a function declared with _Noreturn does not return,,NoReturn,Easy, +c,MISRA-C-2012,RULE-17-10,Yes,Required,,,A function declared with _noreturn shall have a return type of void,,NoReturn,Easy, +c,MISRA-C-2012,RULE-17-11,Yes,Advisory,,,A function without a branch that returns shall be declared with _Noreturn,,NoReturn,Easy, +c,MISRA-C-2012,RULE-17-12,Yes,Advisory,,,A function identifier should only be called with a parenthesized parameter list or used with a & (address-of),,FunctionTypes,Easy, +c,MISRA-C-2012,RULE-17-13,No,Required,,,"A function type shall not include any type qualifiers (const, volatile, restrict, or _Atomic)",,,Easy, c,MISRA-C-2012,RULE-18-1,Yes,Required,,,A pointer resulting from arithmetic on a pointer operand shall address an element of the same array as that pointer operand,M5-0-16,Pointers1,Import, c,MISRA-C-2012,RULE-18-2,Yes,Required,,,Subtraction between pointers shall only be applied to pointers that address elements of the same array,M5-0-17,Pointers1,Import, c,MISRA-C-2012,RULE-18-3,Yes,Required,,,"The relational operators >, >=, < and <= shall not be applied to objects of pointer type except where they point into the same object",M5-0-18,Pointers1,Import, @@ -727,6 +751,8 @@ c,MISRA-C-2012,RULE-18-5,Yes,Advisory,,,Declarations should contain no more than c,MISRA-C-2012,RULE-18-6,Yes,Required,,,The address of an object with automatic storage shall not be copied to another object that persists after the first object has ceased to exist,M7-5-2,Pointers1,Import, c,MISRA-C-2012,RULE-18-7,Yes,Required,,,Flexible array members shall not be declared,,Declarations6,Medium, c,MISRA-C-2012,RULE-18-8,Yes,Required,,,Variable-length array types shall not be used,,Declarations7,Medium, +c,MISRA-C-2012,RULE-18-9,Yes,Required,,,An object with temporary lifetime shall not undergo array to pointer conversion,EXP35-C,InvalidMemory3,Hard, +c,MISRA-C-2012,RULE-18-10,Yes,Mandatory,,,Pointers to variably-modified array types shall not be used,,InvalidMemory3,Import, c,MISRA-C-2012,RULE-19-1,Yes,Mandatory,,,An object shall not be assigned or copied to an overlapping object,M0-2-1,Contracts7,Hard, c,MISRA-C-2012,RULE-19-2,Yes,Advisory,,,The union keyword should not be used,A9-5-1,Banned,Import, c,MISRA-C-2012,RULE-20-1,Yes,Advisory,,,#include directives should only be preceded by preprocessor directives or comments,M16-0-1,Preprocessor1,Import, @@ -753,7 +779,7 @@ c,MISRA-C-2012,RULE-21-7,Yes,Required,,,"The Standard Library functions atof, at c,MISRA-C-2012,RULE-21-8,Yes,Required,,,The Standard Library termination functions of shall not be used,ERR50-CPP,Banned,Easy, c,MISRA-C-2012,RULE-21-9,Yes,Required,,,The Standard Library functions bsearch and qsort of shall not be used,,Banned,Easy, c,MISRA-C-2012,RULE-21-10,Yes,Required,,,The Standard Library time and date functions shall not be used,,Banned,Easy, -c,MISRA-C-2012,RULE-21-11,Yes,Required,,,The standard header file shall not be used,,Banned,Easy, +c,MISRA-C-2012,RULE-21-11,Yes,Advisory,,,The standard header file shall not be used,,Banned,Easy, c,MISRA-C-2012,RULE-21-12,Yes,Advisory,,,The exception handling features of should not be used,,Banned,Easy, c,MISRA-C-2012,RULE-21-13,Yes,Mandatory,,,Any value passed to a function in shall be representable as an unsigned char or be the value EOF,,StandardLibraryFunctionTypes,Medium, c,MISRA-C-2012,RULE-21-14,Yes,Required,,,The Standard Library function memcmp shall not be used to compare null terminated strings,,EssentialTypes,Hard, @@ -764,6 +790,11 @@ c,MISRA-C-2012,RULE-21-18,Yes,Mandatory,,,The size_t argument passed to any func c,MISRA-C-2012,RULE-21-19,Yes,Mandatory,,,"The pointers returned by the Standard Library functions localeconv, getenv, setlocale or, strerror shall only be used as if they have pointer to const-qualified type",ENV30-C,Contracts2,Medium, c,MISRA-C-2012,RULE-21-20,Yes,Mandatory,,,"The pointer returned by the Standard Library functions asctime, ctime, gmtime, localtime, localeconv, getenv, setlocale or strerror shall not be used following a subsequent call to the same function",ENV34-C,Contracts2,Import, c,MISRA-C-2012,RULE-21-21,Yes,Required,,,The Standard Library function system of shall not be used,ENV33-C,Banned,Import, +c,MISRA-C-2012,RULE-21-22,Yes,Mandatory,,,All operand arguments to any type-generic macros in shall have an appropriate essential type,EXP37-C,EssentialTypes2,Hard, +c,MISRA-C-2012,RULE-21-23,Yes,Required,,,All operand arguments to any multi-argument type-generic macros in shall have the same standard type,Rule-21-22,EssentialTypes2,Easy, +c,MISRA-C-2012,RULE-21-24,Yes,Required,,,The random number generator functions of shall not be used,MSC30-C,Banned2,Easy, +c,MISRA-C-2012,RULE-21-25,Yes,Required,,,All memory synchronization operations shall be executed in sequentially consistent order,,Concurrency6,Medium, +c,MISRA-C-2012,RULE-21-26,Yes,Required,,,The Standard Library function mtx_timedlock() shall only be invoked on mutex objects of appropriate mutex type,,Concurrency7,Hard, c,MISRA-C-2012,RULE-22-1,Yes,Required,,,All resources obtained dynamically by means of Standard Library functions shall be explicitly released,,Memory2,Hard, c,MISRA-C-2012,RULE-22-2,Yes,Mandatory,,,A block of memory shall only be freed if it was allocated by means of a Standard Library function,,Memory2,Hard, c,MISRA-C-2012,RULE-22-3,Yes,Required,,,The same file shall not be open for read and write access at the same time on different streams,,IO3,Hard, @@ -774,182 +805,200 @@ c,MISRA-C-2012,RULE-22-7,Yes,Required,,,The macro EOF shall only be compared wit c,MISRA-C-2012,RULE-22-8,Yes,Required,,,The value of errno shall be set to zero prior to a call to an errno-setting-function,ERR30-C,Contracts3,Medium, c,MISRA-C-2012,RULE-22-9,Yes,Required,,,The value of errno shall be tested against zero after calling an errno-setting-function,,Contracts3,Medium, c,MISRA-C-2012,RULE-22-10,Yes,Required,,,The value of errno shall only be tested when the last function to be called was an errno-setting-function,,Contracts3,Medium, -cpp,MISRA-C++-2023,RULE-0-0-1,Yes,Required,Decidable,Single Translation Unit,A function shall not contain unreachable statements,,,Medium, -cpp,MISRA-C++-2023,RULE-0-0-2,Yes,Advisory,Undecidable,System,Controlling expressions should not be invariant,,,Easy, -cpp,MISRA-C++-2023,RULE-0-1-1,Yes,Advisory,Undecidable,System,A value should not be unnecessarily written to a local object,,,Medium, -cpp,MISRA-C++-2023,RULE-0-1-2,Yes,Required,Decidable,Single Translation Unit,The value returned by a function shall be used,,,Easy, -cpp,MISRA-C++-2023,RULE-0-2-1,Yes,Advisory,Decidable,Single Translation Unit,Variables with limited visibility should be used at least once,,,Easy, -cpp,MISRA-C++-2023,RULE-0-2-2,Yes,Required,Decidable,Single Translation Unit,A named function parameter shall be used at least once,,,Easy, -cpp,MISRA-C++-2023,RULE-0-2-3,Yes,Advisory,Decidable,Single Translation Unit,Types with limited visibility should be used at least once,,,Easy, -cpp,MISRA-C++-2023,RULE-0-2-4,Yes,Advisory,Decidable,System,Functions with limited visibility should be used at least once,,,Easy, -cpp,MISRA-C++-2023,DIR-0-3-1,Yes,Advisory,,,Floating-point arithmetic should be used appropriately,,,Hard, -cpp,MISRA-C++-2023,DIR-0-3-2,Yes,Required,,,A function call shall not violate the function’s preconditions,,,Hard, -cpp,MISRA-C++-2023,RULE-4-1-1,Yes,Required,Undecidable,System,A program shall conform to ISO/IEC 14882:2017 (C++17),,,Hard, -cpp,MISRA-C++-2023,RULE-4-1-2,Yes,Advisory,Decidable,Single Translation Unit,Deprecated features should not be used,,,Very Hard, -cpp,MISRA-C++-2023,RULE-4-1-3,Yes,Required,Undecidable,System,There shall be no occurrence of undefined or critical unspecified behaviour,,,Very Hard, -cpp,MISRA-C++-2023,RULE-4-6-1,Yes,Required,Undecidable,System,Operations on a memory location shall be sequenced appropriately,,,Import, -cpp,MISRA-C++-2023,RULE-5-0-1,Yes,Advisory,Decidable,Single Translation Unit,Trigraph-like sequences should not be used,,,Very Hard, -cpp,MISRA-C++-2023,RULE-5-7-1,Yes,Required,Decidable,Single Translation Unit,The character sequence /* shall not be used within a C-style comment,,,Import, -cpp,MISRA-C++-2023,DIR-5-7-2,Yes,Advisory,,,Sections of code should not be “commented out”,,,Import, -cpp,MISRA-C++-2023,RULE-5-7-3,Yes,Required,Decidable,Single Translation Unit,Line-splicing shall not be used in // comments,,,Import, -cpp,MISRA-C++-2023,RULE-5-10-1,Yes,Required,Decidable,Single Translation Unit,User-defined identifiers shall have an appropriate form,,,Easy, -cpp,MISRA-C++-2023,RULE-5-13-1,Yes,Required,Decidable,Single Translation Unit,"In character literals and non-raw string literals, \ shall only be used to form a defined escape sequence or universal character name",,,Import, -cpp,MISRA-C++-2023,RULE-5-13-2,Yes,Required,Decidable,Single Translation Unit,"Octal escape sequences, hexadecimal escape sequences, and universal character names shall be terminated",,,Import, -cpp,MISRA-C++-2023,RULE-5-13-3,Yes,Required,Decidable,Single Translation Unit,Octal constants shall not be used,,,Import, -cpp,MISRA-C++-2023,RULE-5-13-4,Yes,Required,Decidable,Single Translation Unit,Unsigned integer literals shall be appropriately suffixed,,,Import, -cpp,MISRA-C++-2023,RULE-5-13-5,Yes,Required,Decidable,Single Translation Unit,The lowercase form of L shall not be used as the first character in a literal suffix,,,Import, -cpp,MISRA-C++-2023,RULE-5-13-6,Yes,Required,Decidable,Single Translation Unit,An integer-literal of type long long shall not use a single L or l in any suffix,,,Easy, -cpp,MISRA-C++-2023,RULE-5-13-7,No,Required,Decidable,Single Translation Unit,String literals with different encoding prefixes shall not be concatenated,,,, -cpp,MISRA-C++-2023,RULE-6-0-1,Yes,Required,Decidable,Single Translation Unit,Block scope declarations shall not be visually ambiguous,,,Easy, -cpp,MISRA-C++-2023,RULE-6-0-2,Yes,Advisory,Decidable,Single Translation Unit,"When an array with external linkage is declared, its size should be explicitly specified",,,Easy, -cpp,MISRA-C++-2023,RULE-6-0-3,Yes,Advisory,Decidable,Single Translation Unit,"The only declarations in the global namespace should be main, namespace declarations and extern ""C"" declarations",,,Import, -cpp,MISRA-C++-2023,RULE-6-0-4,Yes,Required,Decidable,Single Translation Unit,The identifier main shall not be used for a function other than the global function main,,,Import, -cpp,MISRA-C++-2023,RULE-6-2-1,Yes,Required,Decidable,System,The one-definition rule shall not be violated,,,Import, -cpp,MISRA-C++-2023,RULE-6-2-2,Yes,Required,Decidable,System,All declarations of a variable or function shall have the same type,,,Easy, -cpp,MISRA-C++-2023,RULE-6-2-3,Yes,Required,Decidable,System,The source code used to implement an entity shall appear only once,,,Medium, -cpp,MISRA-C++-2023,RULE-6-2-4,Yes,Required,Decidable,Single Translation Unit,A header file shall not contain definitions of functions or objects that are non-inline and have external linkage,,,Easy, -cpp,MISRA-C++-2023,RULE-6-4-1,Yes,Required,Decidable,Single Translation Unit,A variable declared in an inner scope shall not hide a variable declared in an outer scope,,,Import, -cpp,MISRA-C++-2023,RULE-6-4-2,Yes,Required,Decidable,Single Translation Unit,Derived classes shall not conceal functions that are inherited from their bases,,,Import, -cpp,MISRA-C++-2023,RULE-6-4-3,Yes,Required,Decidable,Single Translation Unit,A name that is present in a dependent base shall not be resolved by unqualified lookup,,,Import, -cpp,MISRA-C++-2023,RULE-6-5-1,Yes,Advisory,Decidable,Single Translation Unit,A function or object with external linkage should be introduced in a header file,,,Medium, -cpp,MISRA-C++-2023,RULE-6-5-2,Yes,Advisory,Decidable,Single Translation Unit,Internal linkage should be specified appropriately,,,Medium, -cpp,MISRA-C++-2023,RULE-6-7-1,Yes,Required,Decidable,Single Translation Unit,Local variables shall not have static storage duration,,,Easy, -cpp,MISRA-C++-2023,RULE-6-7-2,Yes,Required,Decidable,Single Translation Unit,Global variables shall not be used,,,Easy, -cpp,MISRA-C++-2023,RULE-6-8-1,Yes,Required,Undecidable,System,An object shall not be accessed outside of its lifetime,,,Import, -cpp,MISRA-C++-2023,RULE-6-8-2,Yes,Mandatory,Decidable,Single Translation Unit,A function must not return a reference or a pointer to a local variable with automatic storage duration,,,Import, -cpp,MISRA-C++-2023,RULE-6-8-3,Yes,Required,Decidable,Single Translation Unit,An assignment operator shall not assign the address of an object with automatic storage duration to an object with a greater lifetime,,,Medium, -cpp,MISRA-C++-2023,RULE-6-8-4,Yes,Advisory,Decidable,Single Translation Unit,Member functions returning references to their object should be refqualified appropriately,,,Medium, -cpp,MISRA-C++-2023,RULE-6-9-1,Yes,Required,Decidable,Single Translation Unit,The same type aliases shall be used in all declarations of the same entity,,,Medium, -cpp,MISRA-C++-2023,RULE-6-9-2,Yes,Advisory,Decidable,Single Translation Unit,The names of the standard signed integer types and standard unsigned integer types should not be used,,,Easy, -cpp,MISRA-C++-2023,RULE-7-0-1,Yes,Required,Decidable,Single Translation Unit,There shall be no conversion from type bool,,,Easy, -cpp,MISRA-C++-2023,RULE-7-0-2,Yes,Required,Decidable,Single Translation Unit,There shall be no conversion to type bool,,,Easy, -cpp,MISRA-C++-2023,RULE-7-0-3,Yes,Required,Decidable,Single Translation Unit,The numerical value of a character shall not be used,,,Medium, -cpp,MISRA-C++-2023,RULE-7-0-4,Yes,Required,Decidable,Single Translation Unit,The operands of bitwise operators and shift operators shall be appropriate,,,Medium, -cpp,MISRA-C++-2023,RULE-7-0-5,Yes,Required,Decidable,Single Translation Unit,Integral promotion and the usual arithmetic conversions shall not change the signedness or the type category of an operand,,,Medium, -cpp,MISRA-C++-2023,RULE-7-0-6,Yes,Required,Decidable,Single Translation Unit,Assignment between numeric types shall be appropriate,,,Hard, -cpp,MISRA-C++-2023,RULE-7-11-1,Yes,Required,Decidable,Single Translation Unit,nullptr shall be the only form of the null-pointer-constant,,,Import, -cpp,MISRA-C++-2023,RULE-7-11-2,Yes,Required,Decidable,Single Translation Unit,An array passed as a function argument shall not decay to a pointer,,,Import, -cpp,MISRA-C++-2023,RULE-7-11-3,Yes,Required,Decidable,Single Translation Unit,A conversion from function type to pointer-to-function type shall only occur in appropriate contexts,,,Easy, -cpp,MISRA-C++-2023,RULE-8-0-1,Yes,Advisory,Decidable,Single Translation Unit,Parentheses should be used to make the meaning of an expression appropriately explicit,,,Medium, -cpp,MISRA-C++-2023,RULE-8-1-1,Yes,Required,Decidable,Single Translation Unit,A non-transient lambda shall not implicitly capture this,,,Easy, -cpp,MISRA-C++-2023,RULE-8-1-2,Yes,Advisory,Decidable,Single Translation Unit,Variables should be captured explicitly in a non-transient lambda,,,Easy, -cpp,MISRA-C++-2023,RULE-8-2-1,Yes,Required,Decidable,Single Translation Unit,A virtual base class shall only be cast to a derived class by means of dynamic_cast,,,Easy, -cpp,MISRA-C++-2023,RULE-8-2-2,Yes,Required,Decidable,Single Translation Unit,C-style casts and functional notation casts shall not be used,,,Easy, -cpp,MISRA-C++-2023,RULE-8-2-3,Yes,Required,Decidable,Single Translation Unit,A cast shall not remove any const or volatile qualification from the type accessed via a pointer or by reference,,,Import, -cpp,MISRA-C++-2023,RULE-8-2-4,Yes,Required,Decidable,Single Translation Unit,Casts shall not be performed between a pointer to function and any other type,,,Import, -cpp,MISRA-C++-2023,RULE-8-2-5,Yes,Required,Decidable,Single Translation Unit,reinterpret_cast shall not be used,,,Import, -cpp,MISRA-C++-2023,RULE-8-2-6,Yes,Required,Decidable,Single Translation Unit,"An object with integral, enumerated, or pointer to void type shall not be cast to a pointer type",,,Easy, -cpp,MISRA-C++-2023,RULE-8-2-7,Yes,Advisory,Decidable,Single Translation Unit,A cast should not convert a pointer type to an integral type,,,Easy, -cpp,MISRA-C++-2023,RULE-8-2-8,Yes,Required,Decidable,Single Translation Unit,An object pointer type shall not be cast to an integral type other than std::uintptr_t or std::intptr_t,,,Easy, -cpp,MISRA-C++-2023,RULE-8-2-9,Yes,Required,Decidable,Single Translation Unit,The operand to typeid shall not be an expression of polymorphic class type,,,Easy, -cpp,MISRA-C++-2023,RULE-8-2-10,Yes,Required,Undecidable,System,"Functions shall not call themselves, either directly or indirectly",,,Import, -cpp,MISRA-C++-2023,RULE-8-2-11,Yes,Required,Decidable,Single Translation Unit,An argument passed via ellipsis shall have an appropriate type,,,Easy, -cpp,MISRA-C++-2023,RULE-8-3-1,Yes,Advisory,Decidable,Single Translation Unit,The built-in unary - operator should not be applied to an expression of unsigned type,,,Import, -cpp,MISRA-C++-2023,RULE-8-3-2,Yes,Advisory,Decidable,Single Translation Unit,The built-in unary + operator should not be used,,,Easy, -cpp,MISRA-C++-2023,RULE-8-7-1,Yes,Required,Undecidable,System,Pointer arithmetic shall not form an invalid pointer,,,Easy, -cpp,MISRA-C++-2023,RULE-8-7-2,Yes,Required,Undecidable,System,Subtraction between pointers shall only be applied to pointers that address elements of the same array,,,Easy, -cpp,MISRA-C++-2023,RULE-8-9-1,Yes,Required,Undecidable,System,"The built-in relational operators >, >=, < and <= shall not be applied to objects of pointer type, except where they point to elements of the same array",,,Easy, -cpp,MISRA-C++-2023,RULE-8-14-1,Yes,Advisory,Undecidable,System,The right-hand operand of a logical && or operator should not contain persistent side effects,,,Medium, -cpp,MISRA-C++-2023,RULE-8-18-1,Yes,Mandatory,Undecidable,System,An object or subobject must not be copied to an overlapping object,,,Hard, -cpp,MISRA-C++-2023,RULE-8-18-2,Yes,Advisory,Decidable,Single Translation Unit,The result of an assignment operator should not be used,,,Import, -cpp,MISRA-C++-2023,RULE-8-19-1,Yes,Advisory,Decidable,Single Translation Unit,The comma operator should not be used,,,Import, -cpp,MISRA-C++-2023,RULE-8-20-1,Yes,Advisory,Decidable,Single Translation Unit,An unsigned arithmetic operation with constant operands should not wrap,,,Import, -cpp,MISRA-C++-2023,RULE-9-2-1,Yes,Required,Decidable,Single Translation Unit,An explicit type conversion shall not be an expression statement,,,Easy, -cpp,MISRA-C++-2023,RULE-9-3-1,Yes,Required,Decidable,Single Translation Unit,The body of an iteration-statement or a selection-statement shall be a compound-statement,,,Import, -cpp,MISRA-C++-2023,RULE-9-4-1,Yes,Required,Decidable,Single Translation Unit,All if ... else if constructs shall be terminated with an else statement,,,Import, -cpp,MISRA-C++-2023,RULE-9-4-2,Yes,Required,Decidable,Single Translation Unit,The structure of a switch statement shall be appropriate,,,Medium, -cpp,MISRA-C++-2023,RULE-9-5-1,Yes,Advisory,Decidable,Single Translation Unit,Legacy for statements should be simple,,,Hard, -cpp,MISRA-C++-2023,RULE-9-5-2,Yes,Required,Decidable,Single Translation Unit,A for-range-initializer shall contain at most one function call,,,Easy, -cpp,MISRA-C++-2023,RULE-9-6-1,Yes,Advisory,Decidable,Single Translation Unit,The goto statement should not be used,,,Import, -cpp,MISRA-C++-2023,RULE-9-6-2,Yes,Required,Decidable,Single Translation Unit,A goto statement shall reference a label in a surrounding block,,,Import, -cpp,MISRA-C++-2023,RULE-9-6-3,Yes,Required,Decidable,Single Translation Unit,The goto statement shall jump to a label declared later in the function body,,,Import, -cpp,MISRA-C++-2023,RULE-9-6-4,Yes,Required,Undecidable,System,A function declared with the [[noreturn]] attribute shall not return,,,Import, -cpp,MISRA-C++-2023,RULE-9-6-5,Yes,Required,Decidable,Single Translation Unit,A function with non-void return type shall return a value on all paths,,,Import, -cpp,MISRA-C++-2023,RULE-10-0-1,Yes,Advisory,Decidable,Single Translation Unit,A declaration should not declare more than one variable or member variable,,,Import, -cpp,MISRA-C++-2023,RULE-10-1-1,Yes,Advisory,Decidable,Single Translation Unit,The target type of a pointer or lvalue reference parameter should be const-qualified appropriately,,,Hard, -cpp,MISRA-C++-2023,RULE-10-1-2,Yes,Required,Decidable,Single Translation Unit,The volatile qualifier shall be used appropriately,,,Easy, -cpp,MISRA-C++-2023,RULE-10-2-1,Yes,Required,Decidable,Single Translation Unit,An enumeration shall be defined with an explicit underlying type,,,Import, -cpp,MISRA-C++-2023,RULE-10-2-2,Yes,Advisory,Decidable,Single Translation Unit,Unscoped enumerations should not be declared,,,Easy, -cpp,MISRA-C++-2023,RULE-10-2-3,Yes,Required,Decidable,Single Translation Unit,The numeric value of an unscoped enumeration with no fixed underlying type shall not be used,,,Easy, -cpp,MISRA-C++-2023,RULE-10-3-1,Yes,Advisory,Decidable,Single Translation Unit,There should be no unnamed namespaces in header files,,,Easy, -cpp,MISRA-C++-2023,RULE-10-4-1,Yes,Required,Decidable,Single Translation Unit,The asm declaration shall not be used,,,Import, -cpp,MISRA-C++-2023,RULE-11-3-1,Yes,Advisory,Decidable,Single Translation Unit,Variables of array type should not be declared,,,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,,,Import, -cpp,MISRA-C++-2023,RULE-11-6-1,Yes,Advisory,Decidable,Single Translation Unit,All variables should be initialized,,,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,,,Very Hard, -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",,,Import, -cpp,MISRA-C++-2023,RULE-12-2-1,Yes,Advisory,Decidable,Single Translation Unit,Bit-fields should not be declared,,,Easy, -cpp,MISRA-C++-2023,RULE-12-2-2,Yes,Required,Decidable,Single Translation Unit,A bit-field shall have an appropriate type,,,Import, -cpp,MISRA-C++-2023,RULE-12-2-3,Yes,Required,Decidable,Single Translation Unit,A named bit-field with signed integer type shall not have a length of one bit,,,Import, -cpp,MISRA-C++-2023,RULE-12-3-1,Yes,Required,Decidable,Single Translation Unit,The union keyword shall not be used,,,Easy, -cpp,MISRA-C++-2023,RULE-13-1-1,Yes,Advisory,Decidable,Single Translation Unit,Classes should not be inherited virtually,,,Easy, -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,,,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",,,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,,,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,,,Import, -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,,,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,,,Easy, -cpp,MISRA-C++-2023,RULE-15-0-1,Yes,Required,Decidable,Single Translation Unit,Special member functions shall be provided appropriately,,,Medium, -cpp,MISRA-C++-2023,RULE-15-0-2,Yes,Advisory,Decidable,Single Translation Unit,User-provided copy and move member functions of a class should have appropriate signatures,,,Easy, -cpp,MISRA-C++-2023,RULE-15-1-1,Yes,Required,Undecidable,System,An object’s dynamic type shall not be used from within its constructor or destructor,,,Import, -cpp,MISRA-C++-2023,RULE-15-1-2,Yes,Advisory,Decidable,Single Translation Unit,All constructors of a class should explicitly initialize all of its virtual base classes and immediate base classes,,,Import, -cpp,MISRA-C++-2023,RULE-15-1-3,Yes,Required,Decidable,Single Translation Unit,Conversion operators and constructors that are callable with a single argument shall be explicit,,,Easy, -cpp,MISRA-C++-2023,RULE-15-1-4,Yes,Advisory,Decidable,Single Translation Unit,"All direct, non-static data members of a class should be initialized before the class object is accessible",,,Hard, -cpp,MISRA-C++-2023,RULE-15-1-5,Yes,Required,Decidable,Single Translation Unit,A class shall only define an initializer-list constructor when it is the only constructor,,,Import, -cpp,MISRA-C++-2023,DIR-15-8-1,Yes,Required,#VALUE!,,User-provided copy assignment operators and move assignment operators shall handle self-assignment,,,Import, -cpp,MISRA-C++-2023,RULE-16-5-1,Yes,Required,Decidable,Single Translation Unit,The logical AND and logical OR operators shall not be overloaded,,,Easy, -cpp,MISRA-C++-2023,RULE-16-5-2,Yes,Required,Decidable,Single Translation Unit,The address-of operator shall not be overloaded,,,Import, -cpp,MISRA-C++-2023,RULE-16-6-1,Yes,Advisory,Decidable,Single Translation Unit,Symmetrical operators should only be implemented as non-member functions,,,Medium, -cpp,MISRA-C++-2023,RULE-17-8-1,Yes,Required,Decidable,Single Translation Unit,Function templates shall not be explicitly specialized,,,Import, -cpp,MISRA-C++-2023,RULE-18-1-1,Yes,Required,Decidable,Single Translation Unit,An exception object shall not have pointer type,,,Import, -cpp,MISRA-C++-2023,RULE-18-1-2,Yes,Required,Decidable,Single Translation Unit,An empty throw shall only occur within the compound-statement of a catch handler,,,Import, -cpp,MISRA-C++-2023,RULE-18-3-1,Yes,Advisory,Decidable,Single Translation Unit,There should be at least one exception handler to catch all otherwise unhandled exceptions,,,Easy, -cpp,MISRA-C++-2023,RULE-18-3-2,Yes,Required,Decidable,Single Translation Unit,An exception of class type shall be caught by const reference or reference,,,Easy, -cpp,MISRA-C++-2023,RULE-18-3-3,Yes,Required,Decidable,Single Translation Unit,Handlers for a function-try-block of a constructor or destructor shall not refer to non-static members from their class or its bases,,,Import, -cpp,MISRA-C++-2023,RULE-18-4-1,Yes,Required,Decidable,Single Translation Unit,Exception-unfriendly functions shall be noexcept,,,Easy, -cpp,MISRA-C++-2023,RULE-18-5-1,Yes,Advisory,Undecidable,System,A noexcept function should not attempt to propagate an exception to the calling function,,,Import, -cpp,MISRA-C++-2023,RULE-18-5-2,Yes,Advisory,Decidable,Single Translation Unit,Program-terminating functions should not be used,,,Easy, +c,MISRA-C-2012,RULE-22-11,Yes,Required,,,A thread that was previously either joined or detached shall not be subsequently joined nor detached,CON39-C,Concurrency6,Import, +c,MISRA-C-2012,RULE-22-12,Yes,Mandatory,,,"Thread objects, thread synchronization objects, and thread-specific storage pointers shall only be accessed by the appropriate Standard Library functions",,Concurrency8,Medium, +c,MISRA-C-2012,RULE-22-13,Yes,Required,,,"Thread objects, thread synchronization objects, and thread specific storage pointers shall have appropriate storage duration",EXP54-CPP and CON34-C,Concurrency8,Medium, +c,MISRA-C-2012,RULE-22-14,Yes,Mandatory,,,Thread synchronization objects shall be initialized before being accessed,EXP53-CPP,Concurrency8,Hard, +c,MISRA-C-2012,RULE-22-15,Yes,Required,,,Thread synchronization objects and thread-specific storage pointers shall not be destroyed until after all threads accessing them have terminated,,Concurrency9,Hard, +c,MISRA-C-2012,RULE-22-16,Yes,Required,,,All mutex objects locked by a thread shall be explicitly unlocked by the same thread,MEM51-CPP,Concurrency8,Hard, +c,MISRA-C-2012,RULE-22-17,Yes,Required,,,No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it has not locked before,Rule 22.2,Concurrency9,Medium, +c,MISRA-C-2012,RULE-22-18,Yes,Required,,,Non-recursive mutexes shall not be recursively locked,CON56-CPP,Concurrency9,Medium, +c,MISRA-C-2012,RULE-22-19,Yes,Required,,,A condition variable shall be associated with at most one mutex object,,Concurrency9,Medium, +c,MISRA-C-2012,RULE-22-20,Yes,Mandatory,,,Thread-specific storage pointers shall be created before being accessed,,Concurrency9,Hard, +c,MISRA-C-2012,RULE-23-1,Yes,Advisory,,,A generic selection should only be expanded from a macro,,Generics,Medium, +c,MISRA-C-2012,RULE-23-2,Yes,Required,,,A generic selection that is not expanded from a macro shall not contain potential side effects in the controlling expression,,Generics,Hard, +c,MISRA-C-2012,RULE-23-3,Yes,Advisory,,,A generic selection should contain at least one non-default association,,Generics,Easy, +c,MISRA-C-2012,RULE-23-4,Yes,Required,,,A generic association shall list an appropriate type,,Generics,Medium, +c,MISRA-C-2012,RULE-23-5,Yes,Advisory,,,A generic selection should not depend on implicit pointer type conversion,,Generics,Medium, +c,MISRA-C-2012,RULE-23-6,Yes,Required,,,The controlling expression of a generic selection shall have an essential type that matches its standard type,,Generics,Medium, +c,MISRA-C-2012,RULE-23-7,Yes,Advisory,,,A generic selection that is expanded from a macro should evaluate its argument only once,,Generics,Medium, +c,MISRA-C-2012,RULE-23-8,Yes,Required,,,A default association shall appear as either the first or the last association of a generic selection,,Generics,Easy, +cpp,MISRA-C++-2023,RULE-0-0-1,Yes,Required,Decidable,Single Translation Unit,A function shall not contain unreachable statements,M0-1-1,DeadCode2,Medium, +cpp,MISRA-C++-2023,RULE-0-0-2,Yes,Advisory,Undecidable,System,Controlling expressions should not be invariant,M0-1-2,DeadCode2,Easy, +cpp,MISRA-C++-2023,RULE-0-1-1,Yes,Advisory,Undecidable,System,A value should not be unnecessarily written to a local object,A0-1-1,DeadCode2,Medium, +cpp,MISRA-C++-2023,RULE-0-1-2,Yes,Required,Decidable,Single Translation Unit,The value returned by a function shall be used,A0-1-2,DeadCode2,Easy, +cpp,MISRA-C++-2023,RULE-0-2-1,Yes,Advisory,Decidable,Single Translation Unit,Variables with limited visibility should be used at least once,M0-1-3,DeadCode2,Easy, +cpp,MISRA-C++-2023,RULE-0-2-2,Yes,Required,Decidable,Single Translation Unit,A named function parameter shall be used at least once,"A0-1-4, A0-1-5",DeadCode2,Easy, +cpp,MISRA-C++-2023,RULE-0-2-3,Yes,Advisory,Decidable,Single Translation Unit,Types with limited visibility should be used at least once,A0-1-6,DeadCode2,Easy, +cpp,MISRA-C++-2023,RULE-0-2-4,Yes,Advisory,Decidable,System,Functions with limited visibility should be used at least once,A0-1-3,DeadCode2,Easy, +cpp,MISRA-C++-2023,DIR-0-3-1,Yes,Advisory,,,Floating-point arithmetic should be used appropriately,,FloatingPoint,Hard, +cpp,MISRA-C++-2023,DIR-0-3-2,Yes,Required,,,A function call shall not violate the function’s preconditions,,Preconditions,Hard, +cpp,MISRA-C++-2023,RULE-4-1-1,Yes,Required,Undecidable,System,A program shall conform to ISO/IEC 14882:2017 (C++17),,Toolchain2,Hard, +cpp,MISRA-C++-2023,RULE-4-1-2,Yes,Advisory,Decidable,Single Translation Unit,Deprecated features should not be used,,Toolchain2,Very Hard, +cpp,MISRA-C++-2023,RULE-4-1-3,Yes,Required,Undecidable,System,There shall be no occurrence of undefined or critical unspecified behaviour,,Undefined,Very Hard, +cpp,MISRA-C++-2023,RULE-4-6-1,Yes,Required,Undecidable,System,Operations on a memory location shall be sequenced appropriately,RULE-13-2,SideEffects3,Easy, +cpp,MISRA-C++-2023,RULE-5-0-1,Yes,Advisory,Decidable,Single Translation Unit,Trigraph-like sequences should not be used,A2-5-1,Trigraph,Very Hard, +cpp,MISRA-C++-2023,RULE-5-7-1,Yes,Required,Decidable,Single Translation Unit,The character sequence /* shall not be used within a C-style comment,M2-7-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,DIR-5-7-2,Yes,Advisory,,,Sections of code should not be “commented out”,A2-7-2,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-5-7-3,Yes,Required,Decidable,Single Translation Unit,Line-splicing shall not be used in // comments,A2-7-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-5-10-1,Yes,Required,Decidable,Single Translation Unit,User-defined identifiers shall have an appropriate form,,Naming2,Easy, +cpp,MISRA-C++-2023,RULE-5-13-1,Yes,Required,Decidable,Single Translation Unit,"In character literals and non-raw string literals, \ shall only be used to form a defined escape sequence or universal character name",A2-13-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-5-13-2,Yes,Required,Decidable,Single Translation Unit,"Octal escape sequences, hexadecimal escape sequences, and universal character names shall be terminated",RULE-4-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-5-13-3,Yes,Required,Decidable,Single Translation Unit,Octal constants shall not be used,M2-13-2,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-5-13-4,Yes,Required,Decidable,Single Translation Unit,Unsigned integer literals shall be appropriately suffixed,M2-13-3,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-5-13-5,Yes,Required,Decidable,Single Translation Unit,The lowercase form of L shall not be used as the first character in a literal suffix,RULE-7-3,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-5-13-6,Yes,Required,Decidable,Single Translation Unit,An integer-literal of type long long shall not use a single L or l in any suffix,,Expressions2,Easy, +cpp,MISRA-C++-2023,RULE-5-13-7,No,Required,Decidable,Single Translation Unit,String literals with different encoding prefixes shall not be concatenated,A2-13-2,,, +cpp,MISRA-C++-2023,RULE-6-0-1,Yes,Required,Decidable,Single Translation Unit,Block scope declarations shall not be visually ambiguous,"M3-1-2,DCL53-CPP",Declarations2,Easy, +cpp,MISRA-C++-2023,RULE-6-0-2,Yes,Advisory,Decidable,Single Translation Unit,"When an array with external linkage is declared, its size should be explicitly specified",RULE-18-8,Linkage,Easy, +cpp,MISRA-C++-2023,RULE-6-0-3,Yes,Advisory,Decidable,Single Translation Unit,"The only declarations in the global namespace should be main, namespace declarations and extern ""C"" declarations",M7-3-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-6-0-4,Yes,Required,Decidable,Single Translation Unit,The identifier main shall not be used for a function other than the global function main,M7-3-2,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-6-2-1,Yes,Required,Decidable,System,The one-definition rule shall not be violated,M3-2-2,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-6-2-2,Yes,Required,Decidable,System,All declarations of a variable or function shall have the same type,"M3-9-1,DCL40-C",Declarations2,Easy, +cpp,MISRA-C++-2023,RULE-6-2-3,Yes,Required,Decidable,System,The source code used to implement an entity shall appear only once,,Declarations2,Medium, +cpp,MISRA-C++-2023,RULE-6-2-4,Yes,Required,Decidable,Single Translation Unit,A header file shall not contain definitions of functions or objects that are non-inline and have external linkage,,Linkage,Easy, +cpp,MISRA-C++-2023,RULE-6-4-1,Yes,Required,Decidable,Single Translation Unit,A variable declared in an inner scope shall not hide a variable declared in an outer scope,A2-10-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-6-4-2,Yes,Required,Decidable,Single Translation Unit,Derived classes shall not conceal functions that are inherited from their bases,A7-3-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-6-4-3,Yes,Required,Decidable,Single Translation Unit,A name that is present in a dependent base shall not be resolved by unqualified lookup,M14-6-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-6-5-1,Yes,Advisory,Decidable,Single Translation Unit,A function or object with external linkage should be introduced in a header file,,Linkage,Medium, +cpp,MISRA-C++-2023,RULE-6-5-2,Yes,Advisory,Decidable,Single Translation Unit,Internal linkage should be specified appropriately,,Linkage,Medium, +cpp,MISRA-C++-2023,RULE-6-7-1,Yes,Required,Decidable,Single Translation Unit,Local variables shall not have static storage duration,,Declarations2,Easy, +cpp,MISRA-C++-2023,RULE-6-7-2,Yes,Required,Decidable,Single Translation Unit,Global variables shall not be used,,Banned,Easy, +cpp,MISRA-C++-2023,RULE-6-8-1,Yes,Required,Undecidable,System,An object shall not be accessed outside of its lifetime,A3-8-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-6-8-2,Yes,Mandatory,Decidable,Single Translation Unit,A function must not return a reference or a pointer to a local variable with automatic storage duration,M7-5-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-6-8-3,Yes,Required,Decidable,Single Translation Unit,An assignment operator shall not assign the address of an object with automatic storage duration to an object with a greater lifetime,,Lifetime,Medium, +cpp,MISRA-C++-2023,RULE-6-8-4,Yes,Advisory,Decidable,Single Translation Unit,Member functions returning references to their object should be refqualified appropriately,,Declarations2,Medium, +cpp,MISRA-C++-2023,RULE-6-9-1,Yes,Required,Decidable,Single Translation Unit,The same type aliases shall be used in all declarations of the same entity,,Declarations2,Medium, +cpp,MISRA-C++-2023,RULE-6-9-2,Yes,Advisory,Decidable,Single Translation Unit,The names of the standard signed integer types and standard unsigned integer types should not be used,A3-9-1,BannedAPIs,Easy, +cpp,MISRA-C++-2023,RULE-7-0-1,Yes,Required,Decidable,Single Translation Unit,There shall be no conversion from type bool,,Conversions,Easy, +cpp,MISRA-C++-2023,RULE-7-0-2,Yes,Required,Decidable,Single Translation Unit,There shall be no conversion to type bool,,Conversions,Easy, +cpp,MISRA-C++-2023,RULE-7-0-3,Yes,Required,Decidable,Single Translation Unit,The numerical value of a character shall not be used,M5-0-11,Conversions,Medium, +cpp,MISRA-C++-2023,RULE-7-0-4,Yes,Required,Decidable,Single Translation Unit,The operands of bitwise operators and shift operators shall be appropriate,RULE-10-1,Conversions,Medium, +cpp,MISRA-C++-2023,RULE-7-0-5,Yes,Required,Decidable,Single Translation Unit,Integral promotion and the usual arithmetic conversions shall not change the signedness or the type category of an operand,"M5-0-4,M5-0-9,INT31-C",Conversions,Medium, +cpp,MISRA-C++-2023,RULE-7-0-6,Yes,Required,Decidable,Single Translation Unit,Assignment between numeric types shall be appropriate,,Conversions,Hard, +cpp,MISRA-C++-2023,RULE-7-11-1,Yes,Required,Decidable,Single Translation Unit,nullptr shall be the only form of the null-pointer-constant,A4-10-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-7-11-2,Yes,Required,Decidable,Single Translation Unit,An array passed as a function argument shall not decay to a pointer,M5-2-12,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-7-11-3,Yes,Required,Decidable,Single Translation Unit,A conversion from function type to pointer-to-function type shall only occur in appropriate contexts,,Conversions,Easy, +cpp,MISRA-C++-2023,RULE-8-0-1,Yes,Advisory,Decidable,Single Translation Unit,Parentheses should be used to make the meaning of an expression appropriately explicit,M5-0-2,Expressions2,Medium, +cpp,MISRA-C++-2023,RULE-8-1-1,Yes,Required,Decidable,Single Translation Unit,A non-transient lambda shall not implicitly capture this,,Expressions2,Easy, +cpp,MISRA-C++-2023,RULE-8-1-2,Yes,Advisory,Decidable,Single Translation Unit,Variables should be captured explicitly in a non-transient lambda,A5-1-2,Expressions2,Easy, +cpp,MISRA-C++-2023,RULE-8-2-1,Yes,Required,Decidable,Single Translation Unit,A virtual base class shall only be cast to a derived class by means of dynamic_cast,,Conversions2,Easy, +cpp,MISRA-C++-2023,RULE-8-2-2,Yes,Required,Decidable,Single Translation Unit,C-style casts and functional notation casts shall not be used,A5-2-2,Conversions2,Easy, +cpp,MISRA-C++-2023,RULE-8-2-3,Yes,Required,Decidable,Single Translation Unit,A cast shall not remove any const or volatile qualification from the type accessed via a pointer or by reference,A5-2-3,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-8-2-4,Yes,Required,Decidable,Single Translation Unit,Casts shall not be performed between a pointer to function and any other type,M5-2-6,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-8-2-5,Yes,Required,Decidable,Single Translation Unit,reinterpret_cast shall not be used,A5-2-4,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-8-2-6,Yes,Required,Decidable,Single Translation Unit,"An object with integral, enumerated, or pointer to void type shall not be cast to a pointer type","RULE-11-6, INT36-C",Conversions2,Easy, +cpp,MISRA-C++-2023,RULE-8-2-7,Yes,Advisory,Decidable,Single Translation Unit,A cast should not convert a pointer type to an integral type,"RULE-11-6, INT36-C",Conversions2,Easy, +cpp,MISRA-C++-2023,RULE-8-2-8,Yes,Required,Decidable,Single Translation Unit,An object pointer type shall not be cast to an integral type other than std::uintptr_t or std::intptr_t,"RULE-11-6, INT36-C",Conversions2,Easy, +cpp,MISRA-C++-2023,RULE-8-2-9,Yes,Required,Decidable,Single Translation Unit,The operand to typeid shall not be an expression of polymorphic class type,,Preconditions,Easy, +cpp,MISRA-C++-2023,RULE-8-2-10,Yes,Required,Undecidable,System,"Functions shall not call themselves, either directly or indirectly",A7-5-2,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-8-2-11,Yes,Required,Decidable,Single Translation Unit,An argument passed via ellipsis shall have an appropriate type,,Preconditions,Easy, +cpp,MISRA-C++-2023,RULE-8-3-1,Yes,Advisory,Decidable,Single Translation Unit,The built-in unary - operator should not be applied to an expression of unsigned type,M5-3-2,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-8-3-2,Yes,Advisory,Decidable,Single Translation Unit,The built-in unary + operator should not be used,,Banned,Easy, +cpp,MISRA-C++-2023,RULE-8-7-1,Yes,Required,Undecidable,System,Pointer arithmetic shall not form an invalid pointer,ARR30-C,Memory,Easy, +cpp,MISRA-C++-2023,RULE-8-7-2,Yes,Required,Undecidable,System,Subtraction between pointers shall only be applied to pointers that address elements of the same array,ARR36-C,Memory,Easy, +cpp,MISRA-C++-2023,RULE-8-9-1,Yes,Required,Undecidable,System,"The built-in relational operators >, >=, < and <= shall not be applied to objects of pointer type, except where they point to elements of the same array",ARR36-C,Memory,Easy, +cpp,MISRA-C++-2023,RULE-8-14-1,Yes,Advisory,Undecidable,System,The right-hand operand of a logical && or operator should not contain persistent side effects,"M5-14-1, RULE-13-5",SideEffects3,Medium, +cpp,MISRA-C++-2023,RULE-8-18-1,Yes,Mandatory,Undecidable,System,An object or subobject must not be copied to an overlapping object,"M0-2-1, RULE-19-1",Memory,Hard, +cpp,MISRA-C++-2023,RULE-8-18-2,Yes,Advisory,Decidable,Single Translation Unit,The result of an assignment operator should not be used,RULE-13-4,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-8-19-1,Yes,Advisory,Decidable,Single Translation Unit,The comma operator should not be used,M5-18-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-8-20-1,Yes,Advisory,Decidable,Single Translation Unit,An unsigned arithmetic operation with constant operands should not wrap,INT30-C,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-9-2-1,Yes,Required,Decidable,Single Translation Unit,An explicit type conversion shall not be an expression statement,DCL53-CPP,Conversions2,Easy, +cpp,MISRA-C++-2023,RULE-9-3-1,Yes,Required,Decidable,Single Translation Unit,The body of an iteration-statement or a selection-statement shall be a compound-statement,RULE-15-6,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-9-4-1,Yes,Required,Decidable,Single Translation Unit,All if ... else if constructs shall be terminated with an else statement,RULE-15-7,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-9-4-2,Yes,Required,Decidable,Single Translation Unit,The structure of a switch statement shall be appropriate,"RULE-16-1, RULE-16-2,RULE-16-3,RULE-16-4,RULE-16-5,RULE-16-6,RULE-16-7",Statements,Medium, +cpp,MISRA-C++-2023,RULE-9-5-1,Yes,Advisory,Decidable,Single Translation Unit,Legacy for statements should be simple,,Statements,Hard, +cpp,MISRA-C++-2023,RULE-9-5-2,Yes,Required,Decidable,Single Translation Unit,A for-range-initializer shall contain at most one function call,,Statements,Easy, +cpp,MISRA-C++-2023,RULE-9-6-1,Yes,Advisory,Decidable,Single Translation Unit,The goto statement should not be used,RULE-15-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-9-6-2,Yes,Required,Decidable,Single Translation Unit,A goto statement shall reference a label in a surrounding block,RULE-15-3,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-9-6-3,Yes,Required,Decidable,Single Translation Unit,The goto statement shall jump to a label declared later in the function body,RULE-15-2,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-9-6-4,Yes,Required,Undecidable,System,A function declared with the [[noreturn]] attribute shall not return,MSC53-CPP,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-9-6-5,Yes,Required,Decidable,Single Translation Unit,A function with non-void return type shall return a value on all paths,MSC52-CPP,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-10-0-1,Yes,Advisory,Decidable,Single Translation Unit,A declaration should not declare more than one variable or member variable,M8-0-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-10-1-1,Yes,Advisory,Decidable,Single Translation Unit,The target type of a pointer or lvalue reference parameter should be const-qualified appropriately,RULE-8-13,Declarations2,Hard, +cpp,MISRA-C++-2023,RULE-10-1-2,Yes,Required,Decidable,Single Translation Unit,The volatile qualifier shall be used appropriately,,Declarations2,Easy, +cpp,MISRA-C++-2023,RULE-10-2-1,Yes,Required,Decidable,Single Translation Unit,An enumeration shall be defined with an explicit underlying type,A7-2-2,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-10-2-2,Yes,Advisory,Decidable,Single Translation Unit,Unscoped enumerations should not be declared,A7-2-3,Banned,Easy, +cpp,MISRA-C++-2023,RULE-10-2-3,Yes,Required,Decidable,Single Translation Unit,The numeric value of an unscoped enumeration with no fixed underlying type shall not be used,A4-5-1,Banned,Easy, +cpp,MISRA-C++-2023,RULE-10-3-1,Yes,Advisory,Decidable,Single Translation Unit,There should be no unnamed namespaces in header files,"DCL59-CPP, M7-3-3",Banned,Easy, +cpp,MISRA-C++-2023,RULE-10-4-1,Yes,Required,Decidable,Single Translation Unit,The asm declaration shall not be used,A7-4-1,ImportMisra23,Import, +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-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, +cpp,MISRA-C++-2023,RULE-12-2-3,Yes,Required,Decidable,Single Translation Unit,A named bit-field with signed integer type shall not have a length of one bit,M9-6-4,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-12-3-1,Yes,Required,Decidable,Single Translation Unit,The union keyword shall not be used,RULE-19-2,Banned,Easy, +cpp,MISRA-C++-2023,RULE-13-1-1,Yes,Advisory,Decidable,Single Translation Unit,Classes should not be inherited virtually,,Classes2,Easy, +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-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,Classes2,Medium, +cpp,MISRA-C++-2023,RULE-15-0-2,Yes,Advisory,Decidable,Single Translation Unit,User-provided copy and move member functions of a class should have appropriate signatures,,Classes2,Easy, +cpp,MISRA-C++-2023,RULE-15-1-1,Yes,Required,Undecidable,System,An object’s dynamic type shall not be used from within its constructor or destructor,M12-1-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-15-1-2,Yes,Advisory,Decidable,Single Translation Unit,All constructors of a class should explicitly initialize all of its virtual base classes and immediate base classes,A12-1-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-15-1-3,Yes,Required,Decidable,Single Translation Unit,Conversion operators and constructors that are callable with a single argument shall be explicit,"A12-1-4,A13-5-2",Classes2,Easy, +cpp,MISRA-C++-2023,RULE-15-1-4,Yes,Advisory,Decidable,Single Translation Unit,"All direct, non-static data members of a class should be initialized before the class object is accessible",,Classes2,Hard, +cpp,MISRA-C++-2023,RULE-15-1-5,Yes,Required,Decidable,Single Translation Unit,A class shall only define an initializer-list constructor when it is the only constructor,A8-5-4,ImportMisra23,Import, +cpp,MISRA-C++-2023,DIR-15-8-1,Yes,Required,Decidable,Implementation,User-provided copy assignment operators and move assignment operators shall handle self-assignment,A12-8-5,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-16-5-1,Yes,Required,Decidable,Single Translation Unit,The logical AND and logical OR operators shall not be overloaded,M5-2-11,Classes2,Easy, +cpp,MISRA-C++-2023,RULE-16-5-2,Yes,Required,Decidable,Single Translation Unit,The address-of operator shall not be overloaded,M5-3-3,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-16-6-1,Yes,Advisory,Decidable,Single Translation Unit,Symmetrical operators should only be implemented as non-member functions,,Classes2,Medium, +cpp,MISRA-C++-2023,RULE-17-8-1,Yes,Required,Decidable,Single Translation Unit,Function templates shall not be explicitly specialized,A14-8-2,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-18-1-1,Yes,Required,Decidable,Single Translation Unit,An exception object shall not have pointer type,A15-1-2,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-18-1-2,Yes,Required,Decidable,Single Translation Unit,An empty throw shall only occur within the compound-statement of a catch handler,M15-1-3,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-18-3-1,Yes,Advisory,Decidable,Single Translation Unit,There should be at least one exception handler to catch all otherwise unhandled exceptions,A15-3-3,Exceptions3,Easy, +cpp,MISRA-C++-2023,RULE-18-3-2,Yes,Required,Decidable,Single Translation Unit,An exception of class type shall be caught by const reference or reference,A15-3-5,Exceptions3,Easy, +cpp,MISRA-C++-2023,RULE-18-3-3,Yes,Required,Decidable,Single Translation Unit,Handlers for a function-try-block of a constructor or destructor shall not refer to non-static members from their class or its bases,M15-3-3,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-18-4-1,Yes,Required,Decidable,Single Translation Unit,Exception-unfriendly functions shall be noexcept,A15-5-1,Exceptions3,Easy, +cpp,MISRA-C++-2023,RULE-18-5-1,Yes,Advisory,Undecidable,System,A noexcept function should not attempt to propagate an exception to the calling function,A15-4-2,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-18-5-2,Yes,Advisory,Decidable,Single Translation Unit,Program-terminating functions should not be used,,BannedAPIs,Easy, cpp,MISRA-C++-2023,RULE-19-0-1,No,Required,Decidable,Single Translation Unit,A line whose first token is # shall be a valid preprocessing directive,,,, -cpp,MISRA-C++-2023,RULE-19-0-2,Yes,Required,Decidable,Single Translation Unit,Function-like macros shall not be defined,,,Import, -cpp,MISRA-C++-2023,RULE-19-0-3,Yes,Advisory,Decidable,Single Translation Unit,#include directives should only be preceded by preprocessor directives or comments,,,Import, -cpp,MISRA-C++-2023,RULE-19-0-4,Yes,Advisory,Decidable,Single Translation Unit,#undef should only be used for macros defined previously in the same file,,,Easy, -cpp,MISRA-C++-2023,RULE-19-1-1,Yes,Required,Decidable,Single Translation Unit,The defined preprocessor operator shall be used appropriately,,,Easy, -cpp,MISRA-C++-2023,RULE-19-1-2,No,Required,Decidable,Single Translation Unit,"All #else, #elif and #endif preprocessor directives shall reside in the same file as the #if, #ifdef or #ifndef directive to which they are related",,,, -cpp,MISRA-C++-2023,RULE-19-1-3,Yes,Required,Decidable,Single Translation Unit,All identifiers used in the controlling expression of #if or #elif preprocessing directives shall be defined prior to evaluation,,,Import, -cpp,MISRA-C++-2023,RULE-19-2-1,Yes,Required,Decidable,Single Translation Unit,Precautions shall be taken in order to prevent the contents of a header file being included more than once,,,Easy, -cpp,MISRA-C++-2023,RULE-19-2-2,Yes,Required,Decidable,Single Translation Unit,"The #include directive shall be followed by either a or ""filename"" sequence",,,Easy, -cpp,MISRA-C++-2023,RULE-19-2-3,Yes,Required,Decidable,Single Translation Unit,"The ' or "" or \ characters and the /* or // character sequences shall not occur in a header file name",,,Import, -cpp,MISRA-C++-2023,RULE-19-3-1,Yes,Advisory,Decidable,Single Translation Unit,The # and ## preprocessor operators should not be used,,,Import, -cpp,MISRA-C++-2023,RULE-19-3-2,Yes,Required,Decidable,Single Translation Unit,A macro parameter immediately following a # operator shall not be immediately followed by a ## operator,,,Import, -cpp,MISRA-C++-2023,RULE-19-3-3,Yes,Required,Decidable,Single Translation Unit,The argument to a mixed-use macro parameter shall not be subject to further expansion,,,Import, -cpp,MISRA-C++-2023,RULE-19-3-4,Yes,Required,Decidable,Single Translation Unit,Parentheses shall be used to ensure macro arguments are expanded appropriately,,,Medium, -cpp,MISRA-C++-2023,RULE-19-3-5,Yes,Required,Decidable,Single Translation Unit,Tokens that look like a preprocessing directive shall not occur within a macro argument,,,Import, -cpp,MISRA-C++-2023,RULE-19-6-1,Yes,Advisory,Decidable,Single Translation Unit,The #pragma directive and the _Pragma operator should not be used,,,Easy, -cpp,MISRA-C++-2023,RULE-21-2-1,Yes,Required,Decidable,Single Translation Unit,"The library functions atof, atoi, atol and atoll from shall not be used",,,Import, -cpp,MISRA-C++-2023,RULE-21-2-2,Yes,Required,Decidable,Single Translation Unit,"The string handling functions from , , and shall not be used",,,Easy, -cpp,MISRA-C++-2023,RULE-21-2-3,Yes,Required,Decidable,Single Translation Unit,The library function system from shall not be used,,,Easy, -cpp,MISRA-C++-2023,RULE-21-2-4,Yes,Required,Decidable,Single Translation Unit,The macro offsetof shall not be used,,,Import, -cpp,MISRA-C++-2023,RULE-21-6-1,Yes,Advisory,Undecidable,Single Translation Unit,Dynamic memory should not be used,,,Easy, -cpp,MISRA-C++-2023,RULE-21-6-2,Yes,Required,Decidable,Single Translation Unit,Dynamic memory shall be managed automatically,,,Easy, -cpp,MISRA-C++-2023,RULE-21-6-3,Yes,Required,Decidable,Single Translation Unit,Advanced memory management shall not be used,,,Medium, -cpp,MISRA-C++-2023,RULE-21-6-4,Yes,Required,Decidable,System,"If a project defines either a sized or unsized version of a global operator delete, then both shall be defined",,,Import, -cpp,MISRA-C++-2023,RULE-21-6-5,Yes,Required,Decidable,Single Translation Unit,A pointer to an incomplete class type shall not be deleted,,,Import, -cpp,MISRA-C++-2023,RULE-21-10-1,Yes,Required,Decidable,Single Translation Unit,The features of shall not be used,,,Easy, -cpp,MISRA-C++-2023,RULE-21-10-2,Yes,Required,Decidable,Single Translation Unit,The standard header file shall not be used,,,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,,,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,,,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,,,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,,,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,,,Easy, -cpp,MISRA-C++-2023,RULE-24-5-2,Yes,Required,Decidable,Single Translation Unit,"The C++ Standard Library functions memcpy, memmove and memcmp from shall not be used",,,Easy, -cpp,MISRA-C++-2023,RULE-25-5-1,Yes,Required,Decidable,Single Translation Unit,The setlocale and std::locale::global functions shall not be called,,,Easy, -cpp,MISRA-C++-2023,RULE-25-5-2,Yes,Mandatory,Decidable,Single Translation Unit,"The pointers returned by the C++ Standard Library functions localeconv, getenv, setlocale or strerror must only be used as if they have pointer to const-qualified type",,,Import, -cpp,MISRA-C++-2023,RULE-25-5-3,Yes,Mandatory,Undecidable,System,"The pointer returned by the C++ Standard Library functions asctime, ctime, gmtime, localtime, localeconv, getenv, setlocale or strerror must not be used following a subsequent call to the same function",,,Import, -cpp,MISRA-C++-2023,RULE-26-3-1,Yes,Advisory,Decidable,Single Translation Unit,std::vector should not be specialized with bool,,,Import, -cpp,MISRA-C++-2023,RULE-28-3-1,Yes,Required,Undecidable,System,Predicates shall not have persistent side effects,,,Easy, -cpp,MISRA-C++-2023,RULE-28-6-1,Yes,Required,Decidable,Single Translation Unit,The argument to std::move shall be a non-const lvalue,,,Easy, -cpp,MISRA-C++-2023,RULE-28-6-2,Yes,Required,Decidable,Single Translation Unit,Forwarding references and std::forward shall be used together,,,Import, -cpp,MISRA-C++-2023,RULE-28-6-3,Yes,Required,Decidable,Single Translation Unit,An object shall not be used while in a potentially moved-from state,,,Import, -cpp,MISRA-C++-2023,RULE-28-6-4,Yes,Required,Decidable,Single Translation Unit,"The result of std::remove, std::remove_if, std::unique and empty shall be used",,,Easy, -cpp,MISRA-C++-2023,RULE-30-0-1,Yes,Required,Decidable,Single Translation Unit,The C Library input/output functions shall not be used,,,Import, -cpp,MISRA-C++-2023,RULE-30-0-2,Yes,Required,Undecidable,System,Reads and writes on the same file stream shall be separated by a positioning operation,,,Import, \ No newline at end of file +cpp,MISRA-C++-2023,RULE-19-0-2,Yes,Required,Decidable,Single Translation Unit,Function-like macros shall not be defined,DIR-4-9,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-19-0-3,Yes,Advisory,Decidable,Single Translation Unit,#include directives should only be preceded by preprocessor directives or comments,RULE-20-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-19-0-4,Yes,Advisory,Decidable,Single Translation Unit,#undef should only be used for macros defined previously in the same file,,Preprocessor,Easy, +cpp,MISRA-C++-2023,RULE-19-1-1,Yes,Required,Decidable,Single Translation Unit,The defined preprocessor operator shall be used appropriately,M16-1-1,Preprocessor,Easy, +cpp,MISRA-C++-2023,RULE-19-1-2,No,Required,Decidable,Single Translation Unit,"All #else, #elif and #endif preprocessor directives shall reside in the same file as the #if, #ifdef or #ifndef directive to which they are related",M16-1-2,,, +cpp,MISRA-C++-2023,RULE-19-1-3,Yes,Required,Decidable,Single Translation Unit,All identifiers used in the controlling expression of #if or #elif preprocessing directives shall be defined prior to evaluation,M16-0-7,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-19-2-1,Yes,Required,Decidable,Single Translation Unit,Precautions shall be taken in order to prevent the contents of a header file being included more than once,M16-2-3,Preprocessor,Easy, +cpp,MISRA-C++-2023,RULE-19-2-2,Yes,Required,Decidable,Single Translation Unit,"The #include directive shall be followed by either a or ""filename"" sequence",,Preprocessor,Easy, +cpp,MISRA-C++-2023,RULE-19-2-3,Yes,Required,Decidable,Single Translation Unit,"The ' or "" or \ characters and the /* or // character sequences shall not occur in a header file name",A16-2-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-19-3-1,Yes,Advisory,Decidable,Single Translation Unit,The # and ## preprocessor operators should not be used,M16-3-2,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-19-3-2,Yes,Required,Decidable,Single Translation Unit,A macro parameter immediately following a # operator shall not be immediately followed by a ## operator,RULE-20-11,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-19-3-3,Yes,Required,Decidable,Single Translation Unit,The argument to a mixed-use macro parameter shall not be subject to further expansion,RULE-20-12,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-19-3-4,Yes,Required,Decidable,Single Translation Unit,Parentheses shall be used to ensure macro arguments are expanded appropriately,M16-0-6,Preprocessor,Medium, +cpp,MISRA-C++-2023,RULE-19-3-5,Yes,Required,Decidable,Single Translation Unit,Tokens that look like a preprocessing directive shall not occur within a macro argument,RULE-20-6,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-19-6-1,Yes,Advisory,Decidable,Single Translation Unit,The #pragma directive and the _Pragma operator should not be used,A16-7-1,Preprocessor,Easy, +cpp,MISRA-C++-2023,RULE-21-2-1,Yes,Required,Decidable,Single Translation Unit,"The library functions atof, atoi, atol and atoll from shall not be used",RULE-21-7,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-21-2-2,Yes,Required,Decidable,Single Translation Unit,"The string handling functions from , , and shall not be used",M18-0-5,BannedAPIs,Easy, +cpp,MISRA-C++-2023,RULE-21-2-3,Yes,Required,Decidable,Single Translation Unit,The library function system from shall not be used,M18-0-3,BannedAPIs,Easy, +cpp,MISRA-C++-2023,RULE-21-2-4,Yes,Required,Decidable,Single Translation Unit,The macro offsetof shall not be used,M18-2-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-21-6-1,Yes,Advisory,Undecidable,Single Translation Unit,Dynamic memory should not be used,DIR-4-12,Banned,Easy, +cpp,MISRA-C++-2023,RULE-21-6-2,Yes,Required,Decidable,Single Translation Unit,Dynamic memory shall be managed automatically,,Memory,Easy, +cpp,MISRA-C++-2023,RULE-21-6-3,Yes,Required,Decidable,Single Translation Unit,Advanced memory management shall not be used,,Memory,Medium, +cpp,MISRA-C++-2023,RULE-21-6-4,Yes,Required,Decidable,System,"If a project defines either a sized or unsized version of a global operator delete, then both shall be defined",A18-5-4,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-21-6-5,Yes,Required,Decidable,Single Translation Unit,A pointer to an incomplete class type shall not be deleted,A5-3-3,ImportMisra23,Import, +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-4-1,Yes,Required,Decidable,Single Translation Unit,The literal value zero shall be the only value assigned to errno,,Preconditions,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, +cpp,MISRA-C++-2023,RULE-24-5-2,Yes,Required,Decidable,Single Translation Unit,"The C++ Standard Library functions memcpy, memmove and memcmp from shall not be used",,BannedAPIs,Easy, +cpp,MISRA-C++-2023,RULE-25-5-1,Yes,Required,Decidable,Single Translation Unit,The setlocale and std::locale::global functions shall not be called,,BannedAPIs,Easy, +cpp,MISRA-C++-2023,RULE-25-5-2,Yes,Mandatory,Decidable,Single Translation Unit,"The pointers returned by the C++ Standard Library functions localeconv, getenv, setlocale or strerror must only be used as if they have pointer to const-qualified type",RULE-21-19,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-25-5-3,Yes,Mandatory,Undecidable,System,"The pointer returned by the C++ Standard Library functions asctime, ctime, gmtime, localtime, localeconv, getenv, setlocale or strerror must not be used following a subsequent call to the same function",RULE-21-20,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-26-3-1,Yes,Advisory,Decidable,Single Translation Unit,std::vector should not be specialized with bool,A18-1-2,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-28-3-1,Yes,Required,Undecidable,System,Predicates shall not have persistent side effects,A25-1-1,SideEffects3,Easy, +cpp,MISRA-C++-2023,RULE-28-6-1,Yes,Required,Decidable,Single Translation Unit,The argument to std::move shall be a non-const lvalue,A18-9-3,Preconditions,Easy, +cpp,MISRA-C++-2023,RULE-28-6-2,Yes,Required,Decidable,Single Translation Unit,Forwarding references and std::forward shall be used together,A18-9-2,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-28-6-3,Yes,Required,Decidable,Single Translation Unit,An object shall not be used while in a potentially moved-from state,A12-8-3,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-28-6-4,Yes,Required,Decidable,Single Translation Unit,"The result of std::remove, std::remove_if, std::unique and empty shall be used",,DeadCode2,Easy, +cpp,MISRA-C++-2023,RULE-30-0-1,Yes,Required,Decidable,Single Translation Unit,The C Library input/output functions shall not be used,M27-0-1,ImportMisra23,Import, +cpp,MISRA-C++-2023,RULE-30-0-2,Yes,Required,Undecidable,System,Reads and writes on the same file stream shall be separated by a positioning operation,A27-0-3,ImportMisra23,Import, diff --git a/schemas/rule-package.schema.json b/schemas/rule-package.schema.json index 4d3c7f401a..fff79fede0 100644 --- a/schemas/rule-package.schema.json +++ b/schemas/rule-package.schema.json @@ -141,7 +141,8 @@ "obligation": { "type": "string", "enum": [ - "rule" + "rule", + "recommendation" ] } }, @@ -179,6 +180,58 @@ "type": "object", "patternProperties": { "^RULE-\\d+-\\d+": { + "description": "A coding standard rule", + "type": "object", + "properties": { + "properties": { + "type": "object", + "properties": { + "obligation": { + "type": "string", + "enum": [ + "required", + "advisory", + "mandatory" + ] + } + }, + "required": [ + "obligation" + ] + }, + "queries": { + "type": "array", + "uniqueItems": true, + "items": { + "$ref": "#/$defs/query" + } + }, + "title": { + "type": "string" + }, + "implementation_scope": { + "$ref": "#/$defs/implementation_scope" + } + }, + "required": [ + "properties", + "queries", + "title" + ], + "additionalProperties": false + } + }, + "minProperties": 1 + } + } + }, + { + "properties": { + "MISRA-C++-2023": { + "description": "Rules part of the MISRA C++ 2023 standard", + "type": "object", + "patternProperties": { + "^RULE-\\d+-\\d+-\\d+": { "description": "A coding standard rule", "type": "object", "properties": { @@ -289,27 +342,41 @@ "external/cert/default-disabled", "external/autosar/strict", "scope/single-translation-unit", - "scope/system" + "scope/system", + "external/misra/audit", + "external/misra/c/2012/third-edition-first-revision", + "external/misra/c/2012/amendment2", + "external/misra/c/2012/amendment3", + "external/misra/c/2012/amendment4", + "external/misra/c/strict", + "external/cert/severity/low", + "external/cert/severity/medium", + "external/cert/severity/high", + "external/cert/likelihood/unlikely", + "external/cert/likelihood/probable", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/remediation-cost/medium", + "external/cert/remediation-cost/high", + "external/cert/priority/p1", + "external/cert/priority/p2", + "external/cert/priority/p3", + "external/cert/priority/p4", + "external/cert/priority/p6", + "external/cert/priority/p8", + "external/cert/priority/p9", + "external/cert/priority/p12", + "external/cert/priority/p18", + "external/cert/priority/p27", + "external/cert/level/l1", + "external/cert/level/l2", + "external/cert/level/l3" ] }, "minLength": 1 }, "implementation_scope": { - "type": "object", - "properties": { - "description": { - "kind": "string" - }, - "items": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "description" - ] + "$ref": "/schemas/implementation_scope" } }, "required": [ @@ -320,6 +387,25 @@ "short_name", "tags" ] + }, + "implementation_scope": { + "$id": "/schemas/implementation_scope", + "type": "object", + "properties": { + "description": { + "kind": "string" + }, + "items": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "description" + ], + "additionalProperties": false } } } \ No newline at end of file diff --git a/scripts/PSCodingStandards/Config.ps1 b/scripts/PSCodingStandards/Config.ps1 index 2dc8d8e5bc..53605c89f3 100644 --- a/scripts/PSCodingStandards/Config.ps1 +++ b/scripts/PSCodingStandards/Config.ps1 @@ -1,2 +1,2 @@ -$AVAILABLE_SUITES = @("CERT-C++", "AUTOSAR", "MISRA-C-2012", "CERT-C") +$AVAILABLE_SUITES = @("CERT-C++", "AUTOSAR", "MISRA-C-2012", "CERT-C", "MISRA-C++-2023") $AVAILABLE_LANGUAGES = @("c", "cpp") \ No newline at end of file diff --git a/scripts/PSCodingStandards/Get-TestDirectory.ps1 b/scripts/PSCodingStandards/Get-TestDirectory.ps1 index 341cb3d7d9..154a49dabe 100644 --- a/scripts/PSCodingStandards/Get-TestDirectory.ps1 +++ b/scripts/PSCodingStandards/Get-TestDirectory.ps1 @@ -27,6 +27,9 @@ function Get-TestDirectory { elseif ($RuleObject.__memberof_suite -eq "MISRA-C-2012") { $standardString = "misra" } + elseif ($RuleObject.__memberof_suite -eq "MISRA-C++-2023") { + $standardString = "misra" + } else { throw "Unknown standard $($RuleObject.__memberof_suite)" } diff --git a/scripts/add_risk_assessment_tags.py b/scripts/add_risk_assessment_tags.py new file mode 100644 index 0000000000..6560d82a44 --- /dev/null +++ b/scripts/add_risk_assessment_tags.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python3 +""" +Add risk assessment tags to rule package JSON files. + +This script: +1. Iterates through each JSON file in rule_packages directory +2. Looks for CERT-C or CERT-CPP sections +3. For each rule, finds the corresponding markdown file +4. Extracts risk assessment data from the markdown file +5. Adds risk assessment data as tags to each query in the JSON file +""" + +import os +import json +import re +import glob +from bs4 import BeautifulSoup +import logging + +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +logger = logging.getLogger(__name__) + +def find_rule_packages(): + """Find all JSON rule package files in the rule_packages directory.""" + repo_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + rule_packages_dir = os.path.join(repo_root, "rule_packages") + return glob.glob(os.path.join(rule_packages_dir, "**", "*.json"), recursive=True) + +def extract_risk_assessment_from_md(md_file_path): + """Extract risk assessment data from the markdown file.""" + risk_data = {} + + try: + with open(md_file_path, 'r', encoding='utf-8') as f: + content = f.read() + + # Find the Risk Assessment section + risk_section_match = re.search(r'## Risk Assessment(.*?)##', content, re.DOTALL) + if not risk_section_match: + # Try to find it as the last section + risk_section_match = re.search(r'## Risk Assessment(.*?)$', content, re.DOTALL) + if not risk_section_match: + logger.warning(f"No Risk Assessment section found in {md_file_path}") + return risk_data + + risk_section = risk_section_match.group(1) + + # Look for the table with risk assessment data + table_match = re.search(r'(.*?)
', risk_section, re.DOTALL) + if not table_match: + logger.warning(f"No risk assessment table found in {md_file_path}") + return risk_data + + table_html = table_match.group(0) + soup = BeautifulSoup(table_html, 'html.parser') + + # Find all rows in the table + rows = soup.find_all('tr') + if len(rows) < 2: # Need at least header and data row + logger.warning(f"Incomplete risk assessment table in {md_file_path}") + return risk_data + + # Extract headers and values + headers = [th.get_text().strip() for th in rows[0].find_all('th')] + values = [td.get_text().strip() for td in rows[1].find_all('td')] + + # Create a dictionary of headers and values + if len(headers) == len(values): + for i, header in enumerate(headers): + risk_data[header] = values[i] + else: + logger.warning(f"Header and value count mismatch in {md_file_path}") + + except Exception as e: + logger.error(f"Error extracting risk assessment from {md_file_path}: {e}") + + return risk_data + +def find_md_file(rule_id, short_name, language): + """Find the markdown file for the given rule ID and short name.""" + repo_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + md_path = os.path.join(repo_root, language, "cert", "src", "rules", rule_id, f"{short_name}.md") + + if os.path.exists(md_path): + return md_path + else: + # Try without short name (sometimes the file is named after the rule ID) + md_path = os.path.join(repo_root, language, "cert", "src", "rules", rule_id, f"{rule_id}.md") + if os.path.exists(md_path): + return md_path + else: + logger.warning(f"Could not find markdown file for {language} rule {rule_id} ({short_name})") + return None + +def process_rule_package(rule_package_file): + """Process a single rule package JSON file.""" + try: + with open(rule_package_file, 'r', encoding='utf-8') as f: + data = json.load(f) + + modified = False + + # Look for CERT-C and CERT-CPP sections + for cert_key in ["CERT-C", "CERT-C++"]: + if cert_key in data: + language = "c" if cert_key == "CERT-C" else "cpp" + + # Process each rule in the CERT section + for rule_id, rule_data in data[cert_key].items(): + if "queries" in rule_data: + for query in rule_data["queries"]: + if "short_name" in query: + md_file = find_md_file(rule_id, query["short_name"], language) + + if md_file: + risk_data = extract_risk_assessment_from_md(md_file) + + if risk_data: + # Add risk assessment data as tags + if "tags" not in query: + query["tags"] = [] + + # Add each risk assessment property as a tag + for key, value in risk_data.items(): + key_sanitized = key.lower().replace(" ", "-") + if key_sanitized == "rule" or key_sanitized == "recommendation": + # skip rule/recommendation as they just repeat the rule ID + continue + tag = f"external/cert/{key_sanitized}/{value.lower()}" + if tag not in query["tags"]: + query["tags"].append(tag) + modified = True + logger.info(f"Added tag {tag} to {rule_id} ({query['short_name']})") + + # Save the modified data back to the file if any changes were made + if modified: + with open(rule_package_file, 'w', encoding='utf-8') as f: + json.dump(data, f, indent=2) + logger.info(f"Updated {rule_package_file}") + else: + logger.info(f"No changes made to {rule_package_file}") + + except Exception as e: + logger.error(f"Error processing {rule_package_file}: {e}") + +def main(): + """Main function to process all rule packages.""" + logger.info("Starting risk assessment tag addition process") + + rule_packages = find_rule_packages() + logger.info(f"Found {len(rule_packages)} rule package files") + + for rule_package in rule_packages: + logger.info(f"Processing {rule_package}") + process_rule_package(rule_package) + + logger.info("Completed risk assessment tag addition process") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/scripts/generate_modules/queries/codeql-pack.lock.yml b/scripts/generate_modules/queries/codeql-pack.lock.yml index 514e6963d0..a45ea8f438 100644 --- a/scripts/generate_modules/queries/codeql-pack.lock.yml +++ b/scripts/generate_modules/queries/codeql-pack.lock.yml @@ -2,13 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.9.3 + version: 4.0.3 codeql/dataflow: - version: 0.0.4 + version: 2.0.3 + codeql/mad: + version: 1.0.19 + codeql/rangeanalysis: + version: 1.0.19 codeql/ssa: - version: 0.1.5 + version: 1.0.19 codeql/tutorial: - version: 0.1.5 + version: 1.0.19 + codeql/typeflow: + version: 1.0.19 + codeql/typetracking: + version: 2.0.3 codeql/util: - version: 0.1.5 + version: 2.0.6 + codeql/xml: + version: 1.0.19 compiled: false diff --git a/scripts/generate_modules/queries/qlpack.yml b/scripts/generate_modules/queries/qlpack.yml index 4f3768cd79..9aabee2562 100644 --- a/scripts/generate_modules/queries/qlpack.yml +++ b/scripts/generate_modules/queries/qlpack.yml @@ -2,4 +2,4 @@ name: codeql/standard-library-extraction-cpp-coding-standards version: 0.0.0 license: MIT dependencies: - codeql/cpp-all: 0.9.3 + codeql/cpp-all: 4.0.3 diff --git a/scripts/generate_rules/coding_standards_utils.py b/scripts/generate_rules/coding_standards_utils.py index 6f96460ef7..b0bcd48443 100644 --- a/scripts/generate_rules/coding_standards_utils.py +++ b/scripts/generate_rules/coding_standards_utils.py @@ -19,8 +19,10 @@ def split_camel_case(short_name : str) -> List[str]: """Split a camel case string to a list.""" + # Edge case, turn FooNaNBar into foo-nan-bar instead of foo-na-n-bar by a preprocessing step. + nan_fixed = short_name.replace("NaN", "Nan") matches = re.finditer( - ".+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)", short_name) + ".+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)", nan_fixed) return [m.group(0) for m in matches] diff --git a/scripts/generate_rules/generate_package_description.py b/scripts/generate_rules/generate_package_description.py index 20c9adc065..843d3bd78f 100644 --- a/scripts/generate_rules/generate_package_description.py +++ b/scripts/generate_rules/generate_package_description.py @@ -110,6 +110,8 @@ def generate_short_name(title): print("Error: " + standard + " " + rule_id + " is marked as part of package " + package_name + " but is not marked as supportable.") sys.exit(1) + tags = [] + # Add the AUTOSAR obligation, enforcement and allocated target as query properties. properties = {} if obligation_level: @@ -117,7 +119,15 @@ def generate_short_name(title): if enforcement_level: properties["enforcement"] = enforcement_level.lower() if allocated_targets: - properties["allocated-target"] = [target.strip(' ').lower() for target in allocated_targets.split("/")] + if allocated_targets == "Single Translation Unit": + # MISRA C++ 2023 uses the allocated targets field for scope + tags.append("scope/single-translation-unit") + elif allocated_targets == "System": + # MISRA C++ 2023 uses the allocated targets field for scope + tags.append("scope/system") + else: + properties["allocated-target"] = [target.strip(' ').lower() for target in allocated_targets.split("/")] + if difficulty == "Audit": properties["audit"] = "" @@ -164,7 +174,7 @@ def generate_short_name(title): "severity" : severity, "description" : description, "kind" : "problem", - "tags" : [] + "tags" : tags } ] } @@ -187,11 +197,10 @@ def generate_short_name(title): json.dump(package_description, rule_package_file, indent=2, sort_keys=True) print("Rule package file generated at " + str(rule_package_file_path) + ".") print("") - print("A default query has been generated for each for each rule. Please review each rule in the generated JSON file and:") + print("A default query has been generated for each rule. Please review each rule in the generated JSON file and:") print(" (1) Add additional queries as required") print(" (2) Confirm that the following auto-generated properties are appropriate:") - print(" - 'camel_name'.") print(" - 'precision'.") - print(" - 'query_name'.") + print(" - 'short_name'.") print(" - 'severity'.") print(" (3) Add additional 'tags' as required, particularly 'security' or 'correctness'.") diff --git a/scripts/generate_rules/generate_package_files.py b/scripts/generate_rules/generate_package_files.py index 6dabec0a92..862ccfdc1e 100644 --- a/scripts/generate_rules/generate_package_files.py +++ b/scripts/generate_rules/generate_package_files.py @@ -58,11 +58,15 @@ "MISRA-C-2012" : { "standard_title" : "MISRA-C:2012 Guidelines for the use of the C language in critical systems", "standard_url" : "https://www.misra.org.uk/" + }, + "MISRA-C++-2023" : { + "standard_title" : "MISRA C++:2023 Guidelines for the use C++:17 in critical systems", + "standard_url" : "https://misra.org.uk/product/misra-cpp2023/" } } # The help files of these standards cannot be distributed in our repository. -external_help_file_standards = ["AUTOSAR", "MISRA-C-2012"] +external_help_file_standards = ["AUTOSAR", "MISRA-C-2012", "MISRA-C++-2023"] # Mapping from the QL language to source file extension used to generate a help example file. ql_language_ext_mappings = { @@ -188,6 +192,9 @@ def write_shared_implementation(package_name, rule_id, query, language_name, ql_ if len(class_name) > 61: # Line break required after comma f.write("\n TestQuery\n{ }\n") + elif len(class_name) == 61: + # Line break required before `{` + f.write(" TestQuery\n{ }\n") elif len(class_name) > 57: # Line break required after `{` f.write(" TestQuery {\n}\n") diff --git a/scripts/generate_rules/templates/misra-c++-2023-help.md.template b/scripts/generate_rules/templates/misra-c++-2023-help.md.template new file mode 100644 index 0000000000..4fb7b17ee8 --- /dev/null +++ b/scripts/generate_rules/templates/misra-c++-2023-help.md.template @@ -0,0 +1,49 @@ +# {{ rule_id }}: {{ name }} + +This query implements the {{ standard_name | escape }} rule {{ rule_id | escape }}: + +> {{ rule_title }} + +## Classification + +** REPLACE THIS WITH THE CORRECT CLASSIFICATION ** +* required +* implementation +* automated + +## Rationale + +**REPLACE THIS WITH RATIONAL, IF ANY** + +## Exception + +**REPLACE THIS WITH EXCEPTION, IF ANY** + +## Example + +```cpp +// REPLACE THIS WITH C++ EXAMPLE, IF ANY +``` + +## See more + +** REPLACE THIS WITH THE ANY SEE MORE REFERENCES ** + +## Implementation notes + +{% if implementation_scope is defined %} +{{ implementation_scope["description"] }} +{% if implementation_scope["items"] is iterable %} +{% for implementation_scope_entry in implementation_scope["items"] %} +* {{ implementation_scope_entry }} +{% endfor %} +{% endif %} +{% else %} +None +{% endif %} + +## References + +{% if standard_title | length %} +* {{ standard_title | escape }}: [{{ rule_id }}: {{ rule_title }}]({{ standard_url }}) +{% endif %} diff --git a/scripts/generate_rules/templates/shared_library.ql.template b/scripts/generate_rules/templates/shared_library.ql.template index 24431edcc7..93dc503510 100644 --- a/scripts/generate_rules/templates/shared_library.ql.template +++ b/scripts/generate_rules/templates/shared_library.ql.template @@ -1,5 +1,10 @@ +{# + The autogenerated description of the shared query is copied from + the first matching query in `rule_packages`. +#} /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library with a `problems` predicate for the following issue: + * {{ description|join('\n * ') }} */ import cpp diff --git a/scripts/help/cert-help-extraction.py b/scripts/help/cert-help-extraction.py index 6bd1abccd5..f785b0955f 100755 --- a/scripts/help/cert-help-extraction.py +++ b/scripts/help/cert-help-extraction.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 from argparse import ArgumentParser +from typing import Generator import tempfile import re import urllib.request @@ -23,6 +24,7 @@ CERT_WIKI = "https://wiki.sei.cmu.edu" RULES_LIST_C = "/confluence/display/c/2+Rules" +RECOMMENDED_LIST_C = "/confluence/display/c/3+Recommendations" RULES_LIST_CPP = "/confluence/display/cplusplus/2+Rules" cache_path = script_path.parent / '.cache' @@ -47,16 +49,22 @@ def soupify(url: str) -> BeautifulSoup: return BeautifulSoup(content, 'html.parser') - -def get_rules(): - rules = [] - for soup in [soupify(f"{CERT_WIKI}{RULES_LIST_C}"), soupify(f"{CERT_WIKI}{RULES_LIST_CPP}")]: +def get_rule_listings() -> Generator[Tag, None, None]: + for rule_list_id in [RULES_LIST_C, RULES_LIST_CPP]: + soup = soupify(f"{CERT_WIKI}{rule_list_id}") if soup == None: - return None - - rule_listing_start = soup.find( + continue + + yield soup.find( "h1", string="Rule Listing") + soup = soupify(f"{CERT_WIKI}{RECOMMENDED_LIST_C}") + if soup != None: + yield soup.find("h1", string="Recommendation Listing") + +def get_rules(): + rules = [] + for rule_listing_start in get_rule_listings(): for link in rule_listing_start.next_element.next_element.find_all('a'): if '-C' in link.string: rule, title = map(str.strip, link.string.split('.', 1)) @@ -214,6 +222,8 @@ def helper(node): # Fix a broken url present in many CERT-C pages if node.name == 'a' and 'href' in node.attrs and node['href'] == "http://BB. Definitions#vulnerability": node['href'] = "https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability" + elif node.name == 'a' and 'href' in node.attrs and node['href'] == "http://BB. Definitions#unexpected behavior": + node['href'] = "https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unexpectedbehavior" # Turn relative URLs into absolute URLS elif node.name == 'a' and 'href' in node.attrs and node['href'].startswith("/confluence"): node['href'] = f"{CERT_WIKI}{node['href']}" diff --git a/scripts/matrix_testing/CreateMatrixTestReport.ps1 b/scripts/matrix_testing/CreateMatrixTestReport.ps1 index 6f570c1b82..a8de5034ce 100644 --- a/scripts/matrix_testing/CreateMatrixTestReport.ps1 +++ b/scripts/matrix_testing/CreateMatrixTestReport.ps1 @@ -147,9 +147,9 @@ param( $Configuration, # For a suite, the suites we support. Valid values are 'CERT-C++' and - # 'AUTOSAR' and MISRA-C-2012 and CERT-C + # 'AUTOSAR' and MISRA-C-2012, MISRA-C++-2023 and CERT-C [Parameter(Mandatory, ParameterSetName = 'Suite')] - [ValidateSet("CERT-C++", "AUTOSAR", "MISRA-C-2012", "CERT-C")] + [ValidateSet("CERT-C++", "AUTOSAR", "MISRA-C-2012", "CERT-C", "MISRA-C++-2023")] [string] $SuiteName, diff --git a/scripts/release/bump-version.sh b/scripts/release/bump-version.sh index fd5ab5ea0d..5bbd0eeae0 100755 --- a/scripts/release/bump-version.sh +++ b/scripts/release/bump-version.sh @@ -15,6 +15,7 @@ find . -name 'qlpack.yml' | grep -v './codeql_modules' | grep -v './scripts' | x # update the documentation. find docs -name 'user_manual.md' -print0 | xargs -0 sed -i "s/code-scanning-cpp-query-pack-.*\.zip\`/code-scanning-cpp-query-pack-${1}.zip\`/" +find docs -name 'user_manual.md' -print0 | xargs -0 sed -i "s/coding-standard-codeql-pack-.*\.zip\`/coding-standard-codeql-pack-${1}.zip\`/" find docs -name 'user_manual.md' -print0 | xargs -0 sed -i "s/supported_rules_list_.*\.csv\`/supported_rules_list_${1}.csv\`/" find docs -name 'user_manual.md' -print0 | xargs -0 sed -i "s/supported_rules_list_.*\.md\`/supported_rules_list_${1}.md\`/" find docs -name 'user_manual.md' -print0 | xargs -0 sed -i "s/user_manual_.*\.md\`/user_manual_${1}.md\`/" diff --git a/scripts/release/create_supported_rules_list.py b/scripts/release/create_supported_rules_list.py index e3294ed3b1..6d8f3e0991 100644 --- a/scripts/release/create_supported_rules_list.py +++ b/scripts/release/create_supported_rules_list.py @@ -27,7 +27,7 @@ repo_root = Path(__file__).parent.parent.parent -rules_covered = {"AUTOSAR" : {}, "CERT-C++" : {}, "MISRA-C-2012" : {}, "CERT-C" : {}} +rules_covered = {"AUTOSAR" : {}, "CERT-C++" : {}, "MISRA-C-2012" : {}, "CERT-C" : {}, "MISRA-C++-2023" : {},} # Iterate over rule packages for language_name in ["cpp", "c"]: diff --git a/scripts/release/generate_release_notes.py b/scripts/release/generate_release_notes.py index c6cea8d19f..3852a5eeb7 100644 --- a/scripts/release/generate_release_notes.py +++ b/scripts/release/generate_release_notes.py @@ -79,7 +79,7 @@ def transform_legacy_rule_path(p): diff_from_last_release = latest_release_commit.diff(head_commit) # Store a mapping from standard -> rules with new queries -> new queries for those rules -new_rules = {"AUTOSAR" : {}, "CERT-C++" : {}, "MISRA-C-2012" : {}, "CERT-C" : {}} +new_rules = {"AUTOSAR" : {}, "CERT-C++" : {}, "MISRA-C-2012" : {}, "CERT-C" : {}, "MISRA-C++-2023" : {}} # Store the text of the newly added change notes change_notes = [] # Store the names of the rule packages with new queries diff --git a/scripts/release/release-layout.yml b/scripts/release/release-layout.yml index 5e496120f2..4ced0b4d30 100644 --- a/scripts/release/release-layout.yml +++ b/scripts/release/release-layout.yml @@ -10,6 +10,10 @@ layout: - workflow-artifact: name: "Code Scanning Query Pack Generation" artifact: code-scanning-cpp-query-pack.zip + coding-standards-codeql-packs.zip: + - workflow-artifact: + name: "Code Scanning Query Pack Generation" + artifact: coding-standards-codeql-packs supported_rules_list.csv: - shell: | python ${{ coding-standards.root }}/scripts/release/create_supported_rules_list.py --csv > supported_rules_list.csv diff --git a/scripts/release/requirements.txt b/scripts/release/requirements.txt index 5cdcc51546..653323eaaa 100644 --- a/scripts/release/requirements.txt +++ b/scripts/release/requirements.txt @@ -1,5 +1,5 @@ semantic-version==2.10.0 PyGithub==1.59.1 PyYAML==6.0.1 -GitPython==3.1.37 +GitPython==3.1.41 pytest==7.4.3 diff --git a/scripts/release/webhook-handler.js b/scripts/release/webhook-handler.js new file mode 100644 index 0000000000..6197bedb48 --- /dev/null +++ b/scripts/release/webhook-handler.js @@ -0,0 +1,229 @@ +/** + * This function should be installed as an Azure Function with a HTTP trigger and configured as a GitHub webhook. + * It expects the following environment variables to be set: + * - GITHUB_APP_ID: the ID of the GitHub App used to authenticate + * - GITHUB_APP_INSTALLATION_ID: the ID of the GitHub App installation + * - GITHUB_APP_PRIVATE_KEY: the private key of the GitHub App + * - GITHUB_WEBHOOK_SECRET: the secret used to sign the webhook + * - GITHUB_WORKFLOW_ID: the ID of the workflow to trigger, this should be the id of the workflow `update-release-status.yml` + */ +const crypto = require('crypto'); +const { Buffer } = require('buffer'); +const https = require('https'); + +function encode(obj) { + return Buffer.from(JSON.stringify(obj)).toString('base64url'); +} + +function createJwtToken() { + + const signingKey = crypto.createPrivateKey(Buffer.from(process.env['GITHUB_APP_PRIVATE_KEY'], 'base64')); + + const claims = { + // Issue 60 seconds in the past to account for clock drift. + iat: Math.floor(Date.now() / 1000) - 60, + // The token is valid for 1 minute(s). + exp: Math.floor(Date.now() / 1000) + (1 * 60), + iss: process.env["GITHUB_APP_ID"] + }; + + const header = { + alg: "RS256", + typ: "JWT" + }; + + const payload = `${encode(header)}.${encode(claims)}`; + const signer = crypto.createSign('RSA-SHA256'); + const signature = (signer.update(payload), signer.sign(signingKey, 'base64url')); + + return `${payload}.${signature}`; +} + +function createAccessToken(context) { + return new Promise((resolve, reject) => { + const options = { + hostname: 'api.github.com', + path: `/app/installations/${process.env["GITHUB_APP_INSTALLATION_ID"]}/access_tokens`, + method: 'POST' + }; + + const req = https.request(options, (res) => { + res.on('data', (data) => { + const body = JSON.parse(data.toString('utf8')); + access_token = body.token; + //context.log(access_token); + resolve(access_token); + }); + + res.on('error', (error) => { + reject(error); + }) + }); + + req.setHeader('Accept', 'application/vnd.github+json'); + const token = createJwtToken(); + //context.log(`JWT Token ${token}`); + req.setHeader('Authorization', `Bearer ${token}`); + req.setHeader('X-GitHub-Api-Version', '2022-11-28'); + req.setHeader('User-Agent', 'CodeQL Coding Standards Automation'); + + req.end(); + }); +} + +function triggerReleaseUpdate(context, access_token, head_sha) { + context.log(`Triggering release update for head sha ${head_sha}`) + return new Promise((resolve, reject) => { + const options = { + hostname: 'api.github.com', + path: `/repos/github/codeql-coding-standards/actions/workflows/${process.env["GITHUB_WORKFLOW_ID"]}/dispatches`, + method: 'POST' + }; + + const req = https.request(options, (res) => { + res.on('error', (error) => { + reject(error); + }) + }); + + req.setHeader('Accept', 'application/vnd.github+json'); + req.setHeader('Authorization', `Bearer ${access_token}`); + req.setHeader('X-GitHub-Api-Version', '2022-11-28'); + req.setHeader('User-Agent', 'CodeQL Coding Standards Automation'); + + const params = { + ref: 'main', + inputs: { + "head-sha": head_sha + } + }; + req.on('response', (response) => { + context.log(`Received status code ${response.statusCode} with message ${response.statusMessage}`); + resolve(); + }); + req.end(JSON.stringify(params)); + }); +} + +function listCheckRunsForRefPerPage(context, access_token, ref, page = 1) { + context.log(`Listing check runs for ${ref}`) + return new Promise((resolve, reject) => { + const options = { + hostname: 'api.github.com', + path: `/repos/github/codeql-coding-standards/commits/${ref}/check-runs?page=${page}&per_page=100`, + method: 'GET', + headers: { + 'Accept': 'application/vnd.github+json', + 'Authorization': `Bearer ${access_token}`, + 'X-GitHub-Api-Version': '2022-11-28', + 'User-Agent': 'CodeQL Coding Standards Automation' + } + }; + + const req = https.request(options, (res) => { + if (res.statusCode != 200) { + reject(`Received status code ${res.statusCode} with message ${res.statusMessage}`); + } else { + var body = []; + res.on('data', (chunk) => { + body.push(chunk); + }); + res.on('end', () => { + try { + body = JSON.parse(Buffer.concat(body).toString('utf8')); + resolve(body); + } catch (error) { + reject(error); + } + }); + } + }); + req.on('error', (error) => { + reject(error); + }); + + req.end(); + }); +} + +async function listCheckRunsForRef(context, access_token, ref) { + let page = 1; + let check_runs = []; + const first_page = await listCheckRunsForRefPerPage(context, access_token, ref, page); + check_runs = check_runs.concat(first_page.check_runs); + while (first_page.total_count > check_runs.length) { + page++; + const next_page = await listCheckRunsForRefPerPage(context, access_token, ref, page); + check_runs = check_runs.concat(next_page.check_runs); + } + return check_runs; +} + +function hasReleaseStatusCheckRun(check_runs) { + return check_runs.some(check_run => check_run.name == 'release-status'); +} + +function isValidSignature(req) { + const hmac = crypto.createHmac("sha256", process.env["GITHUB_WEBHOOK_SECRET"]); + const signature = hmac.update(JSON.stringify(req.body)).digest('hex'); + const shaSignature = `sha256=${signature}`; + const gitHubSignature = req.headers['x-hub-signature-256']; + + return !shaSignature.localeCompare(gitHubSignature); +} + +module.exports = async function (context, req) { + context.log('Webhook received.'); + + if (isValidSignature(req)) { + const event = req.headers['x-github-event']; + + if (event == 'check_run') { + webhook = req.body; + + // To avoid infinite loops, we skip triggering the workflow for the following checkruns. + const check_runs_to_skip = [ + // check run created by manual dispatch of Update Release workflow + 'Update release', + // check runs created by job in Update release status workflow + 'update-release', + // when update-release calls reusable workflow Update release + 'update-release / Update release', + 'validate-check-runs', + // check run that validates the whole release + 'release-status']; + const update_release_actions = ['completed', 'rerequested']; + + if (update_release_actions.includes(webhook.action) && !check_runs_to_skip.includes(webhook.check_run.name)) { + context.log(`Triggering update release status because ${webhook.check_run.name} received action ${webhook.action}`); + + try { + const access_token = await createAccessToken(context); + const check_runs = await listCheckRunsForRef(context, access_token, webhook.check_run.head_sha); + if (hasReleaseStatusCheckRun(check_runs)) { + context.log(`Release status check run found for ${webhook.check_run.head_sha}`); + await triggerReleaseUpdate(context, access_token, webhook.check_run.head_sha); + } else { + context.log(`Skippping, no release status check run found for ${webhook.check_run.head_sha}`); + } + } catch (error) { + context.log(`Failed with error: ${error}`); + } + } else { + context.log(`Skipping action ${webhook.action} for ${webhook.check_run.name}`) + } + } else { + context.log(`Skipping event: ${event}`) + } + + context.res = { + status: 200 + }; + } else { + context.log('Received invalid GitHub signature') + context.res = { + status: 401, + body: 'Invalid x-hub-signature-256 value' + }; + } +} \ No newline at end of file diff --git a/scripts/reports/test-data/deviations/invalid/coding-standards.yml b/scripts/reports/test-data/deviations/invalid/coding-standards.yml index 7b12c7a8c2..1ce8cc718a 100644 --- a/scripts/reports/test-data/deviations/invalid/coding-standards.yml +++ b/scripts/reports/test-data/deviations/invalid/coding-standards.yml @@ -44,8 +44,8 @@ deviations: permit-id: non-existing-permit - permit-id: DP1 - permit-id: DP2 - - rule-id: RULE-13-6 - query-id: c/misra/sizeof-operand-with-side-effect + - rule-id: RULE-9-1 + query-id: c/misra/object-with-auto-storage-duration-read-before-init deviation-permits: - permit-id: DP1 justification: foo bar baz diff --git a/scripts/reports/test-data/guideline-recategorizations/guideline_recategorizations_report.md.expected b/scripts/reports/test-data/guideline-recategorizations/guideline_recategorizations_report.md.expected index 54fb25ae83..425eba1bc3 100644 --- a/scripts/reports/test-data/guideline-recategorizations/guideline_recategorizations_report.md.expected +++ b/scripts/reports/test-data/guideline-recategorizations/guideline_recategorizations_report.md.expected @@ -13,7 +13,7 @@ | A0-1-1 | required | advisory | | A0-1-1 | required | mandatory | | A0-1-2 | required | disapplied | -| RULE-13-6 | mandatory | required | +| RULE-9-1 | mandatory | required | | CON50-CPP | rule | required | | A0-1-6 | advisory | disapplied | | A10-4-1 | advisory | required | @@ -25,5 +25,5 @@ | invalid/coding-standards.xml:5:7:8:43 | 'Invalid recategorization from 'required' to 'advisory'.' for rule A0-1-1. | | invalid/coding-standards.xml:9:7:12:43 | 'Invalid recategorization from 'required' to 'disapplied'.' for rule A0-1-2. | | invalid/coding-standards.xml:13:7:16:43 | 'Unknown rule id 'A1-4-3'.' for rule A1-4-3. | -| invalid/coding-standards.xml:17:7:20:43 | 'Invalid recategorization from 'mandatory' to 'required'.' for rule RULE-13-6. | +| invalid/coding-standards.xml:17:7:20:43 | 'Invalid recategorization from 'mandatory' to 'required'.' for rule RULE-9-1. | | invalid/coding-standards.xml:21:7:24:43 | 'Invalid recategorization from 'rule' to 'required'.' for rule CON50-CPP. | diff --git a/scripts/reports/test-data/guideline-recategorizations/invalid/coding-standards.yml b/scripts/reports/test-data/guideline-recategorizations/invalid/coding-standards.yml index 89e562c05c..cd6abbf120 100644 --- a/scripts/reports/test-data/guideline-recategorizations/invalid/coding-standards.yml +++ b/scripts/reports/test-data/guideline-recategorizations/invalid/coding-standards.yml @@ -5,7 +5,7 @@ guideline-recategorizations: category: "disapplied" - rule-id: "A1-4-3" category: "mandatory" - - rule-id: "RULE-13-6" + - rule-id: "RULE-9-1" category: "required" - rule-id: "CON50-CPP" category: "required" diff --git a/scripts/reports/utils.py b/scripts/reports/utils.py index 977826891c..6f5785808e 100644 --- a/scripts/reports/utils.py +++ b/scripts/reports/utils.py @@ -149,7 +149,7 @@ def __init__(self, sarif_results_file_path): if standard_rule_id in self.guideline_obligation_level[standard_short_name]: if not self.guideline_obligation_level[standard_short_name][standard_rule_id] == obligation_level: print( - f"WARNING: Rule { rule['id'] } specifies a conflicting obligation level of { obligation_level }, was previously specified as { guideline_obligation_level[standard_short_name][standard_rule_id] }.") + f"WARNING: Rule { rule['id'] } specifies a conflicting obligation level of { obligation_level }, was previously specified as { self.guideline_obligation_level[standard_short_name][standard_rule_id] }.") else: self.guideline_obligation_level[standard_short_name][standard_rule_id] = obligation_level # Add deviation counts for the rule diff --git a/scripts/requirements.txt b/scripts/requirements.txt index 0ad0f1c747..8a240a6dab 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -2,7 +2,7 @@ beautifulsoup4==4.9.3 certifi==2023.7.22 chardet==3.0.4 gitdb==4.0.5 -GitPython==3.1.37 +GitPython==3.1.41 idna==2.10 Jinja2==2.11.3 MarkupSafe==1.1.1 diff --git a/scripts/upgrade-codeql-dependencies/requirements.txt b/scripts/upgrade-codeql-dependencies/requirements.txt index 009d2dc5aa..55b810e4aa 100644 --- a/scripts/upgrade-codeql-dependencies/requirements.txt +++ b/scripts/upgrade-codeql-dependencies/requirements.txt @@ -4,3 +4,4 @@ idna==3.4 requests==2.31.0 semantic-version==2.10.0 urllib3==1.26.18 +pyyaml==6.0.1 \ No newline at end of file diff --git a/scripts/upgrade-codeql-dependencies/upgrade-codeql-dependencies.py b/scripts/upgrade-codeql-dependencies/upgrade-codeql-dependencies.py index 6c98216ca0..c76303e654 100644 --- a/scripts/upgrade-codeql-dependencies/upgrade-codeql-dependencies.py +++ b/scripts/upgrade-codeql-dependencies/upgrade-codeql-dependencies.py @@ -1,18 +1,23 @@ import json import requests -from typing import Optional, Dict, List +from typing import Optional, Dict, List, Tuple from semantic_version import Version from pathlib import Path +import yaml SCRIPT_PATH = Path(__file__) -SUPPORTED_VERSIONS_PATH = SCRIPT_PATH.parent.parent.parent / "supported_codeql_configs.json" +CODING_STANDARDS_ROOT = SCRIPT_PATH.parent.parent.parent +SUPPORTED_VERSIONS_PATH = CODING_STANDARDS_ROOT / "supported_codeql_configs.json" -def get_compatible_stdlib(version: Version) -> Optional[str]: +def get_compatible_stdlib(version: Version) -> Optional[Tuple[str, str]]: tag = f"codeql-cli/v{version}" response = requests.get(f"https://raw.githubusercontent.com/github/codeql/{tag}/cpp/ql/lib/qlpack.yml") if response.status_code == 200: - return tag + # Parse the qlpack.yml returned in the response as a yaml file to read the version property + qlpack = yaml.safe_load(response.text) + if qlpack is not None and "version" in qlpack: + return (tag, qlpack["version"]) return None def get_compatible_bundle(version: Version, token: str) -> Optional[str]: @@ -30,8 +35,8 @@ def get_compatible_bundle(version: Version, token: str) -> Optional[str]: def main(cli_version : str, github_token: str) -> None: try: parsed_cli_version = Version(cli_version) - compatible_stdlib = get_compatible_stdlib(parsed_cli_version) - if compatible_stdlib is None: + compatible_stdlib_return = get_compatible_stdlib(parsed_cli_version) + if compatible_stdlib_return is None: print(f"Unable to find compatible standard library for: {parsed_cli_version}") exit(1) compatible_bundle = get_compatible_bundle(parsed_cli_version, github_token) @@ -39,6 +44,8 @@ def main(cli_version : str, github_token: str) -> None: print(f"Unable to find compatible bundle for: {parsed_cli_version}") exit(1) + compatible_stdlib_tag, compatible_stdlib_version = compatible_stdlib_return + with SUPPORTED_VERSIONS_PATH.open("r") as f: supported_versions = json.load(f) @@ -49,10 +56,37 @@ def main(cli_version : str, github_token: str) -> None: supported_env = supported_envs[0] supported_env["codeql_cli"] = str(parsed_cli_version) supported_env["codeql_cli_bundle"] = compatible_bundle - supported_env["codeql_standard_library"] = compatible_stdlib + supported_env["codeql_standard_library"] = compatible_stdlib_tag with SUPPORTED_VERSIONS_PATH.open("w") as f: json.dump(supported_versions, f, indent=2) + + # Find every qlpack.yml file in the repository + qlpack_files = list(CODING_STANDARDS_ROOT.rglob("qlpack.yml")) + # Filter out any files that are in a hidden directory + qlpack_files = [f for f in qlpack_files if not any(part for part in f.parts if part.startswith("."))] + + # Update the "codeql/cpp-all" entries in the "dependencies" property in every qlpack.yml file + for qlpack_file in qlpack_files: + with qlpack_file.open("r") as f: + qlpack = yaml.safe_load(f) + print("Updating dependencies in " + str(qlpack_file)) + if "codeql/cpp-all" in qlpack["dependencies"]: + qlpack["dependencies"]["codeql/cpp-all"] = compatible_stdlib_version + with qlpack_file.open("w") as f: + yaml.safe_dump(qlpack, f, sort_keys=False) + + # Call CodeQL to update the lock files by running codeql pack upgrade + # Note: we need to do this after updating all the qlpack files, + # otherwise we may get dependency resolution errors + # Note: we need to update all qlpack files, because they may + # transitively depend on the packs we changed + for qlpack_file in qlpack_files: + qlpack = qlpack_file.parent + print("Updating lock files for " + str(qlpack)) + os.system(f"codeql pack upgrade {qlpack}") + + except ValueError as e: print(e) exit(1) diff --git a/scripts/validate-amendments-csv.py b/scripts/validate-amendments-csv.py new file mode 100644 index 0000000000..9d83b7d0c9 --- /dev/null +++ b/scripts/validate-amendments-csv.py @@ -0,0 +1,128 @@ +from collections import defaultdict +import csv +import os +from pathlib import Path +import sys +import json + +help_statement = """ +Usage: {script_name} + +A script which detects invalid entries in amendments.csv. +""" + +if (len(sys.argv) == 2 and sys.argv[1] == "--help"): + print(help_statement.format(script_name=sys.argv[0])) + sys.exit(0) + +if not len(sys.argv) == 2: + print("Error: incorrect number of arguments", file=sys.stderr) + print("Usage: " + sys.argv[0] + " [--help]", file=sys.stderr) + sys.exit(1) + +repo_root = Path(__file__).parent.parent +rules_file_path = repo_root.joinpath('rules.csv') +amendments_file_path = repo_root.joinpath('amendments.csv') +language_name = sys.argv[1] + +failed = False + +rules_from_csv = {} +try: + rules_file = open(rules_file_path, "r") +except PermissionError: + print("Error: No permission to read the rules file located at '" + str(rules_file_path) + "'") + sys.exit(1) +else: + with rules_file: + rules_reader = csv.reader(rules_file) + # Skip header row + next(rules_reader, None) + for rule in rules_reader: + language = rule[0] + rule_id = rule[2] + + # only validate rules for the specified language + if not language == language_name: + continue + + rule_dict = { + "standard": rule[1], + "rule_id": rule_id, + "supportable": rule[3] + } + rules_from_csv[rule_id] = rule_dict + +print(f"Found {len(rules_from_csv)} rules.") +print(f"Verifying amendments") + +seen_amendments = set() +try: + amendments_file = open(amendments_file_path, "r") +except PermissionError: + print("Error: No permission to read the amendments file located at '" + str(amendments_file_path) + "'") + sys.exit(1) +else: + with amendments_file: + amendments_reader = csv.reader(amendments_file) + # Skip header row + next(amendments_reader, None) + for amendment in amendments_reader: + language = amendment[0] + + # only validate rules for the specified language + if not language == language_name: + continue + + if len(amendment) != 8: + print(f"🔴 Error: amendment {amendment} has wrong number of fields") + failed = True + continue + + standard = amendment[1] + amendment_name = amendment[2] + rule_id = amendment[3] + supportable = amendment[4] + implemented = amendment[6] + amendment_id = f"{rule_id}-{amendment_name}" + + if not rule_id in rules_from_csv: + print(f"🔴 Error: Amendment {amendment_id} references rule {rule_id}, not found in rules.csv") + failed = True + continue + + rule = rules_from_csv[rule_id] + + if rule["standard"] != standard: + print(f"🟡 Invalid: {amendment_id} has a different standard than the {rule_id} in rules.csv") + print(f" '{standard}' vs '{rule['standard']}'") + failed = True + + if supportable not in {"Yes", "No"}: + print(f"🟡 Invalid: {amendment_id} 'supportable' field should be 'Yes' or 'No'.") + print(f" got '{supportable}'") + failed = True + + if rule["supportable"] != supportable: + print(f"🟡 Invalid: {amendment_id} supportable does not match rules.csv supportable.") + print(f" '{supportable}' vs '{rule['supportable']}'") + failed = True + + if implemented not in {"Yes", "No"}: + print(f"🟡 Invalid: {amendment_id} 'implemented' field should be 'Yes' or 'No'.") + print(f" got '{implemented}'") + failed = True + + if amendment_id in seen_amendments: + print(f"🔴 Error: {amendment_id} has duplicate entries") + failed = True + + seen_amendments.add(amendment_id) + +print(f"Checked {len(seen_amendments)} amendments.") + +if failed: + print("❌ FAILED: Validity issues found in amendments.csv!") + sys.exit(1) +else: + print("✅ PASSED: No validity issues found in amendments.csv! 🎉") diff --git a/scripts/verify_rule_package_consistency.py b/scripts/verify_rule_package_consistency.py index 7d111e81bc..b9eaa5b934 100644 --- a/scripts/verify_rule_package_consistency.py +++ b/scripts/verify_rule_package_consistency.py @@ -100,6 +100,33 @@ print( f" - ERROR: Rule {rule_id} included in {package_name}.json but not marked as supportable in rules.csv.") failed = True + for query in rule_details["queries"]: + if standard_name == "MISRA-C-2012" and not any(tag for tag in query["tags"] if tag.startswith("external/misra/c/2012/")): + print( + f' - ERROR: MISRA C 2012 query {query["short_name"]}.ql for Rule {rule_id} in {package_name}.json is missing a `external/misra/c/2012/...` tag.') + failed = True + if not standard_name == "MISRA-C-2012" and any(tag for tag in query["tags"] if tag.startswith("external/misra/c/2012/")): + print( + f' - ERROR: {standard_name} query {query["short_name"]}.ql for Rule {rule_id} in {package_name}.json has a spurious `external/misra/c/2012/...` tag.') + failed = True + if standard_name == "CERT-C" or standard_name == "CERT-C++": + expected_properties = [ + "severity", + "likelihood", + "remediation-cost", + "priority", + "level" + ] + for expected_property in expected_properties: + if not any(tag for tag in query["tags"] if tag.startswith(f"external/cert/{expected_property}/")): + print( + f' - ERROR: {standard_name} query {query["short_name"]}.ql for Rule {rule_id} in {package_name}.json is missing a `external/cert/{expected_property}/...` tag.') + failed = True + if not standard_name == "CERT-C" and not standard_name == "CERT-C++": + if any(tag for tag in query["tags"] if tag.startswith("external/cert/")): + print( + f' - ERROR: {standard_name} query {query["short_name"]}.ql for Rule {rule_id} in {package_name}.json has a spurious `external/cert/...` tag.') + failed = True rules_csv_rule_ids = package_rules_from_csv[package_name] json_missing_rules = rules_csv_rule_ids.difference(package_json_rule_ids) diff --git a/supported_codeql_configs.json b/supported_codeql_configs.json index 227f41babd..9b89dd849e 100644 --- a/supported_codeql_configs.json +++ b/supported_codeql_configs.json @@ -1,9 +1,9 @@ { "supported_environment": [ { - "codeql_cli": "2.14.6", - "codeql_standard_library": "codeql-cli/v2.14.6", - "codeql_cli_bundle": "codeql-bundle-v2.14.6" + "codeql_cli": "2.20.7", + "codeql_standard_library": "codeql-cli/v2.20.7", + "codeql_cli_bundle": "codeql-bundle-v2.20.7" } ], "supported_language": [